aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChia-I Wu <olvaffe@gmail.com>2021-08-25 16:30:44 -0700
committerChia-I Wu <olvaffe@gmail.com>2021-09-03 09:28:49 -0700
commit2a610d2708619cbf95d09ee84fe654f9676dd2ad (patch)
treea34e8e945ab45aeecb3976b2a5013bd39e73adc0
parent89898ff60433ac3f2d33cb68a800a8adba0e33d3 (diff)
downloadvirglrenderer-2a610d2708619cbf95d09ee84fe654f9676dd2ad.tar.gz
vkr: introduce vkr_ring_control
It is used to access the control region, with iov support. Signed-off-by: Chia-I Wu <olvaffe@gmail.com> Reviewed-by: Ryan Neph <ryanneph@google.com> Reviewed-by: Yiwei Zhang <zzyiwei@chromium.org>
-rw-r--r--src/venus/vkr_ring.c66
-rw-r--r--src/venus/vkr_ring.h21
2 files changed, 71 insertions, 16 deletions
diff --git a/src/venus/vkr_ring.c b/src/venus/vkr_ring.c
index 223ff843..34a3a0f4 100644
--- a/src/venus/vkr_ring.c
+++ b/src/venus/vkr_ring.c
@@ -15,13 +15,59 @@ enum vkr_ring_status_flag {
VKR_RING_STATUS_IDLE = 1u << 0,
};
+/* callers must make sure they do not seek to end-of-resource or beyond */
+static const struct iovec *
+seek_resource(const struct virgl_resource *res,
+ int base_iov_index,
+ size_t offset,
+ int *out_iov_index,
+ size_t *out_iov_offset)
+{
+ const struct iovec *iov = &res->iov[base_iov_index];
+ assert(iov - res->iov < res->iov_count);
+ while (offset >= iov->iov_len) {
+ offset -= iov->iov_len;
+ iov++;
+ assert(iov - res->iov < res->iov_count);
+ }
+
+ *out_iov_index = iov - res->iov;
+ *out_iov_offset = offset;
+
+ return iov;
+}
+
+static void *
+get_resource_pointer(const struct virgl_resource *res, int base_iov_index, size_t offset)
+{
+ const struct iovec *iov =
+ seek_resource(res, base_iov_index, offset, &base_iov_index, &offset);
+ return (uint8_t *)iov->iov_base + offset;
+}
+
+static bool
+vkr_ring_init_control(struct vkr_ring *ring, const struct vkr_ring_layout *layout)
+{
+ struct vkr_ring_control *ctrl = &ring->control;
+
+ ctrl->head = get_resource_pointer(layout->resource, 0, layout->head.begin);
+ ctrl->tail = get_resource_pointer(layout->resource, 0, layout->tail.begin);
+ ctrl->status = get_resource_pointer(layout->resource, 0, layout->status.begin);
+
+ /* we will manage head and status, and we expect them to be 0 initially */
+ if (*ctrl->head || *ctrl->status)
+ return false;
+
+ return true;
+}
+
static void
vkr_ring_store_head(struct vkr_ring *ring)
{
/* the renderer is expected to load the head with memory_order_acquire,
* forming a release-acquire ordering
*/
- atomic_store_explicit(ring->shared.head, ring->cur, memory_order_release);
+ atomic_store_explicit(ring->control.head, ring->cur, memory_order_release);
}
static uint32_t
@@ -30,13 +76,13 @@ vkr_ring_load_tail(const struct vkr_ring *ring)
/* the driver is expected to store the tail with memory_order_release,
* forming a release-acquire ordering
*/
- return atomic_load_explicit(ring->shared.tail, memory_order_acquire);
+ return atomic_load_explicit(ring->control.tail, memory_order_acquire);
}
static void
vkr_ring_store_status(struct vkr_ring *ring, uint32_t status)
{
- atomic_store_explicit(ring->shared.status, status, memory_order_seq_cst);
+ atomic_store_explicit(ring->control.status, status, memory_order_seq_cst);
}
static void
@@ -69,12 +115,14 @@ vkr_ring_create(const struct vkr_ring_layout *layout,
ring->resource = layout->resource;
+ if (!vkr_ring_init_control(ring, layout)) {
+ free(ring);
+ return NULL;
+ }
+
uint8_t *shared = layout->resource->iov[0].iov_base;
#define ring_attach_shared(member) \
ring->shared.member = (void *)(shared + layout->member.begin)
- ring_attach_shared(head);
- ring_attach_shared(tail);
- ring_attach_shared(status);
ring_attach_shared(buffer);
ring_attach_shared(extra);
#undef ring_attach_shared
@@ -84,12 +132,6 @@ vkr_ring_create(const struct vkr_ring_layout *layout,
ring->buffer_mask = ring->buffer_size - 1;
ring->extra_size = vkr_region_size(&layout->extra);
- /* we will manage head and status, and we expect them to be 0 initially */
- if (*ring->shared.head || *ring->shared.status) {
- free(ring);
- return NULL;
- }
-
ring->cmd = malloc(ring->buffer_size);
if (!ring->cmd) {
free(ring);
diff --git a/src/venus/vkr_ring.h b/src/venus/vkr_ring.h
index 6cd00501..b37fda64 100644
--- a/src/venus/vkr_ring.h
+++ b/src/venus/vkr_ring.h
@@ -22,13 +22,22 @@ struct vkr_ring_layout {
};
static_assert(ATOMIC_INT_LOCK_FREE == 2 && sizeof(atomic_uint) == 4,
- "vkr_ring_shared requires lock-free 32-bit atomic_uint");
-
-/* pointers to a ring in a virgl_resource */
-struct vkr_ring_shared {
+ "vkr_ring_control requires lock-free 32-bit atomic_uint");
+
+/* the control region of a ring */
+struct vkr_ring_control {
+ /* Pointers to ring head, tail, and status.
+ *
+ * Clients increment the tail after commands are added. We increment the
+ * head after commands are executed. The status is updated when there is a
+ * status change to the ring thread.
+ */
volatile atomic_uint *head;
const volatile atomic_uint *tail;
volatile atomic_uint *status;
+};
+
+struct vkr_ring_shared {
const void *buffer;
void *extra;
@@ -39,7 +48,10 @@ struct vkr_ring {
vkr_object_id id;
struct list_head head;
+ /* ring regions */
struct virgl_resource *resource;
+ struct vkr_ring_control control;
+
struct vkr_ring_shared shared;
uint32_t buffer_size;
uint32_t buffer_mask;
@@ -48,6 +60,7 @@ struct vkr_ring {
size_t extra_size;
+ /* ring thread */
struct virgl_context *context;
uint64_t idle_timeout;