v3dv: add the concept of a job

As we make progress towards more complex submissions we will need to split
our command buffers into smaller executable units (jobs) that we can
submit indepdently to the kernel. This will be required to implement
pipeline barriers, split subpasses that have depedencies on previous
subpasses, split render passes that use more than 4 render targets, etc.

For now we keep things simple and we only keep one job as current
recording target in the command buffer, and we generate a new one
with every subpass or with any commands we see outside of a render pass
(only vkCopyImageToBuffer for now). In the future we probably want to
optimize this by merging subpasses into the same job when possible,
etc.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>
This commit is contained in:
Iago Toral Quiroga
2020-01-08 11:14:35 +01:00
committed by Marge Bot
parent aef5a5cbca
commit 5259175fe8
7 changed files with 397 additions and 284 deletions
+71 -55
View File
@@ -29,23 +29,23 @@
#include <errno.h>
static void
v3dv_clif_dump(struct v3dv_queue *queue,
struct v3dv_cmd_buffer *cmd_buffer,
v3dv_clif_dump(struct v3dv_device *device,
struct v3dv_job *job,
struct drm_v3d_submit_cl *submit)
{
if (!(V3D_DEBUG & (V3D_DEBUG_CL | V3D_DEBUG_CLIF)))
return;
struct clif_dump *clif = clif_dump_init(&queue->device->devinfo,
struct clif_dump *clif = clif_dump_init(&device->devinfo,
stderr,
V3D_DEBUG & V3D_DEBUG_CL);
set_foreach(cmd_buffer->bos, entry) {
set_foreach(job->bos, entry) {
struct v3dv_bo *bo = (void *)entry->key;
char *name = ralloc_asprintf(NULL, "%s_0x%x",
"" /* bo->name */ , bo->offset);
v3dv_bo_map(queue->device, bo, bo->size);
v3dv_bo_map(device, bo, bo->size);
clif_dump_add_bo(clif, name, bo->offset, bo->size, bo->map);
ralloc_free(name);
@@ -56,6 +56,67 @@ v3dv_clif_dump(struct v3dv_queue *queue,
clif_dump_destroy(clif);
}
static VkResult
job_submit(struct v3dv_job *job)
{
assert(job);
struct drm_v3d_submit_cl submit;
/* While the RCL will implicitly depend on the last RCL to have finished, we
* also need to block on any previous TFU job we may have dispatched.
*/
submit.in_sync_rcl = 0; /* FIXME */
/* Update the sync object for the last rendering by our context. */
submit.out_sync = 0; /* FIXME */
submit.bcl_start = job->bcl.bo->offset;
submit.bcl_end = job->bcl.bo->offset + v3dv_cl_offset(&job->bcl);
submit.rcl_start = job->rcl.bo->offset;
submit.rcl_end = job->rcl.bo->offset + v3dv_cl_offset(&job->rcl);
submit.flags = 0;
/* FIXME: we already know that we support cache flush, as we only support
* hw that supports that, but would be better to just DRM-ask it
*/
if (job->tmu_dirty_rcl)
submit.flags |= DRM_V3D_SUBMIT_CL_FLUSH_CACHE;
submit.qma = job->tile_alloc->offset;
submit.qms = job->tile_alloc->size;
submit.qts = job->tile_state->offset;
submit.bo_handle_count = job->bo_count;
uint32_t *bo_handles =
(uint32_t *) malloc(sizeof(uint32_t) * MAX2(4, submit.bo_handle_count * 2));
uint32_t bo_idx = 0;
set_foreach(job->bos, entry) {
struct v3dv_bo *bo = (struct v3dv_bo *)entry->key;
bo_handles[bo_idx++] = bo->handle;
}
assert(bo_idx == submit.bo_handle_count);
submit.bo_handles = (uintptr_t)(void *)bo_handles;
struct v3dv_device *device = job->cmd_buffer->device;
v3dv_clif_dump(device, job, &submit);
int ret = v3dv_ioctl(device->fd, DRM_IOCTL_V3D_SUBMIT_CL, &submit);
static bool warned = false;
if (ret && !warned) {
fprintf(stderr, "Draw call returned %s. Expect corruption.\n",
strerror(errno));
warned = true;
}
free(bo_handles);
if (ret)
return VK_ERROR_DEVICE_LOST;
return VK_SUCCESS;
}
static VkResult
queue_submit(struct v3dv_queue *queue,
const VkSubmitInfo *pSubmit,
@@ -69,57 +130,12 @@ queue_submit(struct v3dv_queue *queue,
V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, pSubmit->pCommandBuffers[0]);
struct drm_v3d_submit_cl submit;
/* While the RCL will implicitly depend on the last RCL to have finished, we
* also need to block on any previous TFU job we may have dispatched.
*/
submit.in_sync_rcl = 0; /* FIXME */
/* Update the sync object for the last rendering by our context. */
submit.out_sync = 0; /* FIXME */
submit.bcl_start = cmd_buffer->bcl.bo->offset;
submit.bcl_end = cmd_buffer->bcl.bo->offset + v3dv_cl_offset(&cmd_buffer->bcl);
submit.rcl_start = cmd_buffer->rcl.bo->offset;
submit.rcl_end = cmd_buffer->rcl.bo->offset + v3dv_cl_offset(&cmd_buffer->rcl);
submit.flags = 0;
/* FIXME: we already know that we support cache flush, as we only support
* hw that supports that, but would be better to just DRM-ask it
*/
if (cmd_buffer->state.tmu_dirty_rcl)
submit.flags |= DRM_V3D_SUBMIT_CL_FLUSH_CACHE;
submit.qma = cmd_buffer->tile_alloc->offset;
submit.qms = cmd_buffer->tile_alloc->size;
submit.qts = cmd_buffer->tile_state->offset;
submit.bo_handle_count = cmd_buffer->bo_count;
uint32_t *bo_handles =
(uint32_t *) malloc(sizeof(uint32_t) * MAX2(4, submit.bo_handle_count * 2));
uint32_t bo_idx = 0;
set_foreach(cmd_buffer->bos, entry) {
struct v3dv_bo *bo = (struct v3dv_bo *)entry->key;
bo_handles[bo_idx++] = bo->handle;
list_for_each_entry_safe(struct v3dv_job, job,
&cmd_buffer->submit_jobs, list_link) {
VkResult result = job_submit(job);
if (result != VK_SUCCESS)
return result;
}
assert(bo_idx == submit.bo_handle_count);
submit.bo_handles = (uintptr_t)(void *)bo_handles;
v3dv_clif_dump(queue, cmd_buffer, &submit);
int ret = v3dv_ioctl(queue->device->fd, DRM_IOCTL_V3D_SUBMIT_CL, &submit);
static bool warned = false;
if (ret && !warned) {
fprintf(stderr, "Draw call returned %s. Expect corruption.\n",
strerror(errno));
warned = true;
}
free(bo_handles);
if (ret)
return VK_ERROR_DEVICE_LOST;
return VK_SUCCESS;
}