[Freedreno] [PATCH] freedreno/kgsl: use preamble buffers

sheffmail at mail.ru sheffmail at mail.ru
Fri Jul 18 07:51:19 PDT 2014


From: Stanislav Vorobiov <sheffmail at mail.ru>

There're 2 ways to manage drawing contexts in kgsl:

* rely on kernel - i.e. just submit an IB and kernel will do
  all that's necessary when swapping contexts, i.e. save registers,
  shaders, etc.
* do this yourself - in this case client must submit 2 IBs, first
  is called preamble buffer and the second is actual buffer. when context
  changes to some other and then changes back GPU will execute preamble
  buffer which must restore state

Qualcomm blob uses second way, freedreno
uses the first way, but, has all the necessary info for state restoration in
the buffer. Thus, to fix this we just introduce dummy preamble buffer with
a single NOP instruction
---
 freedreno/kgsl/kgsl_pipe.c       |    2 +-
 freedreno/kgsl/kgsl_ringbuffer.c |   33 +++++++++++++++++++++++++++------
 2 files changed, 28 insertions(+), 7 deletions(-)

diff --git a/freedreno/kgsl/kgsl_pipe.c b/freedreno/kgsl/kgsl_pipe.c
index 88d9505..0779841 100644
--- a/freedreno/kgsl/kgsl_pipe.c
+++ b/freedreno/kgsl/kgsl_pipe.c
@@ -204,7 +204,7 @@ struct fd_pipe * kgsl_pipe_new(struct fd_device *dev, enum fd_pipe_id id)
 			[FD_PIPE_2D] = "/dev/kgsl-2d0",
 	};
 	struct kgsl_drawctxt_create req = {
-			.flags = 0x2000, /* ??? */
+			.flags = 0x10, /* KGSL_CONTEXT_PREAMBLE */
 	};
 	struct kgsl_pipe *kgsl_pipe = NULL;
 	struct fd_pipe *pipe = NULL;
diff --git a/freedreno/kgsl/kgsl_ringbuffer.c b/freedreno/kgsl/kgsl_ringbuffer.c
index dc3c9c2..a93112c 100644
--- a/freedreno/kgsl/kgsl_ringbuffer.c
+++ b/freedreno/kgsl/kgsl_ringbuffer.c
@@ -46,6 +46,7 @@ struct kgsl_rb_bo {
 struct kgsl_ringbuffer {
 	struct fd_ringbuffer base;
 	struct kgsl_rb_bo *bo;
+	struct kgsl_rb_bo *tmp_bo;
 };
 
 static inline struct kgsl_ringbuffer * to_kgsl_ringbuffer(struct fd_ringbuffer *x)
@@ -114,15 +115,22 @@ static int kgsl_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_star
 	struct kgsl_ringbuffer *kgsl_ring = to_kgsl_ringbuffer(ring);
 	struct kgsl_pipe *kgsl_pipe = to_kgsl_pipe(ring->pipe);
 	uint32_t offset = (uint8_t *)last_start - (uint8_t *)ring->start;
-	struct kgsl_ibdesc ibdesc = {
+	struct kgsl_ibdesc ibdesc[2] = {
+		{
+			.gpuaddr     = kgsl_ring->tmp_bo->gpuaddr,
+			.hostptr     = NULL,
+			.sizedwords  = 2,
+		},
+		{
 			.gpuaddr     = kgsl_ring->bo->gpuaddr + offset,
 			.hostptr     = last_start,
 			.sizedwords  = ring->cur - last_start,
+		}
 	};
 	struct kgsl_ringbuffer_issueibcmds req = {
 			.drawctxt_id = kgsl_pipe->drawctxt_id,
-			.ibdesc_addr = (unsigned long)&ibdesc,
-			.numibs      = 1,
+			.ibdesc_addr = (unsigned long)&ibdesc[0],
+			.numibs      = 2,
 			.flags       = KGSL_CONTEXT_SUBMIT_IB_LIST,
 	};
 	int ret;
@@ -135,9 +143,9 @@ static int kgsl_ringbuffer_flush(struct fd_ringbuffer *ring, uint32_t *last_star
 		uint32_t last_size = (uint32_t)(ring->cur - last_start);
 		/* 5 is length of first packet, 2 for the two 7f000000's */
 		last_start[2] = last_size - (5 + 2);
-		ibdesc.gpuaddr = kgsl_ring->bo->gpuaddr;
-		ibdesc.hostptr = kgsl_ring->bo->hostptr;
-		ibdesc.sizedwords = 0x145;
+		ibdesc[0].gpuaddr = kgsl_ring->bo->gpuaddr;
+		ibdesc[0].hostptr = kgsl_ring->bo->hostptr;
+		ibdesc[0].sizedwords = 0x145;
 		req.timestamp = (uint32_t)kgsl_ring->bo->hostptr;
 	}
 
@@ -184,6 +192,7 @@ static void kgsl_ringbuffer_destroy(struct fd_ringbuffer *ring)
 		fd_pipe_wait(ring->pipe, ring->last_timestamp);
 	if (kgsl_ring->bo)
 		kgsl_rb_bo_del(kgsl_ring->bo);
+	kgsl_rb_bo_del(kgsl_ring->tmp_bo);
 	free(kgsl_ring);
 }
 
@@ -200,6 +209,7 @@ struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe,
 {
 	struct kgsl_ringbuffer *kgsl_ring;
 	struct fd_ringbuffer *ring = NULL;
+	uint32_t *ptr;
 
 	kgsl_ring = calloc(1, sizeof(*kgsl_ring));
 	if (!kgsl_ring) {
@@ -216,6 +226,17 @@ struct fd_ringbuffer * kgsl_ringbuffer_new(struct fd_pipe *pipe,
 		goto fail;
 	}
 
+	kgsl_ring->tmp_bo = kgsl_rb_bo_new(to_kgsl_pipe(pipe), 0x10000);
+
+	ptr = kgsl_ring->tmp_bo->hostptr;
+
+	/*
+	 * CP_NOP instruction with payload of 1 dword.
+	 */
+
+	*ptr = 0xc0001000;
+	*(ptr + 1) = 00000000;
+
 	return ring;
 fail:
 	if (ring)
-- 
1.7.9.5



More information about the Freedreno mailing list