1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2022 Imagination Technologies Ltd.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * based in part on radv driver which is:
5bf215546Sopenharmony_ci * Copyright © 2016 Red Hat.
6bf215546Sopenharmony_ci * Copyright © 2016 Bas Nieuwenhuizen
7bf215546Sopenharmony_ci *
8bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
9bf215546Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
10bf215546Sopenharmony_ci * in the Software without restriction, including without limitation the rights
11bf215546Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12bf215546Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
13bf215546Sopenharmony_ci * furnished to do so, subject to the following conditions:
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
16bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
17bf215546Sopenharmony_ci * Software.
18bf215546Sopenharmony_ci *
19bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22bf215546Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25bf215546Sopenharmony_ci * SOFTWARE.
26bf215546Sopenharmony_ci */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci/**
29bf215546Sopenharmony_ci * This file implements VkQueue, VkFence, and VkSemaphore
30bf215546Sopenharmony_ci */
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include <assert.h>
33bf215546Sopenharmony_ci#include <stdbool.h>
34bf215546Sopenharmony_ci#include <stddef.h>
35bf215546Sopenharmony_ci#include <stdint.h>
36bf215546Sopenharmony_ci#include <unistd.h>
37bf215546Sopenharmony_ci#include <vulkan/vulkan.h>
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci#include "pvr_job_compute.h"
40bf215546Sopenharmony_ci#include "pvr_job_context.h"
41bf215546Sopenharmony_ci#include "pvr_job_render.h"
42bf215546Sopenharmony_ci#include "pvr_job_transfer.h"
43bf215546Sopenharmony_ci#include "pvr_limits.h"
44bf215546Sopenharmony_ci#include "pvr_private.h"
45bf215546Sopenharmony_ci#include "util/macros.h"
46bf215546Sopenharmony_ci#include "util/u_atomic.h"
47bf215546Sopenharmony_ci#include "vk_alloc.h"
48bf215546Sopenharmony_ci#include "vk_fence.h"
49bf215546Sopenharmony_ci#include "vk_log.h"
50bf215546Sopenharmony_ci#include "vk_object.h"
51bf215546Sopenharmony_ci#include "vk_queue.h"
52bf215546Sopenharmony_ci#include "vk_semaphore.h"
53bf215546Sopenharmony_ci#include "vk_sync.h"
54bf215546Sopenharmony_ci#include "vk_sync_dummy.h"
55bf215546Sopenharmony_ci#include "vk_util.h"
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_cistatic VkResult pvr_queue_init(struct pvr_device *device,
58bf215546Sopenharmony_ci                               struct pvr_queue *queue,
59bf215546Sopenharmony_ci                               const VkDeviceQueueCreateInfo *pCreateInfo,
60bf215546Sopenharmony_ci                               uint32_t index_in_family)
61bf215546Sopenharmony_ci{
62bf215546Sopenharmony_ci   struct pvr_transfer_ctx *transfer_ctx;
63bf215546Sopenharmony_ci   struct pvr_compute_ctx *compute_ctx;
64bf215546Sopenharmony_ci   struct pvr_render_ctx *gfx_ctx;
65bf215546Sopenharmony_ci   VkResult result;
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   result =
68bf215546Sopenharmony_ci      vk_queue_init(&queue->vk, &device->vk, pCreateInfo, index_in_family);
69bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
70bf215546Sopenharmony_ci      return result;
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   result = pvr_transfer_ctx_create(device,
73bf215546Sopenharmony_ci                                    PVR_WINSYS_CTX_PRIORITY_MEDIUM,
74bf215546Sopenharmony_ci                                    &transfer_ctx);
75bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
76bf215546Sopenharmony_ci      goto err_vk_queue_finish;
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   result = pvr_compute_ctx_create(device,
79bf215546Sopenharmony_ci                                   PVR_WINSYS_CTX_PRIORITY_MEDIUM,
80bf215546Sopenharmony_ci                                   &compute_ctx);
81bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
82bf215546Sopenharmony_ci      goto err_transfer_ctx_destroy;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   result =
85bf215546Sopenharmony_ci      pvr_render_ctx_create(device, PVR_WINSYS_CTX_PRIORITY_MEDIUM, &gfx_ctx);
86bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
87bf215546Sopenharmony_ci      goto err_compute_ctx_destroy;
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   queue->device = device;
90bf215546Sopenharmony_ci   queue->gfx_ctx = gfx_ctx;
91bf215546Sopenharmony_ci   queue->compute_ctx = compute_ctx;
92bf215546Sopenharmony_ci   queue->transfer_ctx = transfer_ctx;
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(queue->completion); i++)
95bf215546Sopenharmony_ci      queue->completion[i] = NULL;
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   return VK_SUCCESS;
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_cierr_compute_ctx_destroy:
100bf215546Sopenharmony_ci   pvr_compute_ctx_destroy(compute_ctx);
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_cierr_transfer_ctx_destroy:
103bf215546Sopenharmony_ci   pvr_transfer_ctx_destroy(transfer_ctx);
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_cierr_vk_queue_finish:
106bf215546Sopenharmony_ci   vk_queue_finish(&queue->vk);
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci   return result;
109bf215546Sopenharmony_ci}
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ciVkResult pvr_queues_create(struct pvr_device *device,
112bf215546Sopenharmony_ci                           const VkDeviceCreateInfo *pCreateInfo)
113bf215546Sopenharmony_ci{
114bf215546Sopenharmony_ci   VkResult result;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   /* Check requested queue families and queues */
117bf215546Sopenharmony_ci   assert(pCreateInfo->queueCreateInfoCount == 1);
118bf215546Sopenharmony_ci   assert(pCreateInfo->pQueueCreateInfos[0].queueFamilyIndex == 0);
119bf215546Sopenharmony_ci   assert(pCreateInfo->pQueueCreateInfos[0].queueCount <= PVR_MAX_QUEUES);
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   const VkDeviceQueueCreateInfo *queue_create =
122bf215546Sopenharmony_ci      &pCreateInfo->pQueueCreateInfos[0];
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci   device->queues = vk_alloc(&device->vk.alloc,
125bf215546Sopenharmony_ci                             queue_create->queueCount * sizeof(*device->queues),
126bf215546Sopenharmony_ci                             8,
127bf215546Sopenharmony_ci                             VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
128bf215546Sopenharmony_ci   if (!device->queues)
129bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci   device->queue_count = 0;
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ci   for (uint32_t i = 0; i < queue_create->queueCount; i++) {
134bf215546Sopenharmony_ci      result = pvr_queue_init(device, &device->queues[i], queue_create, i);
135bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
136bf215546Sopenharmony_ci         goto err_queues_finish;
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci      device->queue_count++;
139bf215546Sopenharmony_ci   }
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   return VK_SUCCESS;
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_cierr_queues_finish:
144bf215546Sopenharmony_ci   pvr_queues_destroy(device);
145bf215546Sopenharmony_ci   return result;
146bf215546Sopenharmony_ci}
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_cistatic void pvr_queue_finish(struct pvr_queue *queue)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci   for (uint32_t i = 0; i < ARRAY_SIZE(queue->completion); i++) {
151bf215546Sopenharmony_ci      if (queue->completion[i])
152bf215546Sopenharmony_ci         vk_sync_destroy(&queue->device->vk, queue->completion[i]);
153bf215546Sopenharmony_ci   }
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   pvr_render_ctx_destroy(queue->gfx_ctx);
156bf215546Sopenharmony_ci   pvr_compute_ctx_destroy(queue->compute_ctx);
157bf215546Sopenharmony_ci   pvr_transfer_ctx_destroy(queue->transfer_ctx);
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_ci   vk_queue_finish(&queue->vk);
160bf215546Sopenharmony_ci}
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_civoid pvr_queues_destroy(struct pvr_device *device)
163bf215546Sopenharmony_ci{
164bf215546Sopenharmony_ci   for (uint32_t q_idx = 0; q_idx < device->queue_count; q_idx++)
165bf215546Sopenharmony_ci      pvr_queue_finish(&device->queues[q_idx]);
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci   vk_free(&device->vk.alloc, device->queues);
168bf215546Sopenharmony_ci}
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ciVkResult pvr_QueueWaitIdle(VkQueue _queue)
171bf215546Sopenharmony_ci{
172bf215546Sopenharmony_ci   PVR_FROM_HANDLE(pvr_queue, queue, _queue);
173bf215546Sopenharmony_ci
174bf215546Sopenharmony_ci   for (int i = 0U; i < ARRAY_SIZE(queue->completion); i++) {
175bf215546Sopenharmony_ci      VkResult result;
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci      if (!queue->completion[i])
178bf215546Sopenharmony_ci         continue;
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci      result = vk_sync_wait(&queue->device->vk,
181bf215546Sopenharmony_ci                            queue->completion[i],
182bf215546Sopenharmony_ci                            0U,
183bf215546Sopenharmony_ci                            VK_SYNC_WAIT_COMPLETE,
184bf215546Sopenharmony_ci                            UINT64_MAX);
185bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
186bf215546Sopenharmony_ci         return result;
187bf215546Sopenharmony_ci   }
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   return VK_SUCCESS;
190bf215546Sopenharmony_ci}
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_cistatic VkResult
193bf215546Sopenharmony_cipvr_process_graphics_cmd(struct pvr_device *device,
194bf215546Sopenharmony_ci                         struct pvr_queue *queue,
195bf215546Sopenharmony_ci                         struct pvr_cmd_buffer *cmd_buffer,
196bf215546Sopenharmony_ci                         struct pvr_sub_cmd_gfx *sub_cmd,
197bf215546Sopenharmony_ci                         struct vk_sync **waits,
198bf215546Sopenharmony_ci                         uint32_t wait_count,
199bf215546Sopenharmony_ci                         uint32_t *stage_flags,
200bf215546Sopenharmony_ci                         struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
201bf215546Sopenharmony_ci{
202bf215546Sopenharmony_ci   const struct pvr_framebuffer *framebuffer = sub_cmd->framebuffer;
203bf215546Sopenharmony_ci   struct vk_sync *sync_geom;
204bf215546Sopenharmony_ci   struct vk_sync *sync_frag;
205bf215546Sopenharmony_ci   uint32_t bo_count = 0;
206bf215546Sopenharmony_ci   VkResult result;
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci   STACK_ARRAY(struct pvr_winsys_job_bo, bos, framebuffer->attachment_count);
209bf215546Sopenharmony_ci   if (!bos)
210bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   result = vk_sync_create(&device->vk,
213bf215546Sopenharmony_ci                           &device->pdevice->ws->syncobj_type,
214bf215546Sopenharmony_ci                           0U,
215bf215546Sopenharmony_ci                           0UL,
216bf215546Sopenharmony_ci                           &sync_geom);
217bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
218bf215546Sopenharmony_ci      return result;
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   result = vk_sync_create(&device->vk,
221bf215546Sopenharmony_ci                           &device->pdevice->ws->syncobj_type,
222bf215546Sopenharmony_ci                           0U,
223bf215546Sopenharmony_ci                           0UL,
224bf215546Sopenharmony_ci                           &sync_frag);
225bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
226bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, sync_geom);
227bf215546Sopenharmony_ci      return result;
228bf215546Sopenharmony_ci   }
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   /* FIXME: DoShadowLoadOrStore() */
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   /* FIXME: If the framebuffer being rendered to has multiple layers then we
233bf215546Sopenharmony_ci    * need to split submissions that run a fragment job into two.
234bf215546Sopenharmony_ci    */
235bf215546Sopenharmony_ci   if (sub_cmd->job.run_frag && framebuffer->layers > 1)
236bf215546Sopenharmony_ci      pvr_finishme("Split job submission for framebuffers with > 1 layers");
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   /* Get any imported buffers used in framebuffer attachments. */
239bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < framebuffer->attachment_count; i++) {
240bf215546Sopenharmony_ci      if (!framebuffer->attachments[i]->image->vma->bo->is_imported)
241bf215546Sopenharmony_ci         continue;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci      bos[bo_count].bo = framebuffer->attachments[i]->image->vma->bo;
244bf215546Sopenharmony_ci      bos[bo_count].flags = PVR_WINSYS_JOB_BO_FLAG_WRITE;
245bf215546Sopenharmony_ci      bo_count++;
246bf215546Sopenharmony_ci   }
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   /* This passes ownership of the wait fences to pvr_render_job_submit(). */
249bf215546Sopenharmony_ci   result = pvr_render_job_submit(queue->gfx_ctx,
250bf215546Sopenharmony_ci                                  &sub_cmd->job,
251bf215546Sopenharmony_ci                                  bos,
252bf215546Sopenharmony_ci                                  bo_count,
253bf215546Sopenharmony_ci                                  waits,
254bf215546Sopenharmony_ci                                  wait_count,
255bf215546Sopenharmony_ci                                  stage_flags,
256bf215546Sopenharmony_ci                                  sync_geom,
257bf215546Sopenharmony_ci                                  sync_frag);
258bf215546Sopenharmony_ci   STACK_ARRAY_FINISH(bos);
259bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
260bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, sync_geom);
261bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, sync_frag);
262bf215546Sopenharmony_ci      return result;
263bf215546Sopenharmony_ci   }
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   /* Replace the completion fences. */
266bf215546Sopenharmony_ci   if (completions[PVR_JOB_TYPE_GEOM])
267bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_GEOM]);
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci   completions[PVR_JOB_TYPE_GEOM] = sync_geom;
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   if (completions[PVR_JOB_TYPE_FRAG])
272bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_FRAG]);
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci   completions[PVR_JOB_TYPE_FRAG] = sync_frag;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   /* FIXME: DoShadowLoadOrStore() */
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci   return result;
279bf215546Sopenharmony_ci}
280bf215546Sopenharmony_ci
281bf215546Sopenharmony_cistatic VkResult
282bf215546Sopenharmony_cipvr_process_compute_cmd(struct pvr_device *device,
283bf215546Sopenharmony_ci                        struct pvr_queue *queue,
284bf215546Sopenharmony_ci                        struct pvr_sub_cmd_compute *sub_cmd,
285bf215546Sopenharmony_ci                        struct vk_sync **waits,
286bf215546Sopenharmony_ci                        uint32_t wait_count,
287bf215546Sopenharmony_ci                        uint32_t *stage_flags,
288bf215546Sopenharmony_ci                        struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
289bf215546Sopenharmony_ci{
290bf215546Sopenharmony_ci   struct vk_sync *sync;
291bf215546Sopenharmony_ci   VkResult result;
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   result = vk_sync_create(&device->vk,
294bf215546Sopenharmony_ci                           &device->pdevice->ws->syncobj_type,
295bf215546Sopenharmony_ci                           0U,
296bf215546Sopenharmony_ci                           0UL,
297bf215546Sopenharmony_ci                           &sync);
298bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
299bf215546Sopenharmony_ci      return result;
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci   /* This passes ownership of the wait fences to pvr_compute_job_submit(). */
302bf215546Sopenharmony_ci   result = pvr_compute_job_submit(queue->compute_ctx,
303bf215546Sopenharmony_ci                                   sub_cmd,
304bf215546Sopenharmony_ci                                   waits,
305bf215546Sopenharmony_ci                                   wait_count,
306bf215546Sopenharmony_ci                                   stage_flags,
307bf215546Sopenharmony_ci                                   sync);
308bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
309bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, sync);
310bf215546Sopenharmony_ci      return result;
311bf215546Sopenharmony_ci   }
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci   /* Replace the completion fences. */
314bf215546Sopenharmony_ci   if (completions[PVR_JOB_TYPE_COMPUTE])
315bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_COMPUTE]);
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci   completions[PVR_JOB_TYPE_COMPUTE] = sync;
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   return result;
320bf215546Sopenharmony_ci}
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_cistatic VkResult
323bf215546Sopenharmony_cipvr_process_transfer_cmds(struct pvr_device *device,
324bf215546Sopenharmony_ci                          struct pvr_queue *queue,
325bf215546Sopenharmony_ci                          struct pvr_sub_cmd_transfer *sub_cmd,
326bf215546Sopenharmony_ci                          struct vk_sync **waits,
327bf215546Sopenharmony_ci                          uint32_t wait_count,
328bf215546Sopenharmony_ci                          uint32_t *stage_flags,
329bf215546Sopenharmony_ci                          struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
330bf215546Sopenharmony_ci{
331bf215546Sopenharmony_ci   struct vk_sync *sync;
332bf215546Sopenharmony_ci   VkResult result;
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   result = vk_sync_create(&device->vk,
335bf215546Sopenharmony_ci                           &device->pdevice->ws->syncobj_type,
336bf215546Sopenharmony_ci                           0U,
337bf215546Sopenharmony_ci                           0UL,
338bf215546Sopenharmony_ci                           &sync);
339bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
340bf215546Sopenharmony_ci      return result;
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci   /* This passes ownership of the wait fences to pvr_transfer_job_submit(). */
343bf215546Sopenharmony_ci   result = pvr_transfer_job_submit(device,
344bf215546Sopenharmony_ci                                    queue->transfer_ctx,
345bf215546Sopenharmony_ci                                    sub_cmd,
346bf215546Sopenharmony_ci                                    waits,
347bf215546Sopenharmony_ci                                    wait_count,
348bf215546Sopenharmony_ci                                    stage_flags,
349bf215546Sopenharmony_ci                                    sync);
350bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
351bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, sync);
352bf215546Sopenharmony_ci      return result;
353bf215546Sopenharmony_ci   }
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci   /* Replace the completion fences. */
356bf215546Sopenharmony_ci   if (completions[PVR_JOB_TYPE_TRANSFER])
357bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, completions[PVR_JOB_TYPE_TRANSFER]);
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci   completions[PVR_JOB_TYPE_TRANSFER] = sync;
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci   return result;
362bf215546Sopenharmony_ci}
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_cistatic VkResult
365bf215546Sopenharmony_cipvr_set_semaphore_payloads(struct pvr_device *device,
366bf215546Sopenharmony_ci                           struct vk_sync *completions[static PVR_JOB_TYPE_MAX],
367bf215546Sopenharmony_ci                           const VkSemaphore *signals,
368bf215546Sopenharmony_ci                           uint32_t signal_count)
369bf215546Sopenharmony_ci{
370bf215546Sopenharmony_ci   struct vk_sync *sync;
371bf215546Sopenharmony_ci   VkResult result;
372bf215546Sopenharmony_ci   int fd = -1;
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_ci   result = vk_sync_create(&device->vk,
375bf215546Sopenharmony_ci                           &device->pdevice->ws->syncobj_type,
376bf215546Sopenharmony_ci                           0U,
377bf215546Sopenharmony_ci                           0UL,
378bf215546Sopenharmony_ci                           &sync);
379bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
380bf215546Sopenharmony_ci      return result;
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci   result = device->ws->ops->null_job_submit(device->ws,
383bf215546Sopenharmony_ci                                             completions,
384bf215546Sopenharmony_ci                                             PVR_JOB_TYPE_MAX,
385bf215546Sopenharmony_ci                                             sync);
386bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
387bf215546Sopenharmony_ci      goto end_set_semaphore_payloads;
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci   /* If we have a single signal semaphore, we can simply move merged sync's
390bf215546Sopenharmony_ci    * payload to the signal semahpore's payload.
391bf215546Sopenharmony_ci    */
392bf215546Sopenharmony_ci   if (signal_count == 1U) {
393bf215546Sopenharmony_ci      VK_FROM_HANDLE(vk_semaphore, sem, signals[0]);
394bf215546Sopenharmony_ci      struct vk_sync *sem_sync = vk_semaphore_get_active_sync(sem);
395bf215546Sopenharmony_ci
396bf215546Sopenharmony_ci      result = vk_sync_move(&device->vk, sem_sync, sync);
397bf215546Sopenharmony_ci      goto end_set_semaphore_payloads;
398bf215546Sopenharmony_ci   }
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_ci   result = vk_sync_export_sync_file(&device->vk, sync, &fd);
401bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
402bf215546Sopenharmony_ci      goto end_set_semaphore_payloads;
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < signal_count; i++) {
405bf215546Sopenharmony_ci      VK_FROM_HANDLE(vk_semaphore, sem, signals[i]);
406bf215546Sopenharmony_ci      struct vk_sync *sem_sync = vk_semaphore_get_active_sync(sem);
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci      result = vk_sync_import_sync_file(&device->vk, sem_sync, fd);
409bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
410bf215546Sopenharmony_ci         goto end_set_semaphore_payloads;
411bf215546Sopenharmony_ci   }
412bf215546Sopenharmony_ci
413bf215546Sopenharmony_ciend_set_semaphore_payloads:
414bf215546Sopenharmony_ci   if (fd != -1)
415bf215546Sopenharmony_ci      close(fd);
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_ci   vk_sync_destroy(&device->vk, sync);
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci   return result;
420bf215546Sopenharmony_ci}
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_cistatic VkResult
423bf215546Sopenharmony_cipvr_set_fence_payload(struct pvr_device *device,
424bf215546Sopenharmony_ci                      struct vk_sync *completions[static PVR_JOB_TYPE_MAX],
425bf215546Sopenharmony_ci                      VkFence _fence)
426bf215546Sopenharmony_ci{
427bf215546Sopenharmony_ci   VK_FROM_HANDLE(vk_fence, fence, _fence);
428bf215546Sopenharmony_ci   struct vk_sync *fence_sync;
429bf215546Sopenharmony_ci   struct vk_sync *sync;
430bf215546Sopenharmony_ci   VkResult result;
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci   result = vk_sync_create(&device->vk,
433bf215546Sopenharmony_ci                           &device->pdevice->ws->syncobj_type,
434bf215546Sopenharmony_ci                           0U,
435bf215546Sopenharmony_ci                           0UL,
436bf215546Sopenharmony_ci                           &sync);
437bf215546Sopenharmony_ci   if (result != VK_SUCCESS)
438bf215546Sopenharmony_ci      return result;
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci   result = device->ws->ops->null_job_submit(device->ws,
441bf215546Sopenharmony_ci                                             completions,
442bf215546Sopenharmony_ci                                             PVR_JOB_TYPE_MAX,
443bf215546Sopenharmony_ci                                             sync);
444bf215546Sopenharmony_ci   if (result != VK_SUCCESS) {
445bf215546Sopenharmony_ci      vk_sync_destroy(&device->vk, sync);
446bf215546Sopenharmony_ci      return result;
447bf215546Sopenharmony_ci   }
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ci   fence_sync = vk_fence_get_active_sync(fence);
450bf215546Sopenharmony_ci   result = vk_sync_move(&device->vk, fence_sync, sync);
451bf215546Sopenharmony_ci   vk_sync_destroy(&device->vk, sync);
452bf215546Sopenharmony_ci
453bf215546Sopenharmony_ci   return result;
454bf215546Sopenharmony_ci}
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_cistatic VkResult
457bf215546Sopenharmony_cipvr_process_cmd_buffer(struct pvr_device *device,
458bf215546Sopenharmony_ci                       struct pvr_queue *queue,
459bf215546Sopenharmony_ci                       VkCommandBuffer commandBuffer,
460bf215546Sopenharmony_ci                       struct vk_sync **waits,
461bf215546Sopenharmony_ci                       uint32_t wait_count,
462bf215546Sopenharmony_ci                       uint32_t *stage_flags,
463bf215546Sopenharmony_ci                       struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
464bf215546Sopenharmony_ci{
465bf215546Sopenharmony_ci   PVR_FROM_HANDLE(pvr_cmd_buffer, cmd_buffer, commandBuffer);
466bf215546Sopenharmony_ci   VkResult result;
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_ci   assert(cmd_buffer->status == PVR_CMD_BUFFER_STATUS_EXECUTABLE);
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_ci   list_for_each_entry_safe (struct pvr_sub_cmd,
471bf215546Sopenharmony_ci                             sub_cmd,
472bf215546Sopenharmony_ci                             &cmd_buffer->sub_cmds,
473bf215546Sopenharmony_ci                             link) {
474bf215546Sopenharmony_ci      switch (sub_cmd->type) {
475bf215546Sopenharmony_ci      case PVR_SUB_CMD_TYPE_GRAPHICS:
476bf215546Sopenharmony_ci         result = pvr_process_graphics_cmd(device,
477bf215546Sopenharmony_ci                                           queue,
478bf215546Sopenharmony_ci                                           cmd_buffer,
479bf215546Sopenharmony_ci                                           &sub_cmd->gfx,
480bf215546Sopenharmony_ci                                           waits,
481bf215546Sopenharmony_ci                                           wait_count,
482bf215546Sopenharmony_ci                                           stage_flags,
483bf215546Sopenharmony_ci                                           completions);
484bf215546Sopenharmony_ci         break;
485bf215546Sopenharmony_ci
486bf215546Sopenharmony_ci      case PVR_SUB_CMD_TYPE_COMPUTE:
487bf215546Sopenharmony_ci         result = pvr_process_compute_cmd(device,
488bf215546Sopenharmony_ci                                          queue,
489bf215546Sopenharmony_ci                                          &sub_cmd->compute,
490bf215546Sopenharmony_ci                                          waits,
491bf215546Sopenharmony_ci                                          wait_count,
492bf215546Sopenharmony_ci                                          stage_flags,
493bf215546Sopenharmony_ci                                          completions);
494bf215546Sopenharmony_ci         break;
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci      case PVR_SUB_CMD_TYPE_TRANSFER:
497bf215546Sopenharmony_ci         result = pvr_process_transfer_cmds(device,
498bf215546Sopenharmony_ci                                            queue,
499bf215546Sopenharmony_ci                                            &sub_cmd->transfer,
500bf215546Sopenharmony_ci                                            waits,
501bf215546Sopenharmony_ci                                            wait_count,
502bf215546Sopenharmony_ci                                            stage_flags,
503bf215546Sopenharmony_ci                                            completions);
504bf215546Sopenharmony_ci         break;
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci      default:
507bf215546Sopenharmony_ci         pvr_finishme("Unsupported sub-command type %d", sub_cmd->type);
508bf215546Sopenharmony_ci         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
509bf215546Sopenharmony_ci      }
510bf215546Sopenharmony_ci
511bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
512bf215546Sopenharmony_ci         cmd_buffer->status = PVR_CMD_BUFFER_STATUS_INVALID;
513bf215546Sopenharmony_ci         return result;
514bf215546Sopenharmony_ci      }
515bf215546Sopenharmony_ci
516bf215546Sopenharmony_ci      p_atomic_inc(&device->global_queue_job_count);
517bf215546Sopenharmony_ci   }
518bf215546Sopenharmony_ci
519bf215546Sopenharmony_ci   return VK_SUCCESS;
520bf215546Sopenharmony_ci}
521bf215546Sopenharmony_ci
522bf215546Sopenharmony_cistatic VkResult
523bf215546Sopenharmony_cipvr_submit_null_job(struct pvr_device *device,
524bf215546Sopenharmony_ci                    struct vk_sync **waits,
525bf215546Sopenharmony_ci                    uint32_t wait_count,
526bf215546Sopenharmony_ci                    uint32_t *stage_flags,
527bf215546Sopenharmony_ci                    struct vk_sync *completions[static PVR_JOB_TYPE_MAX])
528bf215546Sopenharmony_ci{
529bf215546Sopenharmony_ci   VkResult result;
530bf215546Sopenharmony_ci
531bf215546Sopenharmony_ci   STATIC_ASSERT(PVR_JOB_TYPE_MAX >= PVR_NUM_SYNC_PIPELINE_STAGES);
532bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < PVR_JOB_TYPE_MAX; i++) {
533bf215546Sopenharmony_ci      struct vk_sync *per_job_waits[wait_count];
534bf215546Sopenharmony_ci      uint32_t per_job_waits_count = 0;
535bf215546Sopenharmony_ci
536bf215546Sopenharmony_ci      /* Get the waits specific to the job type. */
537bf215546Sopenharmony_ci      for (uint32_t j = 0U; j < wait_count; j++) {
538bf215546Sopenharmony_ci         if (stage_flags[j] & (1U << i)) {
539bf215546Sopenharmony_ci            per_job_waits[per_job_waits_count] = waits[j];
540bf215546Sopenharmony_ci            per_job_waits_count++;
541bf215546Sopenharmony_ci         }
542bf215546Sopenharmony_ci      }
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci      if (per_job_waits_count == 0U)
545bf215546Sopenharmony_ci         continue;
546bf215546Sopenharmony_ci
547bf215546Sopenharmony_ci      result = vk_sync_create(&device->vk,
548bf215546Sopenharmony_ci                              &device->pdevice->ws->syncobj_type,
549bf215546Sopenharmony_ci                              0U,
550bf215546Sopenharmony_ci                              0UL,
551bf215546Sopenharmony_ci                              &completions[i]);
552bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
553bf215546Sopenharmony_ci         goto err_destroy_completion_syncs;
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_ci      result = device->ws->ops->null_job_submit(device->ws,
556bf215546Sopenharmony_ci                                                per_job_waits,
557bf215546Sopenharmony_ci                                                per_job_waits_count,
558bf215546Sopenharmony_ci                                                completions[i]);
559bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
560bf215546Sopenharmony_ci         goto err_destroy_completion_syncs;
561bf215546Sopenharmony_ci   }
562bf215546Sopenharmony_ci
563bf215546Sopenharmony_ci   return VK_SUCCESS;
564bf215546Sopenharmony_ci
565bf215546Sopenharmony_cierr_destroy_completion_syncs:
566bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < PVR_JOB_TYPE_MAX; i++) {
567bf215546Sopenharmony_ci      if (completions[i]) {
568bf215546Sopenharmony_ci         vk_sync_destroy(&device->vk, completions[i]);
569bf215546Sopenharmony_ci         completions[i] = NULL;
570bf215546Sopenharmony_ci      }
571bf215546Sopenharmony_ci   }
572bf215546Sopenharmony_ci
573bf215546Sopenharmony_ci   return result;
574bf215546Sopenharmony_ci}
575bf215546Sopenharmony_ci
576bf215546Sopenharmony_cistatic void pvr_update_syncobjs(struct pvr_device *device,
577bf215546Sopenharmony_ci                                struct vk_sync *src[static PVR_JOB_TYPE_MAX],
578bf215546Sopenharmony_ci                                struct vk_sync *dst[static PVR_JOB_TYPE_MAX])
579bf215546Sopenharmony_ci{
580bf215546Sopenharmony_ci   for (uint32_t i = 0; i < PVR_JOB_TYPE_MAX; i++) {
581bf215546Sopenharmony_ci      if (src[i]) {
582bf215546Sopenharmony_ci         if (dst[i])
583bf215546Sopenharmony_ci            vk_sync_destroy(&device->vk, dst[i]);
584bf215546Sopenharmony_ci
585bf215546Sopenharmony_ci         dst[i] = src[i];
586bf215546Sopenharmony_ci      }
587bf215546Sopenharmony_ci   }
588bf215546Sopenharmony_ci}
589bf215546Sopenharmony_ci
590bf215546Sopenharmony_ciVkResult pvr_QueueSubmit(VkQueue _queue,
591bf215546Sopenharmony_ci                         uint32_t submitCount,
592bf215546Sopenharmony_ci                         const VkSubmitInfo *pSubmits,
593bf215546Sopenharmony_ci                         VkFence fence)
594bf215546Sopenharmony_ci{
595bf215546Sopenharmony_ci   PVR_FROM_HANDLE(pvr_queue, queue, _queue);
596bf215546Sopenharmony_ci   struct vk_sync *completion_syncobjs[PVR_JOB_TYPE_MAX] = {};
597bf215546Sopenharmony_ci   struct pvr_device *device = queue->device;
598bf215546Sopenharmony_ci   VkResult result;
599bf215546Sopenharmony_ci
600bf215546Sopenharmony_ci   for (uint32_t i = 0U; i < submitCount; i++) {
601bf215546Sopenharmony_ci      struct vk_sync *per_submit_completion_syncobjs[PVR_JOB_TYPE_MAX] = {};
602bf215546Sopenharmony_ci      const VkSubmitInfo *desc = &pSubmits[i];
603bf215546Sopenharmony_ci      struct vk_sync *waits[desc->waitSemaphoreCount];
604bf215546Sopenharmony_ci      uint32_t stage_flags[desc->waitSemaphoreCount];
605bf215546Sopenharmony_ci      uint32_t wait_count = 0;
606bf215546Sopenharmony_ci
607bf215546Sopenharmony_ci      for (uint32_t j = 0U; j < desc->waitSemaphoreCount; j++) {
608bf215546Sopenharmony_ci         VK_FROM_HANDLE(vk_semaphore, semaphore, desc->pWaitSemaphores[j]);
609bf215546Sopenharmony_ci         struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore);
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ci         if (sync->type == &vk_sync_dummy_type)
612bf215546Sopenharmony_ci            continue;
613bf215546Sopenharmony_ci
614bf215546Sopenharmony_ci         /* We don't currently support timeline semaphores. */
615bf215546Sopenharmony_ci         assert(!(sync->flags & VK_SYNC_IS_TIMELINE));
616bf215546Sopenharmony_ci
617bf215546Sopenharmony_ci         stage_flags[wait_count] =
618bf215546Sopenharmony_ci            pvr_stage_mask_dst(desc->pWaitDstStageMask[j]);
619bf215546Sopenharmony_ci         waits[wait_count] = vk_semaphore_get_active_sync(semaphore);
620bf215546Sopenharmony_ci         wait_count++;
621bf215546Sopenharmony_ci      }
622bf215546Sopenharmony_ci
623bf215546Sopenharmony_ci      if (desc->commandBufferCount > 0U) {
624bf215546Sopenharmony_ci         for (uint32_t j = 0U; j < desc->commandBufferCount; j++) {
625bf215546Sopenharmony_ci            result = pvr_process_cmd_buffer(device,
626bf215546Sopenharmony_ci                                            queue,
627bf215546Sopenharmony_ci                                            desc->pCommandBuffers[j],
628bf215546Sopenharmony_ci                                            waits,
629bf215546Sopenharmony_ci                                            wait_count,
630bf215546Sopenharmony_ci                                            stage_flags,
631bf215546Sopenharmony_ci                                            per_submit_completion_syncobjs);
632bf215546Sopenharmony_ci            if (result != VK_SUCCESS)
633bf215546Sopenharmony_ci               return result;
634bf215546Sopenharmony_ci         }
635bf215546Sopenharmony_ci      } else {
636bf215546Sopenharmony_ci         result = pvr_submit_null_job(device,
637bf215546Sopenharmony_ci                                      waits,
638bf215546Sopenharmony_ci                                      wait_count,
639bf215546Sopenharmony_ci                                      stage_flags,
640bf215546Sopenharmony_ci                                      per_submit_completion_syncobjs);
641bf215546Sopenharmony_ci         if (result != VK_SUCCESS)
642bf215546Sopenharmony_ci            return result;
643bf215546Sopenharmony_ci      }
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci      if (desc->signalSemaphoreCount) {
646bf215546Sopenharmony_ci         result = pvr_set_semaphore_payloads(device,
647bf215546Sopenharmony_ci                                             per_submit_completion_syncobjs,
648bf215546Sopenharmony_ci                                             desc->pSignalSemaphores,
649bf215546Sopenharmony_ci                                             desc->signalSemaphoreCount);
650bf215546Sopenharmony_ci         if (result != VK_SUCCESS)
651bf215546Sopenharmony_ci            return result;
652bf215546Sopenharmony_ci      }
653bf215546Sopenharmony_ci
654bf215546Sopenharmony_ci      pvr_update_syncobjs(device,
655bf215546Sopenharmony_ci                          per_submit_completion_syncobjs,
656bf215546Sopenharmony_ci                          completion_syncobjs);
657bf215546Sopenharmony_ci   }
658bf215546Sopenharmony_ci
659bf215546Sopenharmony_ci   if (fence) {
660bf215546Sopenharmony_ci      result = pvr_set_fence_payload(device, completion_syncobjs, fence);
661bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
662bf215546Sopenharmony_ci         return result;
663bf215546Sopenharmony_ci   }
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_ci   pvr_update_syncobjs(device, completion_syncobjs, queue->completion);
666bf215546Sopenharmony_ci
667bf215546Sopenharmony_ci   return VK_SUCCESS;
668bf215546Sopenharmony_ci}
669