mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-01 05:58:05 +02:00
agx: Fix implicit sync for virtgpu
The asahi kernel driver is a pure-explicit-sync driver and userspace is required to handle implicit sync itself, by importing/exporting fences in shared dma-bufs. Mesa handles this in its own native or guest context, but dma-buf fences are not shared between the guest and the host, so this breaks implicit sync across the VM boundary. To make this work, explicitly pass a resource list to the host so it can perform the implicit sync dance, like we do in agx_batch.c. This essentially turns the virtgpu protocol into an implicit sync protocol (like many other legacy GPU drivers), which makes sense here since we don't particularly have the primitives to pass through and manage "host" syncobjs that we'd need to do it at that level. Signed-off-by: Asahi Lina <lina@asahilina.net> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31532>
This commit is contained in:
parent
6f3c1c909b
commit
01ef3152c9
6 changed files with 63 additions and 6 deletions
|
|
@ -382,7 +382,7 @@ agx_get_params(struct agx_device *dev, void *buf, size_t size)
|
|||
|
||||
static int
|
||||
agx_submit(struct agx_device *dev, struct drm_asahi_submit *submit,
|
||||
uint32_t vbo_res_id)
|
||||
struct agx_submit_virt *virt)
|
||||
{
|
||||
return drmIoctl(dev->fd, DRM_IOCTL_ASAHI_SUBMIT, submit);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
#include "layout.h"
|
||||
#include "unstable_asahi_drm.h"
|
||||
|
||||
#include "vdrm.h"
|
||||
#include "virglrenderer_hw.h"
|
||||
|
||||
#include "asahi_proto.h"
|
||||
|
||||
// TODO: this is a lie right now
|
||||
static const uint64_t AGX_SUPPORTED_INCOMPAT_FEATURES =
|
||||
DRM_ASAHI_FEAT_MANDATORY_ZS_COMPRESSION;
|
||||
|
|
@ -61,6 +66,12 @@ struct nir_shader;
|
|||
#define BARRIER_RENDER (1 << DRM_ASAHI_SUBQUEUE_RENDER)
|
||||
#define BARRIER_COMPUTE (1 << DRM_ASAHI_SUBQUEUE_COMPUTE)
|
||||
|
||||
struct agx_submit_virt {
|
||||
uint32_t vbo_res_id;
|
||||
uint32_t extres_count;
|
||||
struct asahi_ccmd_submit_res *extres;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct agx_bo *(*bo_alloc)(struct agx_device *dev, size_t size, size_t align,
|
||||
enum agx_bo_flags flags);
|
||||
|
|
@ -70,7 +81,7 @@ typedef struct {
|
|||
void (*bo_mmap)(struct agx_device *dev, struct agx_bo *bo);
|
||||
ssize_t (*get_params)(struct agx_device *dev, void *buf, size_t size);
|
||||
int (*submit)(struct agx_device *dev, struct drm_asahi_submit *submit,
|
||||
uint32_t vbo_res_id);
|
||||
struct agx_submit_virt *virt);
|
||||
} agx_device_ops_t;
|
||||
|
||||
struct agx_device {
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ out:
|
|||
|
||||
static int
|
||||
agx_virtio_submit(struct agx_device *dev, struct drm_asahi_submit *submit,
|
||||
uint32_t vbo_res_id)
|
||||
struct agx_submit_virt *virt)
|
||||
{
|
||||
struct drm_asahi_command *commands =
|
||||
(struct drm_asahi_command *)submit->commands;
|
||||
|
|
@ -226,12 +226,17 @@ agx_virtio_submit(struct agx_device *dev, struct drm_asahi_submit *submit,
|
|||
}
|
||||
}
|
||||
|
||||
size_t extres_size =
|
||||
sizeof(struct asahi_ccmd_submit_res) * virt->extres_count;
|
||||
req_len += extres_size;
|
||||
|
||||
struct asahi_ccmd_submit_req *req =
|
||||
(struct asahi_ccmd_submit_req *)calloc(1, req_len);
|
||||
|
||||
req->queue_id = submit->queue_id;
|
||||
req->result_res_id = vbo_res_id;
|
||||
req->result_res_id = virt->vbo_res_id;
|
||||
req->command_count = submit->command_count;
|
||||
req->extres_count = virt->extres_count;
|
||||
|
||||
char *ptr = (char *)&req->payload;
|
||||
|
||||
|
|
@ -252,6 +257,9 @@ agx_virtio_submit(struct agx_device *dev, struct drm_asahi_submit *submit,
|
|||
}
|
||||
}
|
||||
|
||||
memcpy(ptr, virt->extres, extres_size);
|
||||
ptr += extres_size;
|
||||
|
||||
req->hdr.cmd = ASAHI_CCMD_SUBMIT;
|
||||
req->hdr.len = req_len;
|
||||
|
||||
|
|
|
|||
|
|
@ -120,11 +120,20 @@ struct asahi_ccmd_gem_bind_rsp {
|
|||
int32_t ret;
|
||||
};
|
||||
|
||||
#define ASAHI_EXTRES_READ 0x01
|
||||
#define ASAHI_EXTRES_WRITE 0x02
|
||||
|
||||
struct asahi_ccmd_submit_res {
|
||||
uint32_t res_id;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct asahi_ccmd_submit_req {
|
||||
struct vdrm_ccmd_req hdr;
|
||||
uint32_t queue_id;
|
||||
uint32_t result_res_id;
|
||||
uint32_t command_count;
|
||||
uint32_t extres_count;
|
||||
|
||||
uint8_t payload[];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -299,7 +299,13 @@ union drm_asahi_cmd {
|
|||
static VkResult
|
||||
queue_submit_single(struct agx_device *dev, struct drm_asahi_submit *submit)
|
||||
{
|
||||
int ret = dev->ops.submit(dev, submit, 0);
|
||||
/* Currently we don't use the result buffer or implicit sync */
|
||||
struct agx_submit_virt virt = {
|
||||
.vbo_res_id = 0,
|
||||
.extres_count = 0,
|
||||
};
|
||||
|
||||
int ret = dev->ops.submit(dev, submit, &virt);
|
||||
|
||||
/* XXX: don't trap */
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -764,6 +764,10 @@ agx_batch_submit(struct agx_context *ctx, struct agx_batch *batch,
|
|||
|
||||
uint64_t wait_seqid = p_atomic_read(&screen->flush_wait_seqid);
|
||||
|
||||
struct agx_submit_virt virt = {
|
||||
.vbo_res_id = ctx->result_buf->vbo_res_id,
|
||||
};
|
||||
|
||||
/* Elide syncing against our own queue */
|
||||
if (wait_seqid && wait_seqid == ctx->flush_my_seqid) {
|
||||
batch_debug(batch,
|
||||
|
|
@ -859,6 +863,8 @@ agx_batch_submit(struct agx_context *ctx, struct agx_batch *batch,
|
|||
|
||||
/* And keep track of the BO for cloning the out_sync */
|
||||
shared_bos[shared_bo_count++] = bo;
|
||||
if (dev->is_virtio)
|
||||
virt.extres_count++;
|
||||
} else {
|
||||
/* Deal with BOs which are not externally shared, but which have been
|
||||
* written from another context within the same screen. We also need to
|
||||
|
|
@ -878,6 +884,20 @@ agx_batch_submit(struct agx_context *ctx, struct agx_batch *batch,
|
|||
}
|
||||
}
|
||||
|
||||
if (dev->is_virtio && virt.extres_count) {
|
||||
struct agx_bo **p = shared_bos;
|
||||
virt.extres =
|
||||
malloc(virt.extres_count * sizeof(struct asahi_ccmd_submit_res));
|
||||
|
||||
for (unsigned i = 0; i < virt.extres_count; i++) {
|
||||
while (!*p)
|
||||
p++; // Skip inter-context slots which are not recorded here
|
||||
virt.extres[i].res_id = (*p)->vbo_res_id;
|
||||
virt.extres[i].flags = ASAHI_EXTRES_READ | ASAHI_EXTRES_WRITE;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->debug & AGX_DBG_SCRATCH) {
|
||||
if (compute)
|
||||
agx_scratch_debug_pre(&ctx->scratch_cs);
|
||||
|
|
@ -944,7 +964,7 @@ agx_batch_submit(struct agx_context *ctx, struct agx_batch *batch,
|
|||
.commands = (uint64_t)(uintptr_t)(&commands[0]),
|
||||
};
|
||||
|
||||
int ret = dev->ops.submit(dev, &submit, ctx->result_buf->vbo_res_id);
|
||||
int ret = dev->ops.submit(dev, &submit, &virt);
|
||||
|
||||
u_rwlock_rdunlock(&screen->destroy_lock);
|
||||
|
||||
|
|
@ -1054,6 +1074,9 @@ agx_batch_submit(struct agx_context *ctx, struct agx_batch *batch,
|
|||
|
||||
agx_batch_mark_submitted(batch);
|
||||
|
||||
if (virt.extres)
|
||||
free(virt.extres);
|
||||
|
||||
/* Record the last syncobj for fence creation */
|
||||
ctx->syncobj = batch->syncobj;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue