summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/common
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2007-10-03 15:50:46 +1000
committerDave Airlie <airlied@redhat.com>2007-10-03 15:50:46 +1000
commit4cd3ef58a989f61ff22669648e4117426c6e603c (patch)
treedc57ac2d98d3b7c718ee2c0feb9247cdc2b1df6b /src/mesa/drivers/dri/common
parentde1d725f442caa4d8ecbac3256b5a33d1f4a1257 (diff)
i915/drmbuf: attempt to push relocations into buffer manager
This moves the relocations into the buffer manager in prepration for a superioctl move.
Diffstat (limited to 'src/mesa/drivers/dri/common')
-rw-r--r--src/mesa/drivers/dri/common/dri_bufmgr.c16
-rw-r--r--src/mesa/drivers/dri/common/dri_bufmgr.h13
-rw-r--r--src/mesa/drivers/dri/common/dri_bufmgr_fake.c131
-rw-r--r--src/mesa/drivers/dri/common/dri_bufmgr_ttm.c131
4 files changed, 289 insertions, 2 deletions
diff --git a/src/mesa/drivers/dri/common/dri_bufmgr.c b/src/mesa/drivers/dri/common/dri_bufmgr.c
index 407409bf06..359b57863a 100644
--- a/src/mesa/drivers/dri/common/dri_bufmgr.c
+++ b/src/mesa/drivers/dri/common/dri_bufmgr.c
@@ -150,3 +150,19 @@ dri_bufmgr_destroy(dri_bufmgr *bufmgr)
{
bufmgr->destroy(bufmgr);
}
+
+
+void dri_emit_reloc(dri_bo *batch_buf, GLuint flags, GLuint delta, GLuint offset, dri_bo *relocatee)
+{
+ batch_buf->bufmgr->emit_reloc(batch_buf, flags, delta, offset, relocatee);
+}
+
+void dri_process_relocs(dri_bo *batch_buf)
+{
+ batch_buf->bufmgr->process_relocs(batch_buf);
+}
+
+void dri_post_submit(dri_bo *batch_buf, dri_fence **last_fence)
+{
+ batch_buf->bufmgr->post_submit(batch_buf, last_fence);
+}
diff --git a/src/mesa/drivers/dri/common/dri_bufmgr.h b/src/mesa/drivers/dri/common/dri_bufmgr.h
index 3be342926f..aeeb6bdb43 100644
--- a/src/mesa/drivers/dri/common/dri_bufmgr.h
+++ b/src/mesa/drivers/dri/common/dri_bufmgr.h
@@ -158,6 +158,15 @@ struct _dri_bufmgr {
* Tears down the buffer manager instance.
*/
void (*destroy)(dri_bufmgr *bufmgr);
+
+ /**
+ * Add relocation
+ */
+ void (*emit_reloc)(dri_bo *batch_buf, GLuint flags, GLuint delta, GLuint offset, dri_bo *relocatee);
+
+ void *(*process_relocs)(dri_bo *batch_buf);
+
+ void (*post_submit)(dri_bo *batch_buf, dri_fence **fence);
};
dri_bo *dri_bo_alloc(dri_bufmgr *bufmgr, const char *name, unsigned long size,
@@ -195,4 +204,8 @@ void dri_bufmgr_destroy(dri_bufmgr *bufmgr);
dri_bo *dri_ttm_bo_create_from_handle(dri_bufmgr *bufmgr, const char *name,
unsigned int handle);
+void dri_emit_reloc(dri_bo *batch_buf, GLuint flags, GLuint delta, GLuint offset, dri_bo *relocatee);
+void dri_process_relocs(dri_bo *batch_buf);
+void dri_post_process_relocs(dri_bo *batch_buf);
+void dri_post_submit(dri_bo *batch_buf, dri_fence **last_fence);
#endif
diff --git a/src/mesa/drivers/dri/common/dri_bufmgr_fake.c b/src/mesa/drivers/dri/common/dri_bufmgr_fake.c
index e0d23a3647..adf0cf5ab7 100644
--- a/src/mesa/drivers/dri/common/dri_bufmgr_fake.c
+++ b/src/mesa/drivers/dri/common/dri_bufmgr_fake.c
@@ -59,6 +59,16 @@
* processed through the command queue wouldn't need to care about
* fences.
*/
+#define MAX_RELOCS 4096
+
+struct fake_buffer_reloc
+{
+ dri_bo *buf;
+ GLuint offset;
+ GLuint delta; /* not needed? */
+ GLuint validate_flags;
+};
+
struct block {
struct block *next, *prev;
struct mem_block *mem; /* BM_MEM_AGP */
@@ -107,6 +117,12 @@ typedef struct _bufmgr_fake {
int (*fence_wait)(void *private, unsigned int fence_cookie);
/** Driver-supplied argument to driver callbacks */
void *driver_priv;
+
+
+ /** fake relocation list */
+ struct fake_buffer_reloc reloc[MAX_RELOCS];
+ GLuint nr_relocs;
+ GLboolean performed_rendering;
} dri_bufmgr_fake;
typedef struct _dri_bo_fake {
@@ -837,6 +853,117 @@ dri_fake_destroy(dri_bufmgr *bufmgr)
free(bufmgr);
}
+static void
+dri_fake_emit_reloc(dri_bo *batch_buf, GLuint flags, GLuint delta, GLuint offset,
+ dri_bo *relocatee)
+{
+ dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)batch_buf->bufmgr;
+ struct fake_buffer_reloc *r = &bufmgr_fake->reloc[bufmgr_fake->nr_relocs++];
+
+ assert(bufmgr_fake->nr_relocs <= MAX_RELOCS);
+
+ dri_bo_reference(relocatee);
+
+ r->buf = relocatee;
+ r->offset = offset;
+ r->delta = delta;
+ r->validate_flags = flags;
+
+ return;
+}
+
+
+static int
+relocation_sort(const void *a_in, const void *b_in) {
+ const struct fake_buffer_reloc *a = a_in, *b = b_in;
+
+ return (intptr_t)a->buf < (intptr_t)b->buf ? -1 : 1;
+}
+
+static void *
+dri_fake_process_reloc(dri_bo *batch_buf)
+{
+ dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)batch_buf->bufmgr;
+ GLuint i;
+ GLuint *ptr;
+
+ assert(batch_buf->virtual != NULL);
+ ptr = batch_buf->virtual;
+
+ bufmgr_fake->performed_rendering = GL_FALSE;
+
+ /* Sort our relocation list in terms of referenced buffer pointer.
+ * This lets us uniquely validate the buffers with the sum of all the flags,
+ * while avoiding O(n^2) on number of relocations.
+ */
+ qsort(bufmgr_fake->reloc, bufmgr_fake->nr_relocs, sizeof(bufmgr_fake->reloc[0]),
+ relocation_sort);
+
+ /* Perform the necessary validations of buffers, and enter the relocations
+ * in the batchbuffer.
+ */
+ for (i = 0; i < bufmgr_fake->nr_relocs; i++) {
+ struct fake_buffer_reloc *r = &bufmgr_fake->reloc[i];
+
+ if (r->validate_flags & DRM_BO_FLAG_WRITE)
+ bufmgr_fake->performed_rendering = GL_TRUE;
+
+ /* If this is the first time we've seen this buffer in the relocation
+ * list, figure out our flags and validate it.
+ */
+ if (i == 0 || bufmgr_fake->reloc[i - 1].buf != r->buf) {
+ uint32_t validate_flags;
+ int j, ret;
+
+ /* Accumulate the flags we need for validating this buffer. */
+ validate_flags = r->validate_flags;
+ for (j = i + 1; j < bufmgr_fake->nr_relocs; j++) {
+ if (bufmgr_fake->reloc[j].buf != r->buf)
+ break;
+ validate_flags |= bufmgr_fake->reloc[j].validate_flags;
+ }
+
+ /* Validate. If we fail, fence to clear the unfenced list and bail
+ * out.
+ */
+ ret = dri_bo_validate(r->buf, validate_flags);
+ if (ret != 0) {
+ dri_fence *fo;
+ dri_bo_unmap(batch_buf);
+ fo = dri_fence_validated(batch_buf->bufmgr,
+ "batchbuffer failure fence", GL_TRUE);
+ dri_fence_unreference(fo);
+ goto done;
+ }
+ }
+ ptr[r->offset / 4] = r->buf->offset + r->delta;
+ dri_bo_unreference(r->buf);
+ }
+ dri_bo_unmap(batch_buf);
+
+ dri_bo_validate(batch_buf, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE);
+
+ bufmgr_fake->nr_relocs = 0;
+ done:
+ return NULL;
+}
+
+static void
+dri_fake_post_submit(dri_bo *batch_buf, dri_fence **last_fence)
+{
+ dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)batch_buf->bufmgr;
+ dri_fence *fo;
+
+ fo = dri_fence_validated(batch_buf->bufmgr, "Batch fence", GL_TRUE);
+
+ if (bufmgr_fake->performed_rendering) {
+ dri_fence_unreference(*last_fence);
+ *last_fence = fo;
+ } else {
+ dri_fence_unreference(fo);
+ }
+}
+
dri_bufmgr *
dri_bufmgr_fake_init(unsigned long low_offset, void *low_virtual,
unsigned long size,
@@ -873,7 +1000,9 @@ dri_bufmgr_fake_init(unsigned long low_offset, void *low_virtual,
bufmgr_fake->bufmgr.fence_reference = dri_fake_fence_reference;
bufmgr_fake->bufmgr.fence_unreference = dri_fake_fence_unreference;
bufmgr_fake->bufmgr.destroy = dri_fake_destroy;
-
+ bufmgr_fake->bufmgr.emit_reloc = dri_fake_emit_reloc;
+ bufmgr_fake->bufmgr.process_relocs = dri_fake_process_reloc;
+ bufmgr_fake->bufmgr.post_submit = dri_fake_post_submit;
bufmgr_fake->fence_emit = fence_emit;
bufmgr_fake->fence_wait = fence_wait;
bufmgr_fake->driver_priv = driver_priv;
diff --git a/src/mesa/drivers/dri/common/dri_bufmgr_ttm.c b/src/mesa/drivers/dri/common/dri_bufmgr_ttm.c
index 235398eb87..84ac0b2c0d 100644
--- a/src/mesa/drivers/dri/common/dri_bufmgr_ttm.c
+++ b/src/mesa/drivers/dri/common/dri_bufmgr_ttm.c
@@ -43,6 +43,15 @@
#include "imports.h"
#define BUFMGR_DEBUG 0
+#define MAX_RELOCS 4096
+
+struct ttm_buffer_reloc
+{
+ dri_bo *buf;
+ GLuint offset;
+ GLuint delta; /* not needed? */
+ GLuint validate_flags;
+};
typedef struct _dri_bufmgr_ttm {
dri_bufmgr bufmgr;
@@ -51,6 +60,12 @@ typedef struct _dri_bufmgr_ttm {
_glthread_Mutex mutex;
unsigned int fence_type;
unsigned int fence_type_flush;
+
+ /** ttm relocation list */
+ struct ttm_buffer_reloc reloc[MAX_RELOCS];
+ GLuint nr_relocs;
+ GLboolean performed_rendering;
+
} dri_bufmgr_ttm;
typedef struct _dri_bo_ttm {
@@ -431,6 +446,118 @@ dri_bufmgr_ttm_destroy(dri_bufmgr *bufmgr)
free(bufmgr);
}
+
+static void
+dri_ttm_emit_reloc(dri_bo *batch_buf, GLuint flags, GLuint delta, GLuint offset,
+ dri_bo *relocatee)
+{
+ dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)batch_buf->bufmgr;
+ struct ttm_buffer_reloc *r = &bufmgr_ttm->reloc[bufmgr_ttm->nr_relocs++];
+
+ assert(bufmgr_ttm->nr_relocs <= MAX_RELOCS);
+
+ dri_bo_reference(relocatee);
+
+ r->buf = relocatee;
+ r->offset = offset;
+ r->delta = delta;
+ r->validate_flags = flags;
+
+ return;
+}
+
+
+static int
+relocation_sort(const void *a_in, const void *b_in) {
+ const struct ttm_buffer_reloc *a = a_in, *b = b_in;
+
+ return (intptr_t)a->buf < (intptr_t)b->buf ? -1 : 1;
+}
+
+static void *
+dri_ttm_process_reloc(dri_bo *batch_buf)
+{
+ dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)batch_buf->bufmgr;
+ GLuint i;
+ GLuint *ptr;
+
+ assert(batch_buf->virtual != NULL);
+ ptr = batch_buf->virtual;
+
+ bufmgr_ttm->performed_rendering = GL_FALSE;
+
+ /* Sort our relocation list in terms of referenced buffer pointer.
+ * This lets us uniquely validate the buffers with the sum of all the flags,
+ * while avoiding O(n^2) on number of relocations.
+ */
+ qsort(bufmgr_ttm->reloc, bufmgr_ttm->nr_relocs, sizeof(bufmgr_ttm->reloc[0]),
+ relocation_sort);
+
+ /* Perform the necessary validations of buffers, and enter the relocations
+ * in the batchbuffer.
+ */
+ for (i = 0; i < bufmgr_ttm->nr_relocs; i++) {
+ struct ttm_buffer_reloc *r = &bufmgr_ttm->reloc[i];
+
+ if (r->validate_flags & DRM_BO_FLAG_WRITE)
+ bufmgr_ttm->performed_rendering = GL_TRUE;
+
+ /* If this is the first time we've seen this buffer in the relocation
+ * list, figure out our flags and validate it.
+ */
+ if (i == 0 || bufmgr_ttm->reloc[i - 1].buf != r->buf) {
+ uint32_t validate_flags;
+ int j, ret;
+
+ /* Accumulate the flags we need for validating this buffer. */
+ validate_flags = r->validate_flags;
+ for (j = i + 1; j < bufmgr_ttm->nr_relocs; j++) {
+ if (bufmgr_ttm->reloc[j].buf != r->buf)
+ break;
+ validate_flags |= bufmgr_ttm->reloc[j].validate_flags;
+ }
+
+ /* Validate. If we fail, fence to clear the unfenced list and bail
+ * out.
+ */
+ ret = dri_bo_validate(r->buf, validate_flags);
+ if (ret != 0) {
+ dri_fence *fo;
+ dri_bo_unmap(batch_buf);
+ fo = dri_fence_validated(batch_buf->bufmgr,
+ "batchbuffer failure fence", GL_TRUE);
+ dri_fence_unreference(fo);
+ goto done;
+ }
+ }
+ ptr[r->offset / 4] = r->buf->offset + r->delta;
+ dri_bo_unreference(r->buf);
+ }
+ dri_bo_unmap(batch_buf);
+
+ dri_bo_validate(batch_buf, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE);
+
+ bufmgr_ttm->nr_relocs = 0;
+ done:
+ return NULL;
+}
+
+static void
+dri_ttm_post_submit(dri_bo *batch_buf, dri_fence **last_fence)
+{
+ dri_bufmgr_ttm *bufmgr_ttm = (dri_bufmgr_ttm *)batch_buf->bufmgr;
+ dri_fence *fo;
+
+ fo = dri_fence_validated(batch_buf->bufmgr, "Batch fence", GL_TRUE);
+
+ if (bufmgr_ttm->performed_rendering) {
+ dri_fence_unreference(*last_fence);
+ *last_fence = fo;
+ } else {
+ dri_fence_unreference(fo);
+ }
+}
+
/**
* Initializes the TTM buffer manager, which uses the kernel to allocate, map,
* and manage map buffer objections.
@@ -464,6 +591,8 @@ dri_bufmgr_ttm_init(int fd, unsigned int fence_type,
bufmgr_ttm->bufmgr.fence_unreference = dri_ttm_fence_unreference;
bufmgr_ttm->bufmgr.fence_wait = dri_ttm_fence_wait;
bufmgr_ttm->bufmgr.destroy = dri_bufmgr_ttm_destroy;
-
+ bufmgr_ttm->bufmgr.emit_reloc = dri_ttm_emit_reloc;
+ bufmgr_ttm->bufmgr.process_relocs = dri_ttm_process_reloc;
+ bufmgr_ttm->bufmgr.post_submit = dri_ttm_post_submit;
return &bufmgr_ttm->bufmgr;
}