[intel] Add support for multiple levels of relocation in bufmgr_fake.

This is required for 965 support, which has relocations in other places than
just the batchbuffer.
This commit is contained in:
Eric Anholt 2007-11-16 14:20:24 -08:00
parent df3c530bed
commit 00eb5635c6
2 changed files with 161 additions and 71 deletions

View file

@ -134,13 +134,42 @@ 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, GLuint *count);
/**
* Add relocation entry in reloc_buf, to be set on command submission.
*
* \param reloc_buf Buffer to write the relocation into.
* \param flags BO flags to be used in validating the target buffer.
* Applicable flags include:
* - DRM_BO_FLAG_READ: The buffer will be read in the process of
* command execution.
* - DRM_BO_FLAG_WRITE: The buffer will be written in the process of
* command execution.
* - DRM_BO_FLAG_MEM_TT: The buffer should be validated in TT memory.
* - DRM_BO_FLAG_MEM_VRAM: The buffer should be validated in video
* memory.
* \param delta Constant value to be added to the relocation target's offset.
* \param offset Byte offset within batch_buf of the relocated pointer.
* \param target Buffer whose offset should be written into the relocation
* entry.
*/
void (*emit_reloc)(dri_bo *reloc_buf, GLuint flags, GLuint delta,
GLuint offset, dri_bo *target);
/**
* Processes the relocations, either in userland or by converting the list
* for use in batchbuffer submission.
*
* Kernel-based implementations will return a pointer to the arguments
* to be handed with batchbuffer submission to the kernel. The userland
* implementation performs the buffer validation and emits relocations
* into them the appopriate order.
*
* \param batch_buf buffer at the root of the tree of relocations
* \param count returns the number of buffers validated.
* \return relocation record for use in command submission.
* */
void *(*process_relocs)(dri_bo *batch_buf, GLuint *count);
void (*post_submit)(dri_bo *batch_buf, dri_fence **fence);
};

View file

