mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-02-14 06:50:28 +01:00
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.
This commit is contained in:
parent
a5e73e6887
commit
02df36f394
8 changed files with 201 additions and 0 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
161
src/mesa/drivers/dri/i965/brw_aub_playback.c
Normal file
161
src/mesa/drivers/dri/i965/brw_aub_playback.c
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue