blob: 0edf1cba898a16cf5dda29cd158eb6f2844fcfe1 [file] [log] [blame]
/*
* Copyright © 2021 Collabora Ltd.
*
* Derived from tu_device.c which is:
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
* Copyright © 2015 Intel Corporation
*
* 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 "genxml/gen_macros.h"
#include "decode.h"
#include "panvk_private.h"
#include "panvk_cs.h"
#include "vk_drm_syncobj.h"
static void
panvk_queue_submit_batch(struct panvk_queue *queue,
struct panvk_batch *batch,
uint32_t *bos, unsigned nr_bos,
uint32_t *in_fences,
unsigned nr_in_fences)
{
const struct panvk_device *dev = queue->device;
unsigned debug = dev->physical_device->instance->debug_flags;
const struct panfrost_device *pdev = &dev->physical_device->pdev;
int ret;
/* Reset the batch if it's already been issued */
if (batch->issued) {
util_dynarray_foreach(&batch->jobs, void *, job)
memset((*job), 0, 4 * 4);
/* Reset the tiler before re-issuing the batch */
if (batch->tiler.descs.cpu) {
memcpy(batch->tiler.descs.cpu, batch->tiler.templ,
pan_size(TILER_CONTEXT) + pan_size(TILER_HEAP));
}
}
if (batch->scoreboard.first_job) {
struct drm_panfrost_submit submit = {
.bo_handles = (uintptr_t)bos,
.bo_handle_count = nr_bos,
.in_syncs = (uintptr_t)in_fences,
.in_sync_count = nr_in_fences,
.out_sync = queue->sync,
.jc = batch->scoreboard.first_job,
};
ret = drmIoctl(pdev->fd, DRM_IOCTL_PANFROST_SUBMIT, &submit);
assert(!ret);
if (debug & (PANVK_DEBUG_TRACE | PANVK_DEBUG_SYNC)) {
ret = drmSyncobjWait(pdev->fd, &submit.out_sync, 1, INT64_MAX, 0, NULL);
assert(!ret);
}
if (debug & PANVK_DEBUG_TRACE)
GENX(pandecode_jc)(batch->scoreboard.first_job, pdev->gpu_id);
if (debug & PANVK_DEBUG_DUMP)
pandecode_dump_mappings();
}
if (batch->fragment_job) {
struct drm_panfrost_submit submit = {
.bo_handles = (uintptr_t)bos,
.bo_handle_count = nr_bos,
.out_sync = queue->sync,
.jc = batch->fragment_job,
.requirements = PANFROST_JD_REQ_FS,
};
if (batch->scoreboard.first_job) {
submit.in_syncs = (uintptr_t)(&queue->sync);
submit.in_sync_count = 1;
} else {
submit.in_syncs = (uintptr_t)in_fences;
submit.in_sync_count = nr_in_fences;
}
ret = drmIoctl(pdev->fd, DRM_IOCTL_PANFROST_SUBMIT, &submit);
assert(!ret);
if (debug & (PANVK_DEBUG_TRACE | PANVK_DEBUG_SYNC)) {
ret = drmSyncobjWait(pdev->fd, &submit.out_sync, 1, INT64_MAX, 0, NULL);
assert(!ret);
}
if (debug & PANVK_DEBUG_TRACE)
GENX(pandecode_jc)(batch->fragment_job, pdev->gpu_id);
if (debug & PANVK_DEBUG_DUMP)
pandecode_dump_mappings();
}
if (debug & PANVK_DEBUG_TRACE)
pandecode_next_frame();
batch->issued = true;
}
static void
panvk_queue_transfer_sync(struct panvk_queue *queue, uint32_t syncobj)
{
const struct panfrost_device *pdev = &queue->device->physical_device->pdev;
int ret;
struct drm_syncobj_handle handle = {
.handle = queue->sync,
.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE,
.fd = -1,
};
ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);
assert(!ret);
assert(handle.fd >= 0);
handle.handle = syncobj;
ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &handle);
assert(!ret);
close(handle.fd);
}
static void
panvk_add_wait_event_syncobjs(struct panvk_batch *batch, uint32_t *in_fences, unsigned *nr_in_fences)
{
util_dynarray_foreach(&batch->event_ops, struct panvk_event_op, op) {
switch (op->type) {
case PANVK_EVENT_OP_SET:
/* Nothing to do yet */
break;
case PANVK_EVENT_OP_RESET:
/* Nothing to do yet */
break;
case PANVK_EVENT_OP_WAIT:
in_fences[(*nr_in_fences)++] = op->event->syncobj;
break;
default:
unreachable("bad panvk_event_op type\n");
}
}
}
static void
panvk_signal_event_syncobjs(struct panvk_queue *queue, struct panvk_batch *batch)
{
const struct panfrost_device *pdev = &queue->device->physical_device->pdev;
util_dynarray_foreach(&batch->event_ops, struct panvk_event_op, op) {
switch (op->type) {
case PANVK_EVENT_OP_SET: {
panvk_queue_transfer_sync(queue, op->event->syncobj);
break;
}
case PANVK_EVENT_OP_RESET: {
struct panvk_event *event = op->event;
struct drm_syncobj_array objs = {
.handles = (uint64_t) (uintptr_t) &event->syncobj,
.count_handles = 1
};
int ret = drmIoctl(pdev->fd, DRM_IOCTL_SYNCOBJ_RESET, &objs);
assert(!ret);
break;
}
case PANVK_EVENT_OP_WAIT:
/* Nothing left to do */
break;
default:
unreachable("bad panvk_event_op type\n");
}
}
}
VkResult
panvk_per_arch(queue_submit)(struct vk_queue *vk_queue,
struct vk_queue_submit *submit)
{
struct panvk_queue *queue =
container_of(vk_queue, struct panvk_queue, vk);
const struct panfrost_device *pdev = &queue->device->physical_device->pdev;
unsigned nr_semaphores = submit->wait_count + 1;
uint32_t semaphores[nr_semaphores];
semaphores[0] = queue->sync;
for (unsigned i = 0; i < submit->wait_count; i++) {
assert(vk_sync_type_is_drm_syncobj(submit->waits[i].sync->type));
struct vk_drm_syncobj *syncobj =
vk_sync_as_drm_syncobj(submit->waits[i].sync);
semaphores[i + 1] = syncobj->syncobj;
}
for (uint32_t j = 0; j < submit->command_buffer_count; ++j) {
struct panvk_cmd_buffer *cmdbuf =
container_of(submit->command_buffers[j], struct panvk_cmd_buffer, vk);
list_for_each_entry(struct panvk_batch, batch, &cmdbuf->batches, node) {
/* FIXME: should be done at the batch level */
unsigned nr_bos =
panvk_pool_num_bos(&cmdbuf->desc_pool) +
panvk_pool_num_bos(&cmdbuf->varying_pool) +
panvk_pool_num_bos(&cmdbuf->tls_pool) +
(batch->fb.info ? batch->fb.info->attachment_count : 0) +
(batch->blit.src ? 1 : 0) +
(batch->blit.dst ? 1 : 0) +
(batch->scoreboard.first_tiler ? 1 : 0) + 1;
unsigned bo_idx = 0;
uint32_t bos[nr_bos];
panvk_pool_get_bo_handles(&cmdbuf->desc_pool, &bos[bo_idx]);
bo_idx += panvk_pool_num_bos(&cmdbuf->desc_pool);
panvk_pool_get_bo_handles(&cmdbuf->varying_pool, &bos[bo_idx]);
bo_idx += panvk_pool_num_bos(&cmdbuf->varying_pool);
panvk_pool_get_bo_handles(&cmdbuf->tls_pool, &bos[bo_idx]);
bo_idx += panvk_pool_num_bos(&cmdbuf->tls_pool);
if (batch->fb.info) {
for (unsigned i = 0; i < batch->fb.info->attachment_count; i++) {
bos[bo_idx++] = batch->fb.info->attachments[i].iview->pview.image->data.bo->gem_handle;
}
}
if (batch->blit.src)
bos[bo_idx++] = batch->blit.src->gem_handle;
if (batch->blit.dst)
bos[bo_idx++] = batch->blit.dst->gem_handle;
if (batch->scoreboard.first_tiler)
bos[bo_idx++] = pdev->tiler_heap->gem_handle;
bos[bo_idx++] = pdev->sample_positions->gem_handle;
assert(bo_idx == nr_bos);
/* Merge identical BO entries. */
for (unsigned x = 0; x < nr_bos; x++) {
for (unsigned y = x + 1; y < nr_bos; ) {
if (bos[x] == bos[y])
bos[y] = bos[--nr_bos];
else
y++;
}
}
unsigned nr_in_fences = 0;
unsigned max_wait_event_syncobjs =
util_dynarray_num_elements(&batch->event_ops,
struct panvk_event_op);
uint32_t in_fences[nr_semaphores + max_wait_event_syncobjs];
memcpy(in_fences, semaphores, nr_semaphores * sizeof(*in_fences));
nr_in_fences += nr_semaphores;
panvk_add_wait_event_syncobjs(batch, in_fences, &nr_in_fences);
panvk_queue_submit_batch(queue, batch, bos, nr_bos, in_fences, nr_in_fences);
panvk_signal_event_syncobjs(queue, batch);
}
}
/* Transfer the out fence to signal semaphores */
for (unsigned i = 0; i < submit->signal_count; i++) {
assert(vk_sync_type_is_drm_syncobj(submit->signals[i].sync->type));
struct vk_drm_syncobj *syncobj =
vk_sync_as_drm_syncobj(submit->signals[i].sync);
panvk_queue_transfer_sync(queue, syncobj->syncobj);
}
return VK_SUCCESS;
}
VkResult
panvk_per_arch(CreateSampler)(VkDevice _device,
const VkSamplerCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkSampler *pSampler)
{
VK_FROM_HANDLE(panvk_device, device, _device);
struct panvk_sampler *sampler;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
sampler = vk_object_alloc(&device->vk, pAllocator, sizeof(*sampler),
VK_OBJECT_TYPE_SAMPLER);
if (!sampler)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
STATIC_ASSERT(sizeof(sampler->desc) >= pan_size(SAMPLER));
panvk_per_arch(emit_sampler)(pCreateInfo, &sampler->desc);
*pSampler = panvk_sampler_to_handle(sampler);
return VK_SUCCESS;
}