From 02df36f394da4f699b4841c279a6b573fcb7c32b Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Fri, 8 Sep 2006 10:36:32 +0000 Subject: [PATCH] Basic facility for playing back captured aubfiles. Requires a small hack to the drm to disable command verification on the cmd_buffer ioctl. Doesn't exactly replay as commands are normally delivered as batchbuffers but are captured and replayed as commands on the ring. --- src/mesa/drivers/dri/i965/Makefile | 1 + src/mesa/drivers/dri/i965/brw_aub.c | 3 + src/mesa/drivers/dri/i965/brw_aub.h | 3 + src/mesa/drivers/dri/i965/brw_aub_playback.c | 161 +++++++++++++++++++ src/mesa/drivers/dri/i965/brw_context.c | 8 + src/mesa/drivers/dri/i965/brw_draw.c | 6 + src/mesa/drivers/dri/i965/bufmgr.h | 4 + src/mesa/drivers/dri/i965/bufmgr_fake.c | 15 ++ 8 files changed, 201 insertions(+) create mode 100644 src/mesa/drivers/dri/i965/brw_aub_playback.c diff --git a/src/mesa/drivers/dri/i965/Makefile b/src/mesa/drivers/dri/i965/Makefile index 1710d2b6d45..e4fb451cc09 100644 --- a/src/mesa/drivers/dri/i965/Makefile +++ b/src/mesa/drivers/dri/i965/Makefile @@ -20,6 +20,7 @@ DRIVER_SOURCES = \ intel_tex.c \ intel_tex_validate.c \ brw_aub.c \ + brw_aub_playback.c \ brw_cc.c \ brw_clip.c \ brw_clip_line.c \ diff --git a/src/mesa/drivers/dri/i965/brw_aub.c b/src/mesa/drivers/dri/i965/brw_aub.c index 2b7d1f4356a..cc70692adda 100644 --- a/src/mesa/drivers/dri/i965/brw_aub.c +++ b/src/mesa/drivers/dri/i965/brw_aub.c @@ -291,6 +291,9 @@ int brw_aub_init( struct brw_context *brw ) i++; + if (_mesa_getenv("INTEL_REPLAY")) + return 0; + if (_mesa_getenv("INTEL_AUBFILE")) { val = snprintf(filename, sizeof(filename), "%s%d.aub", _mesa_getenv("INTEL_AUBFILE"), i%4); _mesa_printf("--> Aub file: %s\n", filename); diff --git a/src/mesa/drivers/dri/i965/brw_aub.h b/src/mesa/drivers/dri/i965/brw_aub.h index a2e1f6112dd..198e36dc3c0 100644 --- a/src/mesa/drivers/dri/i965/brw_aub.h +++ b/src/mesa/drivers/dri/i965/brw_aub.h @@ -166,4 +166,7 @@ struct intel_context; int brw_aub_init( struct brw_context *brw ); void brw_aub_destroy( struct brw_context *brw ); +int brw_playback_aubfile(struct brw_context *brw, + const char *filename); + #endif diff --git a/src/mesa/drivers/dri/i965/brw_aub_playback.c b/src/mesa/drivers/dri/i965/brw_aub_playback.c new file mode 100644 index 00000000000..73743daa60c --- /dev/null +++ b/src/mesa/drivers/dri/i965/brw_aub_playback.c @@ -0,0 +1,161 @@ + +#include +#include +#include +#include +#include +#include + +#include "brw_aub.h" +#include "brw_context.h" +#include "intel_ioctl.h" +#include "bufmgr.h" + +struct aub_state { + struct intel_context *intel; + const char *map; + unsigned int csr; + unsigned int sz; +}; + + +static int gobble( struct aub_state *s, int size ) +{ + if (s->csr + size > s->sz) { + DBG("EOF in %s\n", __FUNCTION__); + return 1; + } + + s->csr += size; + return 0; +} + +/* In order to work, the memory layout has to be the same as the X + * server which created the aubfile. + */ +static int parse_block_header( struct aub_state *s ) +{ + struct aub_block_header *bh = (struct aub_block_header *)(s->map + s->csr); + void *data = (void *)(bh + 1); + unsigned int len = (bh->length + 3) & ~3; + + DBG("block header at 0x%x\n", s->csr); + + if (s->csr + len + sizeof(*bh) > s->sz) { + DBG("EOF in data in %s\n", __FUNCTION__); + return 1; + } + + if (bh->address_space == ADDR_GTT) { + + switch (bh->operation) + { + case BH_DATA_WRITE: { + void *dest = bmFindVirtual( s->intel, bh->address, len ); + if (dest == NULL) { + _mesa_printf("Couldn't find virtual address for offset %x\n", bh->address); + return 1; + } + + /* Just copy the data to the indicated place in agp memory: + */ + memcpy(dest, data, len); + break; + } + case BH_COMMAND_WRITE: + /* For ring data, just send off immediately via an ioctl. + * This differs slightly from how the stream was executed + * initially as this would have been a batchbuffer. + */ + intel_cmd_ioctl(s->intel, data, len, GL_TRUE); + break; + default: + break; + } + } + + s->csr += sizeof(*bh) + len; + return 0; +} + + +#define AUB_FILE_HEADER 0xe085000b +#define AUB_BLOCK_HEADER 0xe0c10003 +#define AUB_DUMP_BMP 0xe09e0004 + +int brw_playback_aubfile(struct brw_context *brw, + const char *filename) +{ + struct intel_context *intel = &brw->intel; + struct aub_state state; + struct stat sb; + int fd; + int retval = 0; + + state.intel = intel; + + fd = open(filename, O_RDONLY, 0); + if (fd < 0) { + DBG("couldn't open aubfile: %s\n", filename); + return 1; + } + + if (fstat(fd, &sb) != 0) { + DBG("couldn't open %s\n", filename); + return 1; + } + + state.csr = 0; + state.sz = sb.st_size; + state.map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + + if (state.map == NULL) { + DBG("couldn't mmap %s\n", filename); + return 1; + } + + LOCK_HARDWARE(intel); + { + /* Make sure we don't confuse anything that might happen to be + * going on with the hardware: + */ +/* bmEvictAll(intel); */ +/* intel->vtbl.lost_hardware(intel); */ + + + /* Replay the aubfile item by item: + */ + while (retval == 0 && + state.csr != state.sz) { + unsigned int insn = *(unsigned int *)(state.map + state.csr); + + switch (insn) { + case AUB_FILE_HEADER: + retval = gobble(&state, sizeof(struct aub_file_header)); + break; + + case AUB_BLOCK_HEADER: + retval = parse_block_header(&state); + break; + + case AUB_DUMP_BMP: + retval = gobble(&state, sizeof(struct aub_dump_bmp)); + break; + + default: + DBG("unknown instruction %x\n", insn); + retval = 1; + break; + } + } + } + UNLOCK_HARDWARE(intel); + return retval; +} + + + + + + + diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c index dba6845e53e..c1f6617f3fd 100644 --- a/src/mesa/drivers/dri/i965/brw_context.c +++ b/src/mesa/drivers/dri/i965/brw_context.c @@ -162,6 +162,14 @@ GLboolean brwCreateContext( const __GLcontextModes *mesaVis, brw_exec_init( ctx ); brw_save_init( ctx ); + { + const char *filename = getenv("INTEL_REPLAY"); + if (filename) { + brw_playback_aubfile(brw, filename); + exit(0); + } + } + return GL_TRUE; } diff --git a/src/mesa/drivers/dri/i965/brw_draw.c b/src/mesa/drivers/dri/i965/brw_draw.c index 02c24574232..ef4f1104848 100644 --- a/src/mesa/drivers/dri/i965/brw_draw.c +++ b/src/mesa/drivers/dri/i965/brw_draw.c @@ -400,6 +400,12 @@ GLboolean brw_draw_prims( GLcontext *ctx, retval = brw_try_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index, flags); } + if (intel->aub_file) { + intelFinish( &intel->ctx ); + intel->aub_wrap = 1; + } + + return retval; } diff --git a/src/mesa/drivers/dri/i965/bufmgr.h b/src/mesa/drivers/dri/i965/bufmgr.h index ab5d56a231a..83a810cc6dd 100644 --- a/src/mesa/drivers/dri/i965/bufmgr.h +++ b/src/mesa/drivers/dri/i965/bufmgr.h @@ -186,6 +186,10 @@ void bmReleaseBuffers( struct intel_context * ); GLboolean bmError( struct intel_context * ); void bmEvictAll( struct intel_context * ); +void *bmFindVirtual( struct intel_context *intel, + unsigned int offset, + size_t sz ); + /* This functionality is used by the buffer manager, not really sure * if we need to be exposing it in this way, probably libdrm will * offer equivalent calls. diff --git a/src/mesa/drivers/dri/i965/bufmgr_fake.c b/src/mesa/drivers/dri/i965/bufmgr_fake.c index 67fa7c8e2e2..40e92398836 100644 --- a/src/mesa/drivers/dri/i965/bufmgr_fake.c +++ b/src/mesa/drivers/dri/i965/bufmgr_fake.c @@ -650,6 +650,21 @@ static struct buffer *do_GenBuffer(struct intel_context *intel, const char *name return buf; } + +void *bmFindVirtual( struct intel_context *intel, + unsigned int offset, + size_t sz ) +{ + struct bufmgr *bm = intel->bm; + int i; + + for (i = 0; i < bm->nr_pools; i++) + if (offset >= bm->pool[i].low_offset && + offset + sz <= bm->pool[i].low_offset + bm->pool[i].size) + return bm->pool[i].virtual + offset; + + return NULL; +} void bmGenBuffers(struct intel_context *intel, -- 2.30.2