#include <virglrenderer.h>
+/*
+ * VIRGL_CHECK_VERSION available since libvirglrenderer 1.0.1 and was fixed
+ * in 1.1.0. Undefine bugged version of the macro and provide our own.
+ */
+#if defined(VIRGL_CHECK_VERSION) && \
+ VIRGL_VERSION_MAJOR == 1 && VIRGL_VERSION_MINOR < 1
+#undef VIRGL_CHECK_VERSION
+#endif
+
+#ifndef VIRGL_CHECK_VERSION
+#define VIRGL_CHECK_VERSION(major, minor, micro) \
+ (VIRGL_VERSION_MAJOR > (major) || \
+ VIRGL_VERSION_MAJOR == (major) && VIRGL_VERSION_MINOR > (minor) || \
+ VIRGL_VERSION_MAJOR == (major) && VIRGL_VERSION_MINOR == (minor) && \
+ VIRGL_VERSION_MICRO >= (micro))
+#endif
+
struct virtio_gpu_virgl_resource {
struct virtio_gpu_simple_resource base;
MemoryRegion *mr;
}
#endif
+void virtio_gpu_virgl_reset_async_fences(VirtIOGPU *g)
+{
+ struct virtio_gpu_virgl_context_fence *f;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
+
+ while (!QSLIST_EMPTY(&gl->async_fenceq)) {
+ f = QSLIST_FIRST(&gl->async_fenceq);
+
+ QSLIST_REMOVE_HEAD(&gl->async_fenceq, next);
+
+ g_free(f);
+ }
+}
+
+#if VIRGL_CHECK_VERSION(1, 1, 2)
+static void virtio_gpu_virgl_async_fence_bh(void *opaque)
+{
+ QSLIST_HEAD(, virtio_gpu_virgl_context_fence) async_fenceq;
+ struct virtio_gpu_ctrl_command *cmd, *tmp;
+ struct virtio_gpu_virgl_context_fence *f;
+ VirtIOGPU *g = opaque;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
+
+ if (gl->renderer_state != RS_INITED) {
+ return;
+ }
+
+ QSLIST_MOVE_ATOMIC(&async_fenceq, &gl->async_fenceq);
+
+ while (!QSLIST_EMPTY(&async_fenceq)) {
+ f = QSLIST_FIRST(&async_fenceq);
+
+ QSLIST_REMOVE_HEAD(&async_fenceq, next);
+
+ QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
+ /*
+ * the guest can end up emitting fences out of order
+ * so we should check all fenced cmds not just the first one.
+ */
+ if (cmd->cmd_hdr.fence_id > f->fence_id) {
+ continue;
+ }
+ if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_INFO_RING_IDX) {
+ if (cmd->cmd_hdr.ring_idx != f->ring_idx) {
+ continue;
+ }
+ if (cmd->cmd_hdr.ctx_id != f->ctx_id) {
+ continue;
+ }
+ }
+ virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
+ QTAILQ_REMOVE(&g->fenceq, cmd, next);
+ g_free(cmd);
+ }
+
+ trace_virtio_gpu_fence_resp(f->fence_id);
+ g_free(f);
+ g->inflight--;
+ if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
+ trace_virtio_gpu_dec_inflight_fences(g->inflight);
+ }
+ }
+}
+
+static void
+virtio_gpu_virgl_push_async_fence(VirtIOGPU *g, uint32_t ctx_id,
+ uint32_t ring_idx, uint64_t fence_id)
+{
+ struct virtio_gpu_virgl_context_fence *f;
+ VirtIOGPUGL *gl = VIRTIO_GPU_GL(g);
+
+ f = g_new(struct virtio_gpu_virgl_context_fence, 1);
+ f->ctx_id = ctx_id;
+ f->ring_idx = ring_idx;
+ f->fence_id = fence_id;
+
+ QSLIST_INSERT_HEAD_ATOMIC(&gl->async_fenceq, f, next);
+
+ qemu_bh_schedule(gl->async_fence_bh);
+}
+
+static void virgl_write_async_fence(void *opaque, uint32_t fence)
+{
+ VirtIOGPU *g = opaque;
+
+ virtio_gpu_virgl_push_async_fence(g, 0, UINT32_MAX, fence);
+}
+
+static void virgl_write_async_context_fence(void *opaque, uint32_t ctx_id,
+ uint32_t ring_idx, uint64_t fence)
+{
+ VirtIOGPU *g = opaque;
+
+ virtio_gpu_virgl_push_async_fence(g, ctx_id, ring_idx, fence);
+}
+#endif
+
static virgl_renderer_gl_context
virgl_create_context(void *opaque, int scanout_idx,
struct virgl_renderer_gl_ctx_param *params)
void virtio_gpu_virgl_reset(VirtIOGPU *g)
{
virgl_renderer_reset();
+
+ virtio_gpu_virgl_reset_async_fences(g);
}
int virtio_gpu_virgl_init(VirtIOGPU *g)
if (qemu_egl_display) {
virtio_gpu_3d_cbs.version = 4;
virtio_gpu_3d_cbs.get_egl_display = virgl_get_egl_display;
+#if VIRGL_CHECK_VERSION(1, 1, 2)
+ virtio_gpu_3d_cbs.write_fence = virgl_write_async_fence;
+ virtio_gpu_3d_cbs.write_context_fence = virgl_write_async_context_fence;
+ flags |= VIRGL_RENDERER_ASYNC_FENCE_CB;
+ flags |= VIRGL_RENDERER_THREAD_SYNC;
+#endif
}
#endif
#ifdef VIRGL_RENDERER_D3D11_SHARE_TEXTURE
gl->cmdq_resume_bh = virtio_bh_io_new_guarded(DEVICE(g),
virtio_gpu_virgl_resume_cmdq_bh,
g);
+#if VIRGL_CHECK_VERSION(1, 1, 2)
+ gl->async_fence_bh = virtio_bh_io_new_guarded(DEVICE(g),
+ virtio_gpu_virgl_async_fence_bh,
+ g);
+#endif
#endif
return 0;