From 8dfc9f038ee3f6a57f0a3f3cc641b0866a6111b7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 16 Oct 2013 11:51:22 -0700 Subject: [PATCH] i965/fs: Use the gen7 scratch read opcode when possible. This avoids a lot of message setup we had to do otherwise. Improves GLB2.7 performance with register spilling force enabled by 1.6442% +/- 0.553218% (n=4). v2: Use BRW_PREDICATE_NONE, improve a comment (by Paul). Reviewed-by: Paul Berry --- src/mesa/drivers/dri/i965/brw_defines.h | 7 ++++ src/mesa/drivers/dri/i965/brw_eu.h | 5 +++ src/mesa/drivers/dri/i965/brw_eu_emit.c | 42 +++++++++++++++++++ src/mesa/drivers/dri/i965/brw_fs.h | 1 + .../drivers/dri/i965/brw_fs_generator.cpp | 10 +++++ .../drivers/dri/i965/brw_fs_reg_allocate.cpp | 15 +++++-- .../dri/i965/brw_schedule_instructions.cpp | 12 ++++++ src/mesa/drivers/dri/i965/brw_shader.cpp | 2 + 8 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_defines.h b/src/mesa/drivers/dri/i965/brw_defines.h index 224869358cd..bad6d40fca8 100644 --- a/src/mesa/drivers/dri/i965/brw_defines.h +++ b/src/mesa/drivers/dri/i965/brw_defines.h @@ -780,6 +780,7 @@ enum opcode { SHADER_OPCODE_GEN4_SCRATCH_READ, SHADER_OPCODE_GEN4_SCRATCH_WRITE, + SHADER_OPCODE_GEN7_SCRATCH_READ, FS_OPCODE_DDX, FS_OPCODE_DDY, @@ -1141,6 +1142,12 @@ enum brw_message_target { #define GEN7_DATAPORT_DC_BYTE_SCATTERED_WRITE 12 #define GEN7_DATAPORT_DC_UNTYPED_SURFACE_WRITE 13 +#define GEN7_DATAPORT_SCRATCH_READ ((1 << 18) | \ + (0 << 17)) +#define GEN7_DATAPORT_SCRATCH_WRITE ((1 << 18) | \ + (1 << 17)) +#define GEN7_DATAPORT_SCRATCH_NUM_REGS_SHIFT 12 + /* HSW */ #define HSW_DATAPORT_DC_PORT0_OWORD_BLOCK_READ 0 #define HSW_DATAPORT_DC_PORT0_UNALIGNED_OWORD_BLOCK_READ 1 diff --git a/src/mesa/drivers/dri/i965/brw_eu.h b/src/mesa/drivers/dri/i965/brw_eu.h index 1a448d055c3..01f8bccdb2f 100644 --- a/src/mesa/drivers/dri/i965/brw_eu.h +++ b/src/mesa/drivers/dri/i965/brw_eu.h @@ -379,6 +379,11 @@ void brw_oword_block_write_scratch(struct brw_compile *p, int num_regs, GLuint offset); +void gen7_block_read_scratch(struct brw_compile *p, + struct brw_reg dest, + int num_regs, + GLuint offset); + void brw_shader_time_add(struct brw_compile *p, struct brw_reg payload, uint32_t surf_index); diff --git a/src/mesa/drivers/dri/i965/brw_eu_emit.c b/src/mesa/drivers/dri/i965/brw_eu_emit.c index 34239be26a2..cc093e0cd67 100644 --- a/src/mesa/drivers/dri/i965/brw_eu_emit.c +++ b/src/mesa/drivers/dri/i965/brw_eu_emit.c @@ -2055,6 +2055,48 @@ brw_oword_block_read_scratch(struct brw_compile *p, } } +void +gen7_block_read_scratch(struct brw_compile *p, + struct brw_reg dest, + int num_regs, + GLuint offset) +{ + dest = retype(dest, BRW_REGISTER_TYPE_UW); + + struct brw_instruction *insn = next_insn(p, BRW_OPCODE_SEND); + + assert(insn->header.predicate_control == BRW_PREDICATE_NONE); + insn->header.compression_control = BRW_COMPRESSION_NONE; + + brw_set_dest(p, insn, dest); + + /* The HW requires that the header is present; this is to get the g0.5 + * scratch offset. + */ + bool header_present = true; + brw_set_src0(p, insn, brw_vec8_grf(0, 0)); + + brw_set_message_descriptor(p, insn, + GEN7_SFID_DATAPORT_DATA_CACHE, + 1, /* mlen: just g0 */ + num_regs, + header_present, + false); + + insn->bits3.ud |= GEN7_DATAPORT_SCRATCH_READ; + + assert(num_regs == 1 || num_regs == 2 || num_regs == 4); + insn->bits3.ud |= (num_regs - 1) << GEN7_DATAPORT_SCRATCH_NUM_REGS_SHIFT; + + /* According to the docs, offset is "A 12-bit HWord offset into the memory + * Immediate Memory buffer as specified by binding table 0xFF." An HWORD + * is 32 bytes, which happens to be the size of a register. + */ + offset /= REG_SIZE; + assert(offset < (1 << 12)); + insn->bits3.ud |= offset; +} + /** * Read a float[4] vector from the data port Data Cache (const buffer). * Location (in buffer) should be a multiple of 16. diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h index 0512ab43948..a3a4dc0f141 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.h +++ b/src/mesa/drivers/dri/i965/brw_fs.h @@ -525,6 +525,7 @@ private: bool negate_value); void generate_scratch_write(fs_inst *inst, struct brw_reg src); void generate_scratch_read(fs_inst *inst, struct brw_reg dst); + void generate_scratch_read_gen7(fs_inst *inst, struct brw_reg dst); void generate_uniform_pull_constant_load(fs_inst *inst, struct brw_reg dst, struct brw_reg index, struct brw_reg offset); diff --git a/src/mesa/drivers/dri/i965/brw_fs_generator.cpp b/src/mesa/drivers/dri/i965/brw_fs_generator.cpp index 21729498c3a..672e8968658 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_generator.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_generator.cpp @@ -769,6 +769,12 @@ fs_generator::generate_scratch_read(fs_inst *inst, struct brw_reg dst) dispatch_width / 8, inst->offset); } +void +fs_generator::generate_scratch_read_gen7(fs_inst *inst, struct brw_reg dst) +{ + gen7_block_read_scratch(p, dst, dispatch_width / 8, inst->offset); +} + void fs_generator::generate_uniform_pull_constant_load(fs_inst *inst, struct brw_reg dst, @@ -1587,6 +1593,10 @@ fs_generator::generate_code(exec_list *instructions) generate_scratch_read(inst, dst); break; + case SHADER_OPCODE_GEN7_SCRATCH_READ: + generate_scratch_read_gen7(inst, dst); + break; + case FS_OPCODE_UNIFORM_PULL_CONSTANT_LOAD: generate_uniform_pull_constant_load(inst, dst, src[0], src[1]); break; diff --git a/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp b/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp index d975423086c..d9e80d07f48 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp @@ -542,14 +542,22 @@ fs_visitor::emit_unspill(fs_inst *inst, fs_reg dst, uint32_t spill_offset, int count) { for (int i = 0; i < count; i++) { + /* The gen7 descriptor-based offset is 12 bits of HWORD units. */ + bool gen7_read = brw->gen >= 7 && spill_offset < (1 << 12) * REG_SIZE; + fs_inst *unspill_inst = - new(mem_ctx) fs_inst(SHADER_OPCODE_GEN4_SCRATCH_READ, dst); + new(mem_ctx) fs_inst(gen7_read ? + SHADER_OPCODE_GEN7_SCRATCH_READ : + SHADER_OPCODE_GEN4_SCRATCH_READ, + dst); unspill_inst->offset = spill_offset; unspill_inst->ir = inst->ir; unspill_inst->annotation = inst->annotation; - unspill_inst->base_mrf = 14; - unspill_inst->mlen = 1; /* header contains offset */ + if (!gen7_read) { + unspill_inst->base_mrf = 14; + unspill_inst->mlen = 1; /* header contains offset */ + } inst->insert_before(unspill_inst); dst.reg_offset++; @@ -617,6 +625,7 @@ fs_visitor::choose_spill_reg(struct ra_graph *g) break; case SHADER_OPCODE_GEN4_SCRATCH_READ: + case SHADER_OPCODE_GEN7_SCRATCH_READ: if (inst->dst.file == GRF) no_spill[inst->dst.reg] = true; break; diff --git a/src/mesa/drivers/dri/i965/brw_schedule_instructions.cpp b/src/mesa/drivers/dri/i965/brw_schedule_instructions.cpp index 5093dd59782..9e4de29150b 100644 --- a/src/mesa/drivers/dri/i965/brw_schedule_instructions.cpp +++ b/src/mesa/drivers/dri/i965/brw_schedule_instructions.cpp @@ -342,6 +342,18 @@ schedule_node::set_latency_gen7(bool is_haswell) latency = 200; break; + case SHADER_OPCODE_GEN7_SCRATCH_READ: + /* Testing a load from offset 0, that had been previously written: + * + * send(8) g114<1>UW g0<8,8,1>F data (0, 0, 0) mlen 1 rlen 1 { align1 WE_normal 1Q }; + * mov(8) null g114<8,8,1>F { align1 WE_normal 1Q }; + * + * The cycles spent seemed to be grouped around 40-50 (as low as 38), + * then around 140. Presumably this is cache hit vs miss. + */ + latency = 50; + break; + default: /* 2 cycles: * mul(8) g4<1>F g2<0,1,0>F 0.5F { align1 WE_normal 1Q }; diff --git a/src/mesa/drivers/dri/i965/brw_shader.cpp b/src/mesa/drivers/dri/i965/brw_shader.cpp index a35118336e4..b7b0a5b181d 100644 --- a/src/mesa/drivers/dri/i965/brw_shader.cpp +++ b/src/mesa/drivers/dri/i965/brw_shader.cpp @@ -458,6 +458,8 @@ brw_instruction_name(enum opcode op) return "gen4_scratch_read"; case SHADER_OPCODE_GEN4_SCRATCH_WRITE: return "gen4_scratch_write"; + case SHADER_OPCODE_GEN7_SCRATCH_READ: + return "gen7_scratch_read"; case FS_OPCODE_DDX: return "ddx"; -- 2.30.2