@ -63,10 +63,12 @@
struct fake_buffer_reloc
{
dri_bo *buf;
dri_bo *reloc_buf;
dri_bo *target_buf;
GLuint offset;
GLuint delta; /* not needed? */
GLuint validate_flags;
GLboolean relocated;
};
struct block {
@ -139,7 +141,14 @@ typedef struct _dri_bo_fake {
*/
unsigned int flags;
unsigned int alignment;
GLboolean is_static;
GLboolean is_static, validated;
unsigned int map_count;
/* Relocation count to assist in determining the order to perform
* relocations.
*/
unsigned int nr_relocs;
/* Flags for the buffer to be validated with in command submission */
uint64_t validate_flags;
struct block *block;
void *backing_store;
@ -629,6 +638,7 @@ dri_fake_bo_unreference(dri_bo *bo)
free_backing_store(bo);
_glthread_UNLOCK_MUTEX(bufmgr_fake->mutex);
free(bo);
DBG("drm_bo_unreference: free %s\n", bo_fake->name);
return;
}
_glthread_UNLOCK_MUTEX(bufmgr_fake->mutex);
@ -649,6 +659,12 @@ dri_fake_bo_map(dri_bo *bo, GLboolean write_enable)
return 0;
_glthread_LOCK_MUTEX(bufmgr_fake->mutex);
/* Allow recursive mapping, which is used internally in relocation. */
if (bo_fake->map_count++ != 0) {
_glthread_UNLOCK_MUTEX(bufmgr_fake->mutex);
return 0;
}
{
DBG("drm_bo_map: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
bo_fake->bo.size / 1024);
@ -692,20 +708,26 @@ dri_fake_bo_map(dri_bo *bo, GLboolean write_enable)
static int
dri_fake_bo_unmap(dri_bo *bo)
{
dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr;
dri_bo_fake *bo_fake = (dri_bo_fake *)bo;
/* Static buffers are always mapped. */
if (bo_fake->is_static)
return 0;
if (bo == NULL)
_glthread_LOCK_MUTEX(bufmgr_fake->mutex);
if (--bo_fake->map_count != 0) {
_glthread_UNLOCK_MUTEX(bufmgr_fake->mutex);
return 0;
}
DBG("drm_bo_unmap: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name,
bo_fake->bo.size / 1024);
bo->virtual = NULL;
_glthread_UNLOCK_MUTEX(bufmgr_fake->mutex);
return 0;
}
@ -854,17 +876,34 @@ dri_fake_destroy(dri_bufmgr *bufmgr)
}
static void
dri_fake_emit_reloc(dri_bo *batch_buf, GLuint flags, GLuint delta, GLuint offset,
dri_bo *relocatee)
dri_fake_emit_reloc(dri_bo *reloc_buf, GLuint flags, GLuint delta,
GLuint offset, dri_bo *target_buf)
{
dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)batch_buf->bufmgr;
dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)reloc_buf->bufmgr;
struct fake_buffer_reloc *r = &bufmgr_fake->reloc[bufmgr_fake->nr_relocs++];
dri_bo_fake *target_fake = (dri_bo_fake *)target_buf;
dri_bo_fake *reloc_fake = (dri_bo_fake *)reloc_buf;
assert(bufmgr_fake->nr_relocs <= MAX_RELOCS);
dri_bo_reference(relocatee);
dri_bo_reference(target_buf);
r->buf = relocatee;
if (target_fake->flags == 0) {
target_fake->validate_flags = flags;
} else {
/* Mask the memory location to the intersection of all the memory
* locations the buffer is being validated to.
*/
target_fake->validate_flags =
(target_fake->validate_flags & ~DRM_BO_MASK_MEM) |
(flags & target_fake->validate_flags & DRM_BO_MASK_MEM);
/* All the other flags just accumulate. */
target_fake->validate_flags |= flags & ~DRM_BO_MASK_MEM;
}
reloc_fake->nr_relocs++;
r->reloc_buf = reloc_buf;
r->target_buf = target_buf;
r->offset = offset;
r->delta = delta;
r->validate_flags = flags;
@ -872,81 +911,83 @@ dri_fake_emit_reloc(dri_bo *batch_buf, GLuint flags, GLuint delta, GLuint offset
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_relocs(dri_bo *batch_buf, GLuint *count_p)
{
dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)batch_buf->bufmgr;
GLuint i;
GLuint *ptr;
GLuint count = 0;
assert(batch_buf->virtual != NULL);
ptr = batch_buf->virtual;
GLboolean cont;
int ret;
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.
/* Loop over the relocation list validating and writing the relocation
* entries for target buffers that don't contain any remaining relocations.
* In the current examples we have, the depth of the tree of relocations
* is small (up to 3), so this loop shouldn't hurt too bad.
*/
qsort(bufmgr_fake->reloc, bufmgr_fake->nr_relocs, sizeof(bufmgr_fake->reloc[0]),
relocation_sort);
do {
cont = GL_FALSE;
/* 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];
for (i = 0; i < bufmgr_fake->nr_relocs; i++) {
struct fake_buffer_reloc *r = &bufmgr_fake->reloc[i];
dri_bo_fake *reloc_fake = (dri_bo_fake *)r->reloc_buf;
dri_bo_fake *target_fake = (dri_bo_fake *)r->target_buf;
if (r->validate_flags & DRM_BO_FLAG_WRITE)
bufmgr_fake->performed_rendering = GL_TRUE;
if (r->relocated)
continue;
/* 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;
if (target_fake->nr_relocs == 0) {
/* Validate the target if it hasn't been. If we fail, fence to
* clear the unfenced list and bail out.
*/
if (!target_fake->validated) {
int 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;
ret = dri_fake_bo_validate(r->target_buf,
target_fake->validate_flags);
if (ret != 0) {
dri_fence *fo;
dri_bo_unmap(r->reloc_buf);
fo = dri_fake_fence_validated(batch_buf->bufmgr,
"batchbuffer failure fence",
GL_TRUE);
dri_fence_unreference(fo);
goto done;
}
if (target_fake->validate_flags & DRM_BO_FLAG_WRITE)
bufmgr_fake->performed_rendering = GL_TRUE;
count++;
}
/* Map and write in the relocation to reloc_buf */
if (reloc_fake->map_count == 0)
dri_bo_map(r->reloc_buf, GL_TRUE);
*(uint32_t *)(r->reloc_buf->virtual + r->offset) =
r->target_buf->offset + r->delta;
/* Mark this relocation in reloc_buf as done. If it was the last
* one to be done to it, unmap the buffer so it can be validated
* next.
*/
reloc_fake->nr_relocs--;
if (reloc_fake->nr_relocs == 0)
dri_bo_unmap(r->reloc_buf);
r->relocated = GL_TRUE;
cont = GL_TRUE;
}
/* Validate. If we fail, fence to clear the unfenced list and bail
* out.
*/
ret = dri_fake_bo_validate(r->buf, validate_flags);
if (ret != 0) {
dri_fence *fo;
dri_bo_unmap(batch_buf);
fo = dri_fake_fence_validated(batch_buf->bufmgr,
"batchbuffer failure fence", GL_TRUE);
dri_fence_unreference(fo);
goto done;
}
count++;
}
ptr[r->offset / 4] = r->buf->offset + r->delta;
dri_bo_unreference(r->buf);
}
dri_bo_unmap(batch_buf);
} while (cont);
dri_fake_bo_validate(batch_buf, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE);
ret = dri_fake_bo_validate(batch_buf, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE);
assert(ret == 0);
*count_p = count;
bufmgr_fake->nr_relocs = 0;
done:
return NULL;
}
@ -956,6 +997,7 @@ 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;
int i;
fo = dri_fake_fence_validated(batch_buf->bufmgr, "Batch fence", GL_TRUE);
@ -965,6 +1007,25 @@ dri_fake_post_submit(dri_bo *batch_buf, dri_fence **last_fence)
} else {
dri_fence_unreference(fo);
}
/* Clean up the validation list. */
for (i = 0; i < bufmgr_fake->nr_relocs; i++) {
struct fake_buffer_reloc *r = &bufmgr_fake->reloc[i];
dri_bo_fake *reloc_fake = (dri_bo_fake *)r->reloc_buf;
dri_bo_fake *target_fake = (dri_bo_fake *)r->target_buf;
assert(r->relocated);
assert(reloc_fake->map_count == 0);
DBG("%s@0x%08x + 0x%08x -> %s@0x%08x + 0x%08x\n",
reloc_fake->name, (uint32_t)r->reloc_buf->offset, r->offset,
target_fake->name, (uint32_t)r->target_buf->offset, r->delta);
reloc_fake->validate_flags = 0;
target_fake->validated = GL_FALSE;
r->relocated = GL_FALSE;
dri_bo_unreference(r->target_buf);
}
bufmgr_fake->nr_relocs = 0;
}
dri_bufmgr *