summaryrefslogtreecommitdiff
path: root/i965/brw_aub_playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'i965/brw_aub_playback.c')
-rw-r--r--i965/brw_aub_playback.c446
1 files changed, 446 insertions, 0 deletions
diff --git a/i965/brw_aub_playback.c b/i965/brw_aub_playback.c
new file mode 100644
index 0000000..99d9475
--- /dev/null
+++ b/i965/brw_aub_playback.c
@@ -0,0 +1,446 @@
+
+#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_defines.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) {
+ _mesa_printf("EOF in %s\n", __FUNCTION__);
+ return 1;
+ }
+
+ s->csr += size;
+ return 0;
+}
+
+static void flush_and_fence( struct aub_state *s )
+{
+ struct intel_context *intel = s->intel;
+ GLuint buf[2];
+
+ buf[0] = intel->vtbl.flush_cmd();
+ buf[1] = 0;
+
+ intel_cmd_ioctl(intel, (char *)&buf, sizeof(buf));
+
+ intelWaitIrq( intel, intelEmitIrqLocked( intel ));
+}
+
+static void flush_cmds( struct aub_state *s,
+ const void *data,
+ int len )
+{
+ DBG("%s %d\n", __FUNCTION__, len);
+
+ if (len & 0x4) {
+ unsigned int *tmp = malloc(len + 4);
+ DBG("padding to octword\n");
+ memcpy(tmp, data, len);
+ tmp[len/4] = MI_NOOP;
+ flush_cmds(s, tmp, len+4);
+ free(tmp);
+ return;
+ }
+
+ /* 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, (void *)data, len);
+
+ if (1)
+ flush_and_fence(s);
+}
+
+static const char *pstrings[] = {
+ "none",
+ "POINTLIST",
+ "LINELIST",
+ "LINESTRIP",
+ "TRILIST",
+ "TRISTRIP",
+ "TRIFAN",
+ "QUADLIST",
+ "QUADSTRIP",
+ "LINELIST_ADJ",
+ "LINESTRIP_ADJ",
+ "TRILIST_ADJ",
+ "TRISTRIP_ADJ",
+ "TRISTRIP_REVERSE",
+ "POLYGON",
+ "RECTLIST",
+ "LINELOOP",
+ "POINTLIST_BF",
+ "LINESTRIP_CONT",
+ "LINESTRIP_BF",
+ "LINESTRIP_CONT_BF",
+ "TRIFAN_NOSTIPPLE",
+};
+
+static void do_3d_prim( struct aub_state *s,
+ const void *data,
+ int len )
+{
+ struct brw_3d_primitive prim;
+ const struct brw_3d_primitive *orig = data;
+ int i;
+
+ assert(len == sizeof(prim));
+ memcpy(&prim, data, sizeof(prim));
+
+#define START 0
+#define BLOCK (12*28)
+
+ if (orig->verts_per_instance < BLOCK)
+ flush_cmds(s, &prim, sizeof(prim));
+ else {
+ for (i = START; i + BLOCK < orig->verts_per_instance; i += BLOCK/2) {
+ prim.start_vert_location = i;
+ prim.verts_per_instance = BLOCK;
+ _mesa_printf("%sprim %d/%s verts %d..%d (of %d)\n",
+ prim.header.indexed ? "INDEXED " : "",
+ prim.header.topology, pstrings[prim.header.topology%16],
+ prim.start_vert_location,
+ prim.start_vert_location + prim.verts_per_instance,
+ orig->verts_per_instance);
+ flush_cmds(s, &prim, sizeof(prim));
+ }
+ }
+}
+
+
+
+static struct {
+ int cmd;
+ const char *name;
+ int has_length;
+} cmd_info[] = {
+ { 0, "NOOP", 0 },
+ { 0x5410, "XY_COLOR_BLT_RGB", 1 },
+ { 0x5430, "XY_COLOR_BLT_RGBA", 1 },
+ { 0x54d0, "XY_SRC_COPY_BLT_RGB", 1 },
+ { 0x54f0, "XY_SRC_COPY_BLT_RGBA", 1 },
+ { CMD_URB_FENCE, "URB_FENCE", 1 },
+ { CMD_CONST_BUFFER_STATE, "CONST_BUFFER_STATE", 1 },
+ { CMD_CONST_BUFFER, "CONST_BUFFER", 1 },
+ { CMD_STATE_BASE_ADDRESS, "STATE_BASE_ADDRESS", 1 },
+ { CMD_STATE_INSN_POINTER, "STATE_INSN_POINTER", 1 },
+ { CMD_PIPELINE_SELECT_965, "PIPELINE_SELECT", 0, },
+ { CMD_PIPELINE_SELECT_IGD, "PIPELINE_SELECT", 0,},
+ { CMD_PIPELINED_STATE_POINTERS, "PIPELINED_STATE_POINTERS", 1 },
+ { CMD_BINDING_TABLE_PTRS, "BINDING_TABLE_PTRS", 1 },
+ { CMD_VERTEX_BUFFER, "VERTEX_BUFFER", 1 },
+ { CMD_VERTEX_ELEMENT, "VERTEX_ELEMENT", 1 },
+ { CMD_INDEX_BUFFER, "INDEX_BUFFER", 1 },
+ { CMD_VF_STATISTICS_965, "VF_STATISTICS", 0 },
+ { CMD_VF_STATISTICS_IGD, "VF_STATISTICS", 0 },
+ { CMD_DRAW_RECT, "DRAW_RECT", 1 },
+ { CMD_BLEND_CONSTANT_COLOR, "BLEND_CONSTANT_COLOR", 1 },
+ { CMD_CHROMA_KEY, "CHROMA_KEY", 1 },
+ { CMD_DEPTH_BUFFER, "DEPTH_BUFFER", 1 },
+ { CMD_POLY_STIPPLE_OFFSET, "POLY_STIPPLE_OFFSET", 1 },
+ { CMD_POLY_STIPPLE_PATTERN, "POLY_STIPPLE_PATTERN", 1 },
+ { CMD_LINE_STIPPLE_PATTERN, "LINE_STIPPLE_PATTERN", 1 },
+ { CMD_AA_LINE_PARAMETERS, "AA_LINE_PARAMETERS", 1},
+ { CMD_GLOBAL_DEPTH_OFFSET_CLAMP, "GLOBAL_DEPTH_OFFSET_CLAMP", 1 },
+ { CMD_PIPE_CONTROL, "PIPE_CONTROL", 1 },
+ { CMD_MI_FLUSH, "MI_FLUSH", 0 },
+ { CMD_3D_PRIM, "3D_PRIM", 1 },
+};
+
+#define NR_CMDS (sizeof(cmd_info)/sizeof(cmd_info[0]))
+
+
+static int find_command( unsigned int cmd )
+{
+ int i;
+
+ for (i = 0; i < NR_CMDS; i++)
+ if (cmd == cmd_info[i].cmd)
+ return i;
+
+ return -1;
+}
+
+
+
+static int parse_commands( struct aub_state *s,
+ const unsigned int *data,
+ int len )
+{
+ while (len) {
+ int cmd = data[0] >> 16;
+ int dwords;
+ int i;
+
+ i = find_command(cmd);
+
+ if (i < 0) {
+ _mesa_printf("couldn't find info for cmd %x\n", cmd);
+ return 1;
+ }
+
+ if (cmd_info[i].has_length)
+ dwords = (data[0] & 0xff) + 2;
+ else
+ dwords = 1;
+
+ _mesa_printf("%s (%d dwords) 0x%x\n", cmd_info[i].name, dwords, data[0]);
+
+ if (len < dwords * 4) {
+ _mesa_printf("EOF in %s (%d bytes)\n", __FUNCTION__, len);
+ return 1;
+ }
+
+
+ if (0 && cmd == CMD_3D_PRIM)
+ do_3d_prim(s, data, dwords * 4);
+ else
+ flush_cmds(s, data, dwords * 4);
+
+ data += dwords;
+ len -= dwords * 4;
+ }
+
+ return 0;
+}
+
+
+
+static void parse_data_write( struct aub_state *s,
+ const struct aub_block_header *bh,
+ void *dest,
+ const unsigned int *data,
+ int len )
+{
+ switch (bh->type) {
+ case DW_GENERAL_STATE:
+ switch (bh->general_state_type) {
+ case DWGS_VERTEX_SHADER_STATE: {
+ struct brw_vs_unit_state vs;
+ assert(len == sizeof(vs));
+
+ _mesa_printf("DWGS_VERTEX_SHADER_STATE\n");
+ memcpy(&vs, data, sizeof(vs));
+
+/* vs.vs6.vert_cache_disable = 1; */
+/* vs.thread4.max_threads = 4; */
+
+ memcpy(dest, &vs, sizeof(vs));
+ return;
+ }
+ case DWGS_CLIPPER_STATE: {
+ struct brw_clip_unit_state clip;
+ assert(len == sizeof(clip));
+
+ _mesa_printf("DWGS_CLIPPER_STATE\n");
+ memcpy(&clip, data, sizeof(clip));
+
+/* clip.thread4.max_threads = 0; */
+/* clip.clip5.clip_mode = BRW_CLIPMODE_REJECT_ALL; */
+
+ memcpy(dest, &clip, sizeof(clip));
+ return;
+ }
+
+ case DWGS_NOTYPE:
+ case DWGS_GEOMETRY_SHADER_STATE:
+ case DWGS_STRIPS_FANS_STATE:
+ break;
+
+ case DWGS_WINDOWER_IZ_STATE: {
+ struct brw_wm_unit_state wm;
+ assert(len == sizeof(wm));
+
+ _mesa_printf("DWGS_WINDOWER_IZ_STATE\n");
+ memcpy(&wm, data, sizeof(wm));
+
+/* wm.wm5.max_threads = 10; */
+
+ memcpy(dest, &wm, sizeof(wm));
+ return;
+ }
+
+ case DWGS_COLOR_CALC_STATE:
+ case DWGS_CLIPPER_VIEWPORT_STATE:
+ case DWGS_STRIPS_FANS_VIEWPORT_STATE:
+ case DWGS_COLOR_CALC_VIEWPORT_STATE:
+ case DWGS_SAMPLER_STATE:
+ case DWGS_KERNEL_INSTRUCTIONS:
+ case DWGS_SCRATCH_SPACE:
+ case DWGS_SAMPLER_DEFAULT_COLOR:
+ case DWGS_INTERFACE_DESCRIPTOR:
+ case DWGS_VLD_STATE:
+ case DWGS_VFE_STATE:
+ default:
+ break;
+ }
+ break;
+ case DW_SURFACE_STATE:
+ break;
+ case DW_1D_MAP:
+ case DW_2D_MAP:
+ case DW_CUBE_MAP:
+ case DW_VOLUME_MAP:
+ case DW_CONSTANT_BUFFER:
+ case DW_CONSTANT_URB_ENTRY:
+ case DW_VERTEX_BUFFER:
+ case DW_INDEX_BUFFER:
+ default:
+ break;
+ }
+
+ memcpy(dest, data, len);
+}
+
+
+/* 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;
+
+ _mesa_printf("block header at 0x%x\n", s->csr);
+
+ if (s->csr + len + sizeof(*bh) > s->sz) {
+ _mesa_printf("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;
+ }
+
+#if 1
+ parse_data_write(s, bh, dest, data, len);
+#else
+ memcpy(dest, data, len);
+#endif
+ break;
+ }
+ case BH_COMMAND_WRITE:
+#if 0
+ intel_cmd_ioctl(s->intel, (void *)data, len);
+#else
+ if (parse_commands(s, data, len) != 0)
+ _mesa_printf("parse_commands failed\n");
+#endif
+ 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) {
+ _mesa_printf("couldn't open aubfile: %s\n", filename);
+ return 1;
+ }
+
+ if (fstat(fd, &sb) != 0) {
+ _mesa_printf("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) {
+ _mesa_printf("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:
+ _mesa_printf("unknown instruction %x\n", insn);
+ retval = 1;
+ break;
+ }
+ }
+ }
+ UNLOCK_HARDWARE(intel);
+ return retval;
+}
+
+
+
+
+
+
+