static void emit_pixel_xy(struct brw_compile *p, const struct brw_reg *dst, GLuint mask, const struct brw_reg *arg0) { struct brw_reg r1 = brw_vec1_grf(1, 0); struct brw_reg r1_uw = retype(r1, BRW_REGISTER_TYPE_UW); brw_set_compression_control(p, BRW_COMPRESSION_NONE); /* Calculate pixel centers by adding 1 or 0 to each of the * micro-tile coordinates passed in r1. */ if (mask & WRITEMASK_X) { brw_ADD(p, vec16(retype(dst[0], BRW_REGISTER_TYPE_UW)), stride(suboffset(r1_uw, 4), 2, 4, 0), brw_imm_v(0x10101010)); } if (mask & WRITEMASK_Y) { brw_ADD(p, vec16(retype(dst[1], BRW_REGISTER_TYPE_UW)), stride(suboffset(r1_uw,5), 2, 4, 0), brw_imm_v(0x11001100)); } brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); }
static void brw_wm_xy(struct brw_compile *p, int dw) { struct brw_reg r1 = brw_vec1_grf(1, 0); struct brw_reg r1_uw = __retype_uw(r1); struct brw_reg x_uw, y_uw; brw_set_compression_control(p, BRW_COMPRESSION_NONE); if (dw == 16) { x_uw = brw_uw16_grf(30, 0); y_uw = brw_uw16_grf(28, 0); } else { x_uw = brw_uw8_grf(30, 0); y_uw = brw_uw8_grf(28, 0); } brw_ADD(p, x_uw, __stride(__suboffset(r1_uw, 4), 2, 4, 0), brw_imm_v(0x10101010)); brw_ADD(p, y_uw, __stride(__suboffset(r1_uw, 5), 2, 4, 0), brw_imm_v(0x11001100)); brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); brw_ADD(p, brw_vec8_grf(X16, 0), vec8(x_uw), brw_negate(r1)); brw_ADD(p, brw_vec8_grf(Y16, 0), vec8(y_uw), brw_negate(__suboffset(r1, 1))); }
void emit_math1(struct brw_wm_compile *c, GLuint function, const struct brw_reg *dst, GLuint mask, const struct brw_reg *arg0) { struct brw_compile *p = &c->func; struct intel_context *intel = &p->brw->intel; int dst_chan = _mesa_ffs(mask & WRITEMASK_XYZW) - 1; GLuint saturate = ((mask & SATURATE) ? BRW_MATH_SATURATE_SATURATE : BRW_MATH_SATURATE_NONE); struct brw_reg src; if (!(mask & WRITEMASK_XYZW)) return; /* Do not emit dead code */ assert(is_power_of_two(mask & WRITEMASK_XYZW)); if (intel->gen >= 6 && ((arg0[0].hstride == BRW_HORIZONTAL_STRIDE_0 || arg0[0].file != BRW_GENERAL_REGISTER_FILE) || arg0[0].negate || arg0[0].abs)) { /* Gen6 math requires that source and dst horizontal stride be 1, * and that the argument be in the GRF. * * The hardware ignores source modifiers (negate and abs) on math * instructions, so we also move to a temp to set those up. */ src = dst[dst_chan]; brw_MOV(p, src, arg0[0]); } else { src = arg0[0]; } /* Send two messages to perform all 16 operations: */ brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_math(p, dst[dst_chan], function, saturate, 2, src, BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); if (c->dispatch_width == 16) { brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_math(p, offset(dst[dst_chan],1), function, saturate, 3, sechalf(src), BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); } brw_pop_insn_state(p); }
static void brw_fb_write(struct brw_compile *p, int dw) { struct brw_instruction *insn; unsigned msg_control, msg_type, msg_len; struct brw_reg src0; bool header; if (dw == 16) { brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE; msg_len = 8; } else { brw_set_compression_control(p, BRW_COMPRESSION_NONE); msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01; msg_len = 4; } if (p->gen < 060) { brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_mask_control(p, BRW_MASK_DISABLE); brw_MOV(p, brw_message_reg(1), brw_vec8_grf(1, 0)); brw_pop_insn_state(p); msg_len += 2; } /* The execution mask is ignored for render target writes. */ insn = brw_next_insn(p, BRW_OPCODE_SEND); insn->header.predicate_control = 0; insn->header.compression_control = BRW_COMPRESSION_NONE; if (p->gen >= 060) { msg_type = GEN6_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE; src0 = brw_message_reg(2); header = false; } else { insn->header.destreg__conditionalmod = 0; msg_type = BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE; src0 = __retype_uw(brw_vec8_grf(0, 0)); header = true; } brw_set_dest(p, insn, null_result(dw)); brw_set_src0(p, insn, src0); brw_set_dp_write_message(p, insn, 0, msg_control, msg_type, msg_len, header, true, 0, true, false); }
/* Kill pixel - set execution mask to zero for those pixels which * fail. */ static void emit_kil( struct brw_wm_compile *c, struct brw_reg *arg0) { struct brw_compile *p = &c->func; struct intel_context *intel = &p->brw->intel; struct brw_reg pixelmask; GLuint i, j; if (intel->gen >= 6) pixelmask = retype(brw_vec1_grf(1, 7), BRW_REGISTER_TYPE_UW); else pixelmask = retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_UW); for (i = 0; i < 4; i++) { /* Check if we've already done the comparison for this reg * -- common when someone does KIL TEMP.wwww. */ for (j = 0; j < i; j++) { if (memcmp(&arg0[j], &arg0[i], sizeof(arg0[0])) == 0) break; } if (j != i) continue; brw_push_insn_state(p); brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_GE, arg0[i], brw_imm_f(0)); brw_set_predicate_control_flag_value(p, 0xff); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_AND(p, pixelmask, brw_flag_reg(), pixelmask); brw_pop_insn_state(p); } }
static void fire_fb_write( struct brw_wm_compile *c, GLuint base_reg, GLuint nr, GLuint target, GLuint eot ) { struct brw_compile *p = &c->func; /* Pass through control information: */ /* mov (8) m1.0<1>:ud r1.0<8;8,1>:ud { Align1 NoMask } */ { brw_push_insn_state(p); brw_set_mask_control(p, BRW_MASK_DISABLE); /* ? */ brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(base_reg + 1), brw_vec8_grf(1, 0)); brw_pop_insn_state(p); } /* Send framebuffer write message: */ /* send (16) null.0<1>:uw m0 r0.0<8;8,1>:uw 0x85a04000:ud { Align1 EOT } */ brw_fb_WRITE(p, retype(vec16(brw_null_reg()), BRW_REGISTER_TYPE_UW), base_reg, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW), target, nr, 0, eot); }
void brw_init_compile(struct brw_context *brw, struct brw_compile *p, void *mem_ctx) { p->brw = brw; /* * Set the initial instruction store array size to 1024, if found that * isn't enough, then it will double the store size at brw_next_insn() * until out of memory. */ p->store_size = 1024; p->store = rzalloc_array(mem_ctx, struct brw_instruction, p->store_size); p->nr_insn = 0; p->current = p->stack; p->compressed = false; memset(p->current, 0, sizeof(p->current[0])); p->mem_ctx = mem_ctx; /* Some defaults? */ brw_set_mask_control(p, BRW_MASK_ENABLE); /* what does this do? */ brw_set_saturate(p, 0); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_predicate_control_flag_value(p, 0xff); /* Set up control flow stack */ p->if_stack_depth = 0; p->if_stack_array_size = 16; p->if_stack = rzalloc_array(mem_ctx, int, p->if_stack_array_size); p->loop_stack_depth = 0; p->loop_stack_array_size = 16; p->loop_stack = rzalloc_array(mem_ctx, int, p->loop_stack_array_size); p->if_depth_in_loop = rzalloc_array(mem_ctx, int, p->loop_stack_array_size); }
static void brw_wm_write(struct brw_compile *p, int dw, int src) { int n; if (dw == 8 && p->gen >= 060) { /* XXX pixel execution mask? */ brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(2), brw_vec8_grf(src+0, 0)); brw_MOV(p, brw_message_reg(3), brw_vec8_grf(src+1, 0)); brw_MOV(p, brw_message_reg(4), brw_vec8_grf(src+2, 0)); brw_MOV(p, brw_message_reg(5), brw_vec8_grf(src+3, 0)); goto done; } brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); for (n = 0; n < 4; n++) { if (p->gen >= 060) { brw_MOV(p, brw_message_reg(2 + 2*n), brw_vec8_grf(src + 2*n, 0)); } else if (p->gen >= 045 && dw == 16) { brw_MOV(p, brw_message_reg(2 + n + BRW_MRF_COMPR4), brw_vec8_grf(src + 2*n, 0)); } else { brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(2 + n), brw_vec8_grf(src + 2*n, 0)); if (dw == 16) { brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_MOV(p, brw_message_reg(2 + n + 4), brw_vec8_grf(src + 2*n+1, 0)); } } } done: brw_fb_write(p, dw); }
void brw_init_compile( struct brw_compile *p ) { p->nr_insn = 0; p->current = p->stack; memset(p->current, 0, sizeof(p->current[0])); /* Some defaults? */ brw_set_mask_control(p, BRW_MASK_ENABLE); /* what does this do? */ brw_set_saturate(p, 0); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_predicate_control_flag_value(p, 0xff); }
/** * Extended math function, float[16]. * Use 2 send instructions. */ void brw_math_16( struct brw_compile *p, struct brw_reg dest, GLuint function, GLuint saturate, GLuint msg_reg_nr, struct brw_reg src, GLuint precision ) { struct brw_instruction *insn; GLuint msg_length = (function == BRW_MATH_FUNCTION_POW) ? 2 : 1; GLuint response_length = (function == BRW_MATH_FUNCTION_SINCOS) ? 2 : 1; /* First instruction: */ brw_push_insn_state(p); brw_set_predicate_control_flag_value(p, 0xff); brw_set_compression_control(p, BRW_COMPRESSION_NONE); insn = next_insn(p, BRW_OPCODE_SEND); insn->header.destreg__conditionalmod = msg_reg_nr; brw_set_dest(insn, dest); brw_set_src0(insn, src); brw_set_math_message(p->brw, insn, msg_length, response_length, function, BRW_MATH_INTEGER_UNSIGNED, precision, saturate, BRW_MATH_DATA_VECTOR); /* Second instruction: */ insn = next_insn(p, BRW_OPCODE_SEND); insn->header.compression_control = BRW_COMPRESSION_2NDHALF; insn->header.destreg__conditionalmod = msg_reg_nr+1; brw_set_dest(insn, offset(dest,1)); brw_set_src0(insn, src); brw_set_math_message(p->brw, insn, msg_length, response_length, function, BRW_MATH_INTEGER_UNSIGNED, precision, saturate, BRW_MATH_DATA_VECTOR); brw_pop_insn_state(p); }
/** * Read a float[4] vector from the data port Data Cache (const buffer). * Location (in buffer) should be a multiple of 16. * Used for fetching shader constants. * If relAddr is true, we'll do an indirect fetch using the address register. */ void brw_dp_READ_4( struct brw_compile *p, struct brw_reg dest, GLboolean relAddr, GLuint location, GLuint bind_table_index ) { /* XXX: relAddr not implemented */ GLuint msg_reg_nr = 1; { struct brw_reg b; brw_push_insn_state(p); brw_set_predicate_control(p, BRW_PREDICATE_NONE); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_mask_control(p, BRW_MASK_DISABLE); /* Setup MRF[1] with location/offset into const buffer */ b = brw_message_reg(msg_reg_nr); b = retype(b, BRW_REGISTER_TYPE_UD); /* XXX I think we're setting all the dwords of MRF[1] to 'location'. * when the docs say only dword[2] should be set. Hmmm. But it works. */ brw_MOV(p, b, brw_imm_ud(location)); brw_pop_insn_state(p); } { struct brw_instruction *insn = next_insn(p, BRW_OPCODE_SEND); insn->header.predicate_control = BRW_PREDICATE_NONE; insn->header.compression_control = BRW_COMPRESSION_NONE; insn->header.destreg__conditionalmod = msg_reg_nr; insn->header.mask_control = BRW_MASK_DISABLE; /* cast dest to a uword[8] vector */ dest = retype(vec8(dest), BRW_REGISTER_TYPE_UW); brw_set_dest(insn, dest); brw_set_src0(insn, brw_null_reg()); brw_set_dp_read_message(p->brw, insn, bind_table_index, 0, /* msg_control (0 means 1 Oword) */ BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ, /* msg_type */ 0, /* source cache = data cache */ 1, /* msg_length */ 1, /* response_length (1 Oword) */ 0); /* eot */ } }
static void emit_aa( struct brw_wm_compile *c, struct brw_reg *arg1, GLuint reg ) { struct brw_compile *p = &c->func; GLuint comp = c->aa_dest_stencil_reg / 2; GLuint off = c->aa_dest_stencil_reg % 2; struct brw_reg aa = offset(arg1[comp], off); brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); /* ?? */ brw_MOV(p, brw_message_reg(reg), aa); brw_pop_insn_state(p); }
static void brw_wm_affine_st(struct brw_compile *p, int dw, int channel, int msg) { int uv; if (dw == 16) { brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); uv = p->gen >= 060 ? 6 : 3; } else { brw_set_compression_control(p, BRW_COMPRESSION_NONE); uv = p->gen >= 060 ? 4 : 3; } uv += 2*channel; msg++; if (p->gen >= 060) { brw_PLN(p, brw_message_reg(msg), brw_vec1_grf(uv, 0), brw_vec8_grf(2, 0)); msg += dw/8; brw_PLN(p, brw_message_reg(msg), brw_vec1_grf(uv, 4), brw_vec8_grf(2, 0)); } else { struct brw_reg r = brw_vec1_grf(uv, 0); brw_LINE(p, brw_null_reg(), __suboffset(r, 0), brw_vec8_grf(X16, 0)); brw_MAC(p, brw_message_reg(msg), __suboffset(r, 1), brw_vec8_grf(Y16, 0)); msg += dw/8; brw_LINE(p, brw_null_reg(), __suboffset(r, 4), brw_vec8_grf(X16, 0)); brw_MAC(p, brw_message_reg(msg), __suboffset(r, 5), brw_vec8_grf(Y16, 0)); } }
static void fire_fb_write( struct brw_wm_compile *c, GLuint base_reg, GLuint nr, GLuint target, GLuint eot ) { struct brw_compile *p = &c->func; struct intel_context *intel = &p->brw->intel; uint32_t msg_control; /* Pass through control information: * * Gen6 has done m1 mov in emit_fb_write() for current SIMD16 case. */ /* mov (8) m1.0<1>:ud r1.0<8;8,1>:ud { Align1 NoMask } */ if (intel->gen < 6) { brw_push_insn_state(p); brw_set_mask_control(p, BRW_MASK_DISABLE); /* ? */ brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(base_reg + 1), brw_vec8_grf(1, 0)); brw_pop_insn_state(p); } if (c->dispatch_width == 16) msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE; else msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01; /* Send framebuffer write message: */ /* send (16) null.0<1>:uw m0 r0.0<8;8,1>:uw 0x85a04000:ud { Align1 EOT } */ brw_fb_WRITE(p, c->dispatch_width, base_reg, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW), msg_control, target, nr, 0, eot, true); }
/* Kill pixel - set execution mask to zero for those pixels which * fail. */ static void emit_kil( struct brw_wm_compile *c, struct brw_reg *arg0) { struct brw_compile *p = &c->func; struct brw_reg r0uw = retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_UW); GLuint i; /* XXX - usually won't need 4 compares! */ for (i = 0; i < 4; i++) { brw_push_insn_state(p); brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_GE, arg0[i], brw_imm_f(0)); brw_set_predicate_control_flag_value(p, 0xff); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_AND(p, r0uw, brw_flag_reg(), r0uw); brw_pop_insn_state(p); } }
static void emit_math2( struct brw_compile *p, GLuint function, const struct brw_reg *dst, GLuint mask, const struct brw_reg *arg0, const struct brw_reg *arg1) { if (!(mask & WRITEMASK_XYZW)) return; /* Do not emit dead code*/ assert((mask & WRITEMASK_XYZW) == WRITEMASK_X); brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(2), arg0[0]); brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_MOV(p, brw_message_reg(4), sechalf(arg0[0])); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(3), arg1[0]); brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_MOV(p, brw_message_reg(5), sechalf(arg1[0])); /* Send two messages to perform all 16 operations: */ brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_math(p, dst[0], function, (mask & SATURATE) ? BRW_MATH_SATURATE_SATURATE : BRW_MATH_SATURATE_NONE, 2, brw_null_reg(), BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_math(p, offset(dst[0],1), function, (mask & SATURATE) ? BRW_MATH_SATURATE_SATURATE : BRW_MATH_SATURATE_NONE, 4, brw_null_reg(), BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); brw_pop_insn_state(p); }
static void wm_src_sample_argb(struct brw_compile *p) { static const uint32_t fragment[][4] = { #include "exa_wm_src_affine.g6b" #include "exa_wm_src_sample_argb.g6b" #include "exa_wm_write.g6b" }; int n; brw_push_insn_state(p); brw_set_mask_control(p, BRW_MASK_DISABLE); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, retype(brw_vec1_grf(0,2), BRW_REGISTER_TYPE_UD), brw_imm_ud(0)); brw_pop_insn_state(p); brw_SAMPLE(p, retype(vec16(brw_vec8_grf(14, 0)), BRW_REGISTER_TYPE_UW), 1, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UD), 1, 0, WRITEMASK_XYZW, GEN5_SAMPLER_MESSAGE_SAMPLE, 8, 5, true, BRW_SAMPLER_SIMD_MODE_SIMD16); for (n = 0; n < p->nr_insn; n++) { brw_disasm(stdout, &p->store[n], 60); } printf("\n\n"); for (n = 0; n < ARRAY_SIZE(fragment); n++) { brw_disasm(stdout, (const struct brw_instruction *)&fragment[n][0], 60); } }
/** * Write block of 16 dwords/floats to the data port Render Cache scratch buffer. * Scratch offset should be a multiple of 64. * Used for register spilling. */ void brw_dp_WRITE_16( struct brw_compile *p, struct brw_reg src, GLuint scratch_offset ) { GLuint msg_reg_nr = 1; { brw_push_insn_state(p); brw_set_mask_control(p, BRW_MASK_DISABLE); brw_set_compression_control(p, BRW_COMPRESSION_NONE); /* set message header global offset field (reg 0, element 2) */ brw_MOV(p, retype(brw_vec1_grf(0, 2), BRW_REGISTER_TYPE_D), brw_imm_d(scratch_offset)); brw_pop_insn_state(p); } { GLuint msg_length = 3; struct brw_reg dest = retype(brw_null_reg(), BRW_REGISTER_TYPE_UW); struct brw_instruction *insn = next_insn(p, BRW_OPCODE_SEND); insn->header.predicate_control = 0; /* XXX */ insn->header.compression_control = BRW_COMPRESSION_NONE; insn->header.destreg__conditionalmod = msg_reg_nr; brw_set_dest(insn, dest); brw_set_src0(insn, src); brw_set_dp_write_message(p->brw, insn, 255, /* binding table index (255=stateless) */ BRW_DATAPORT_OWORD_BLOCK_4_OWORDS, /* msg_control */ BRW_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE, /* msg_type */ msg_length, 0, /* pixel scoreboard */ 0, /* response_length */ 0); /* eot */ } }
/** * Read block of 16 dwords/floats from the data port Render Cache scratch buffer. * Scratch offset should be a multiple of 64. * Used for register spilling. */ void brw_dp_READ_16( struct brw_compile *p, struct brw_reg dest, GLuint scratch_offset ) { GLuint msg_reg_nr = 1; { brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_mask_control(p, BRW_MASK_DISABLE); /* set message header global offset field (reg 0, element 2) */ brw_MOV(p, retype(brw_vec1_grf(0, 2), BRW_REGISTER_TYPE_D), brw_imm_d(scratch_offset)); brw_pop_insn_state(p); } { struct brw_instruction *insn = next_insn(p, BRW_OPCODE_SEND); insn->header.predicate_control = 0; /* XXX */ insn->header.compression_control = BRW_COMPRESSION_NONE; insn->header.destreg__conditionalmod = msg_reg_nr; brw_set_dest(insn, dest); /* UW? */ brw_set_src0(insn, retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW)); brw_set_dp_read_message(p->brw, insn, 255, /* binding table index (255=stateless) */ 3, /* msg_control (3 means 4 Owords) */ BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ, /* msg_type */ 1, /* target cache (render/scratch) */ 1, /* msg_length */ 2, /* response_length */ 0); /* eot */ } }
/** * Computes the screen-space x,y position of the pixels. * * This will be used by emit_delta_xy() or emit_wpos_xy() for * interpolation of attributes.. * * Payload R0: * * R0.0 -- pixel mask, one bit for each of 4 pixels in 4 tiles, * corresponding to each of the 16 execution channels. * R0.1..8 -- ? * R1.0 -- triangle vertex 0.X * R1.1 -- triangle vertex 0.Y * R1.2 -- tile 0 x,y coords (2 packed uwords) * R1.3 -- tile 1 x,y coords (2 packed uwords) * R1.4 -- tile 2 x,y coords (2 packed uwords) * R1.5 -- tile 3 x,y coords (2 packed uwords) * R1.6 -- ? * R1.7 -- ? * R1.8 -- ? */ void emit_pixel_xy(struct brw_wm_compile *c, const struct brw_reg *dst, GLuint mask) { struct brw_compile *p = &c->func; struct brw_reg r1 = brw_vec1_grf(1, 0); struct brw_reg r1_uw = retype(r1, BRW_REGISTER_TYPE_UW); struct brw_reg dst0_uw, dst1_uw; brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); if (c->dispatch_width == 16) { dst0_uw = vec16(retype(dst[0], BRW_REGISTER_TYPE_UW)); dst1_uw = vec16(retype(dst[1], BRW_REGISTER_TYPE_UW)); } else { dst0_uw = vec8(retype(dst[0], BRW_REGISTER_TYPE_UW)); dst1_uw = vec8(retype(dst[1], BRW_REGISTER_TYPE_UW)); } /* Calculate pixel centers by adding 1 or 0 to each of the * micro-tile coordinates passed in r1. */ if (mask & WRITEMASK_X) { brw_ADD(p, dst0_uw, stride(suboffset(r1_uw, 4), 2, 4, 0), brw_imm_v(0x10101010)); } if (mask & WRITEMASK_Y) { brw_ADD(p, dst1_uw, stride(suboffset(r1_uw,5), 2, 4, 0), brw_imm_v(0x11001100)); } brw_pop_insn_state(p); }
void brw_compile_init(struct brw_compile *p, int gen, void *store) { assert(gen); p->gen = gen; p->store = store; p->nr_insn = 0; p->current = p->stack; p->compressed = false; memset(p->current, 0, sizeof(p->current[0])); /* Some defaults? */ brw_set_mask_control(p, BRW_MASK_ENABLE); /* what does this do? */ brw_set_saturate(p, 0); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_predicate_control_flag_value(p, 0xff); p->if_stack_depth = 0; p->if_stack_array_size = 0; p->if_stack = NULL; }
/* Post-fragment-program processing. Send the results to the * framebuffer. */ static void emit_fb_write( struct brw_wm_compile *c, struct brw_reg *arg0, struct brw_reg *arg1, struct brw_reg *arg2, GLuint target, GLuint eot) { struct brw_compile *p = &c->func; GLuint nr = 2; GLuint channel; /* Reserve a space for AA - may not be needed: */ if (c->key.aa_dest_stencil_reg) nr += 1; /* I don't really understand how this achieves the color interleave * (ie RGBARGBA) in the result: [Do the saturation here] */ { brw_push_insn_state(p); for (channel = 0; channel < 4; channel++) { /* mov (8) m2.0<1>:ud r28.0<8;8,1>:ud { Align1 } */ /* mov (8) m6.0<1>:ud r29.0<8;8,1>:ud { Align1 SecHalf } */ brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(nr + channel), arg0[channel]); brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_MOV(p, brw_message_reg(nr + channel + 4), sechalf(arg0[channel])); } /* skip over the regs populated above: */ nr += 8; brw_pop_insn_state(p); } if (c->key.source_depth_to_render_target) { if (c->key.computes_depth) brw_MOV(p, brw_message_reg(nr), arg2[2]); else brw_MOV(p, brw_message_reg(nr), arg1[1]); /* ? */ nr += 2; } if (c->key.dest_depth_reg) { GLuint comp = c->key.dest_depth_reg / 2; GLuint off = c->key.dest_depth_reg % 2; if (off != 0) { brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(nr), offset(arg1[comp],1)); /* 2nd half? */ brw_MOV(p, brw_message_reg(nr+1), arg1[comp+1]); brw_pop_insn_state(p); } else { brw_MOV(p, brw_message_reg(nr), arg1[comp]); } nr += 2; } if (!c->key.runtime_check_aads_emit) { if (c->key.aa_dest_stencil_reg) emit_aa(c, arg1, 2); fire_fb_write(c, 0, nr, target, eot); } else { struct brw_reg v1_null_ud = vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_UD)); struct brw_reg ip = brw_ip_reg(); struct brw_instruction *jmp; brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_conditionalmod(p, BRW_CONDITIONAL_Z); brw_AND(p, v1_null_ud, get_element_ud(brw_vec8_grf(1,0), 6), brw_imm_ud(1<<26)); jmp = brw_JMPI(p, ip, ip, brw_imm_w(0)); { emit_aa(c, arg1, 2); fire_fb_write(c, 0, nr, target, eot); /* note - thread killed in subroutine */ } brw_land_fwd_jump(p, jmp); /* ELSE: Shuffle up one register to fill in the hole left for AA: */ fire_fb_write(c, 1, nr-1, target, eot); } }
void emit_math2(struct brw_wm_compile *c, GLuint function, const struct brw_reg *dst, GLuint mask, const struct brw_reg *arg0, const struct brw_reg *arg1) { struct brw_compile *p = &c->func; struct intel_context *intel = &p->brw->intel; int dst_chan = _mesa_ffs(mask & WRITEMASK_XYZW) - 1; if (!(mask & WRITEMASK_XYZW)) return; /* Do not emit dead code */ assert(is_power_of_two(mask & WRITEMASK_XYZW)); brw_push_insn_state(p); /* math can only operate on up to a vec8 at a time, so in * dispatch_width==16 we have to do the second half manually. */ if (intel->gen >= 6) { struct brw_reg src0 = arg0[0]; struct brw_reg src1 = arg1[0]; struct brw_reg temp_dst = dst[dst_chan]; if (arg0[0].hstride == BRW_HORIZONTAL_STRIDE_0) { brw_MOV(p, temp_dst, src0); src0 = temp_dst; } if (arg1[0].hstride == BRW_HORIZONTAL_STRIDE_0) { /* This is a heinous hack to get a temporary register for use * in case both arg0 and arg1 are constants. Why you're * doing exponentiation on constant values in the shader, we * don't know. * * max_wm_grf is almost surely less than the maximum GRF, and * gen6 doesn't care about the number of GRFs used in a * shader like pre-gen6 did. */ struct brw_reg temp = brw_vec8_grf(c->max_wm_grf, 0); brw_MOV(p, temp, src1); src1 = temp; } brw_set_saturate(p, (mask & SATURATE) ? 1 : 0); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_math2(p, temp_dst, function, src0, src1); if (c->dispatch_width == 16) { brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_math2(p, sechalf(temp_dst), function, sechalf(src0), sechalf(src1)); } } else { GLuint saturate = ((mask & SATURATE) ? BRW_MATH_SATURATE_SATURATE : BRW_MATH_SATURATE_NONE); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(3), arg1[0]); if (c->dispatch_width == 16) { brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_MOV(p, brw_message_reg(5), sechalf(arg1[0])); } brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_math(p, dst[dst_chan], function, saturate, 2, arg0[0], BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); /* Send two messages to perform all 16 operations: */ if (c->dispatch_width == 16) { brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_math(p, offset(dst[dst_chan],1), function, saturate, 4, sechalf(arg0[0]), BRW_MATH_DATA_VECTOR, BRW_MATH_PRECISION_FULL); } } brw_pop_insn_state(p); }
/* Emit the fragment program instructions here. */ void brw_wm_emit( struct brw_wm_compile *c ) { struct brw_compile *p = &c->func; struct intel_context *intel = &p->brw->intel; GLuint insn; brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); if (intel->gen >= 6) brw_set_acc_write_control(p, 1); /* Check if any of the payload regs need to be spilled: */ spill_values(c, c->payload.depth, 4); spill_values(c, c->creg, c->nr_creg); spill_values(c, c->payload.input_interp, FRAG_ATTRIB_MAX); for (insn = 0; insn < c->nr_insns; insn++) { struct brw_wm_instruction *inst = &c->instruction[insn]; struct brw_reg args[3][4], dst[4]; GLuint i, dst_flags; /* Get argument regs: */ for (i = 0; i < 3; i++) get_argument_regs(c, inst->src[i], args[i]); /* Get dest regs: */ for (i = 0; i < 4; i++) if (inst->dst[i]) dst[i] = inst->dst[i]->hw_reg; else dst[i] = brw_null_reg(); /* Flags */ dst_flags = inst->writemask; if (inst->saturate) dst_flags |= SATURATE; switch (inst->opcode) { /* Generated instructions for calculating triangle interpolants: */ case WM_PIXELXY: emit_pixel_xy(c, dst, dst_flags); break; case WM_DELTAXY: emit_delta_xy(p, dst, dst_flags, args[0]); break; case WM_WPOSXY: emit_wpos_xy(c, dst, dst_flags, args[0]); break; case WM_PIXELW: emit_pixel_w(c, dst, dst_flags, args[0], args[1]); break; case WM_LINTERP: emit_linterp(p, dst, dst_flags, args[0], args[1]); break; case WM_PINTERP: emit_pinterp(p, dst, dst_flags, args[0], args[1], args[2]); break; case WM_CINTERP: emit_cinterp(p, dst, dst_flags, args[0]); break; case WM_FB_WRITE: emit_fb_write(c, args[0], args[1], args[2], inst->target, inst->eot); break; case WM_FRONTFACING: emit_frontfacing(p, dst, dst_flags); break; /* Straightforward arithmetic: */ case OPCODE_ADD: emit_alu2(p, brw_ADD, dst, dst_flags, args[0], args[1]); break; case OPCODE_FRC: emit_alu1(p, brw_FRC, dst, dst_flags, args[0]); break; case OPCODE_FLR: emit_alu1(p, brw_RNDD, dst, dst_flags, args[0]); break; case OPCODE_DDX: emit_ddxy(p, dst, dst_flags, true, args[0]); break; case OPCODE_DDY: emit_ddxy(p, dst, dst_flags, false, args[0]); break; case OPCODE_DP2: emit_dp2(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_DP3: emit_dp3(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_DP4: emit_dp4(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_DPH: emit_dph(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_TRUNC: for (i = 0; i < 4; i++) { if (dst_flags & (1<<i)) { brw_RNDZ(p, dst[i], args[0][i]); } } break; case OPCODE_LRP: emit_lrp(p, dst, dst_flags, args[0], args[1], args[2]); break; case OPCODE_MAD: emit_mad(p, dst, dst_flags, args[0], args[1], args[2]); break; case OPCODE_MOV: case OPCODE_SWZ: emit_alu1(p, brw_MOV, dst, dst_flags, args[0]); break; case OPCODE_MUL: emit_alu2(p, brw_MUL, dst, dst_flags, args[0], args[1]); break; case OPCODE_XPD: emit_xpd(p, dst, dst_flags, args[0], args[1]); break; /* Higher math functions: */ case OPCODE_RCP: emit_math1(c, BRW_MATH_FUNCTION_INV, dst, dst_flags, args[0]); break; case OPCODE_RSQ: emit_math1(c, BRW_MATH_FUNCTION_RSQ, dst, dst_flags, args[0]); break; case OPCODE_SIN: emit_math1(c, BRW_MATH_FUNCTION_SIN, dst, dst_flags, args[0]); break; case OPCODE_COS: emit_math1(c, BRW_MATH_FUNCTION_COS, dst, dst_flags, args[0]); break; case OPCODE_EX2: emit_math1(c, BRW_MATH_FUNCTION_EXP, dst, dst_flags, args[0]); break; case OPCODE_LG2: emit_math1(c, BRW_MATH_FUNCTION_LOG, dst, dst_flags, args[0]); break; case OPCODE_SCS: /* There is an scs math function, but it would need some * fixup for 16-element execution. */ if (dst_flags & WRITEMASK_X) emit_math1(c, BRW_MATH_FUNCTION_COS, dst, (dst_flags&SATURATE)|WRITEMASK_X, args[0]); if (dst_flags & WRITEMASK_Y) emit_math1(c, BRW_MATH_FUNCTION_SIN, dst+1, (dst_flags&SATURATE)|WRITEMASK_X, args[0]); break; case OPCODE_POW: emit_math2(c, BRW_MATH_FUNCTION_POW, dst, dst_flags, args[0], args[1]); break; /* Comparisons: */ case OPCODE_CMP: emit_cmp(p, dst, dst_flags, args[0], args[1], args[2]); break; case OPCODE_MAX: emit_max(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_MIN: emit_min(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SLT: emit_slt(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SLE: emit_sle(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SGT: emit_sgt(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SGE: emit_sge(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SEQ: emit_seq(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SNE: emit_sne(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SSG: emit_sign(p, dst, dst_flags, args[0]); break; case OPCODE_LIT: emit_lit(c, dst, dst_flags, args[0]); break; /* Texturing operations: */ case OPCODE_TEX: emit_tex(c, dst, dst_flags, args[0], c->payload.depth[0].hw_reg, inst->tex_idx, inst->tex_unit, inst->tex_shadow); break; case OPCODE_TXB: emit_txb(c, dst, dst_flags, args[0], c->payload.depth[0].hw_reg, inst->tex_idx, inst->tex_unit); break; case OPCODE_KIL: emit_kil(c, args[0]); break; default: printf("Unsupported opcode %i (%s) in fragment shader\n", inst->opcode, inst->opcode < MAX_OPCODE ? _mesa_opcode_string(inst->opcode) : "unknown"); } for (i = 0; i < 4; i++) if (inst->dst[i] && inst->dst[i]->spill_slot) emit_spill(c, inst->dst[i]->hw_reg, inst->dst[i]->spill_slot); } /* Only properly tested on ILK */ if (p->brw->intel.gen == 5) { brw_remove_duplicate_mrf_moves(p); if (c->dispatch_width == 16) brw_remove_grf_to_mrf_moves(p); } if (unlikely(INTEL_DEBUG & DEBUG_WM)) { int i; printf("wm-native:\n"); for (i = 0; i < p->nr_insn; i++) brw_disasm(stdout, &p->store[i], p->brw->intel.gen); printf("\n"); } }
/* Post-fragment-program processing. Send the results to the * framebuffer. * \param arg0 the fragment color * \param arg1 the pass-through depth value * \param arg2 the shader-computed depth value */ void emit_fb_write(struct brw_wm_compile *c, struct brw_reg *arg0, struct brw_reg *arg1, struct brw_reg *arg2, GLuint target, GLuint eot) { struct brw_compile *p = &c->func; struct brw_context *brw = p->brw; struct intel_context *intel = &brw->intel; GLuint nr = 2; GLuint channel; /* Reserve a space for AA - may not be needed: */ if (c->aa_dest_stencil_reg) nr += 1; /* I don't really understand how this achieves the color interleave * (ie RGBARGBA) in the result: [Do the saturation here] */ brw_push_insn_state(p); if (c->key.clamp_fragment_color) brw_set_saturate(p, 1); for (channel = 0; channel < 4; channel++) { if (intel->gen >= 6) { /* gen6 SIMD16 single source DP write looks like: * m + 0: r0 * m + 1: r1 * m + 2: g0 * m + 3: g1 * m + 4: b0 * m + 5: b1 * m + 6: a0 * m + 7: a1 */ if (c->dispatch_width == 16) { brw_MOV(p, brw_message_reg(nr + channel * 2), arg0[channel]); } else { brw_MOV(p, brw_message_reg(nr + channel), arg0[channel]); } } else if (c->dispatch_width == 16 && brw->has_compr4) { /* pre-gen6 SIMD16 single source DP write looks like: * m + 0: r0 * m + 1: g0 * m + 2: b0 * m + 3: a0 * m + 4: r1 * m + 5: g1 * m + 6: b1 * m + 7: a1 * * By setting the high bit of the MRF register number, we indicate * that we want COMPR4 mode - instead of doing the usual destination * + 1 for the second half we get destination + 4. */ brw_MOV(p, brw_message_reg(nr + channel + BRW_MRF_COMPR4), arg0[channel]); } else { /* mov (8) m2.0<1>:ud r28.0<8;8,1>:ud { Align1 } */ /* mov (8) m6.0<1>:ud r29.0<8;8,1>:ud { Align1 SecHalf } */ brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(nr + channel), arg0[channel]); if (c->dispatch_width == 16) { brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF); brw_MOV(p, brw_message_reg(nr + channel + 4), sechalf(arg0[channel])); } } } brw_set_saturate(p, 0); /* skip over the regs populated above: */ if (c->dispatch_width == 16) nr += 8; else nr += 4; brw_pop_insn_state(p); if (c->source_depth_to_render_target) { if (c->computes_depth) brw_MOV(p, brw_message_reg(nr), arg2[2]); else brw_MOV(p, brw_message_reg(nr), arg1[1]); /* ? */ nr += 2; } if (c->dest_depth_reg) { GLuint comp = c->dest_depth_reg / 2; GLuint off = c->dest_depth_reg % 2; if (off != 0) { brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, brw_message_reg(nr), offset(arg1[comp],1)); /* 2nd half? */ brw_MOV(p, brw_message_reg(nr+1), arg1[comp+1]); brw_pop_insn_state(p); } else { brw_MOV(p, brw_message_reg(nr), arg1[comp]); } nr += 2; } if (intel->gen >= 6) { /* Load the message header. There's no implied move from src0 * to the base mrf on gen6. */ brw_push_insn_state(p); brw_set_mask_control(p, BRW_MASK_DISABLE); brw_MOV(p, retype(brw_message_reg(0), BRW_REGISTER_TYPE_UD), retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UD)); brw_pop_insn_state(p); if (target != 0) { brw_MOV(p, retype(brw_vec1_reg(BRW_MESSAGE_REGISTER_FILE, 0, 2), BRW_REGISTER_TYPE_UD), brw_imm_ud(target)); } } if (!c->runtime_check_aads_emit) { if (c->aa_dest_stencil_reg) emit_aa(c, arg1, 2); fire_fb_write(c, 0, nr, target, eot); } else { struct brw_reg v1_null_ud = vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_UD)); struct brw_reg ip = brw_ip_reg(); struct brw_instruction *jmp; brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_conditionalmod(p, BRW_CONDITIONAL_Z); brw_AND(p, v1_null_ud, get_element_ud(brw_vec8_grf(1,0), 6), brw_imm_ud(1<<26)); jmp = brw_JMPI(p, ip, ip, brw_imm_w(0)); { emit_aa(c, arg1, 2); fire_fb_write(c, 0, nr, target, eot); /* note - thread killed in subroutine */ } brw_land_fwd_jump(p, jmp); /* ELSE: Shuffle up one register to fill in the hole left for AA: */ fire_fb_write(c, 1, nr-1, target, eot); } }
/** * Read float[4] constant(s) from VS constant buffer. * For relative addressing, two float[4] constants will be read into 'dest'. * Otherwise, one float[4] constant will be read into the lower half of 'dest'. */ void brw_dp_READ_4_vs(struct brw_compile *p, struct brw_reg dest, GLuint oword, GLboolean relAddr, struct brw_reg addrReg, GLuint location, GLuint bind_table_index) { GLuint msg_reg_nr = 1; assert(oword < 2); /* printf("vs const read msg, location %u, msg_reg_nr %d\n", location, msg_reg_nr); */ /* Setup MRF[1] with location/offset into const buffer */ { struct brw_reg b; brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_mask_control(p, BRW_MASK_DISABLE); brw_set_predicate_control(p, BRW_PREDICATE_NONE); /*brw_set_access_mode(p, BRW_ALIGN_16);*/ /* XXX I think we're setting all the dwords of MRF[1] to 'location'. * when the docs say only dword[2] should be set. Hmmm. But it works. */ b = brw_message_reg(msg_reg_nr); b = retype(b, BRW_REGISTER_TYPE_UD); /*b = get_element_ud(b, 2);*/ if (relAddr) { brw_ADD(p, b, addrReg, brw_imm_ud(location)); } else { brw_MOV(p, b, brw_imm_ud(location)); } brw_pop_insn_state(p); } { struct brw_instruction *insn = next_insn(p, BRW_OPCODE_SEND); insn->header.predicate_control = BRW_PREDICATE_NONE; insn->header.compression_control = BRW_COMPRESSION_NONE; insn->header.destreg__conditionalmod = msg_reg_nr; insn->header.mask_control = BRW_MASK_DISABLE; /*insn->header.access_mode = BRW_ALIGN_16;*/ brw_set_dest(insn, dest); brw_set_src0(insn, brw_null_reg()); brw_set_dp_read_message(p->brw, insn, bind_table_index, oword, /* 0 = lower Oword, 1 = upper Oword */ BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ, /* msg_type */ 0, /* source cache = data cache */ 1, /* msg_length */ 1, /* response_length (1 Oword) */ 0); /* eot */ } }
const GLuint * brw_blorp_const_color_program::compile(struct brw_context *brw, GLuint *program_size) { /* Set up prog_data */ memset(&prog_data, 0, sizeof(prog_data)); prog_data.persample_msaa_dispatch = false; alloc_regs(); brw_set_compression_control(&func, BRW_COMPRESSION_NONE); struct brw_reg mrf_rt_write = retype(vec16(brw_message_reg(base_mrf)), BRW_REGISTER_TYPE_F); uint32_t mlen, msg_type; if (key->use_simd16_replicated_data) { /* The message payload is a single register with the low 4 floats/ints * filled with the constant clear color. */ brw_set_mask_control(&func, BRW_MASK_DISABLE); brw_MOV(&func, vec4(brw_message_reg(base_mrf)), clear_rgba); brw_set_mask_control(&func, BRW_MASK_ENABLE); msg_type = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED; mlen = 1; } else { for (int i = 0; i < 4; i++) { /* The message payload is pairs of registers for 16 pixels each of r, * g, b, and a. */ brw_set_compression_control(&func, BRW_COMPRESSION_COMPRESSED); brw_MOV(&func, brw_message_reg(base_mrf + i * 2), brw_vec1_grf(clear_rgba.nr, i)); brw_set_compression_control(&func, BRW_COMPRESSION_NONE); } msg_type = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE; mlen = 8; } /* Now write to the render target and terminate the thread */ brw_fb_WRITE(&func, 16 /* dispatch_width */, base_mrf /* msg_reg_nr */, mrf_rt_write /* src0 */, msg_type, BRW_BLORP_RENDERBUFFER_BINDING_TABLE_INDEX, mlen, 0 /* response_length */, true /* eot */, false /* header present */); if (unlikely(INTEL_DEBUG & DEBUG_BLORP)) { fprintf(stderr, "Native code for BLORP clear:\n"); brw_dump_compile(&func, stderr, 0, func.next_insn_offset); fprintf(stderr, "\n"); } return brw_get_program(&func, program_size); }
/** * Texture sample instruction. * Note: the msg_type plus msg_length values determine exactly what kind * of sampling operation is performed. See volume 4, page 161 of docs. */ void brw_SAMPLE(struct brw_compile *p, struct brw_reg dest, GLuint msg_reg_nr, struct brw_reg src0, GLuint binding_table_index, GLuint sampler, GLuint writemask, GLuint msg_type, GLuint response_length, GLuint msg_length, GLboolean eot, GLuint header_present, GLuint simd_mode) { GLboolean need_stall = 0; if (writemask == 0) { /*_mesa_printf("%s: zero writemask??\n", __FUNCTION__); */ return; } /* Hardware doesn't do destination dependency checking on send * instructions properly. Add a workaround which generates the * dependency by other means. In practice it seems like this bug * only crops up for texture samples, and only where registers are * written by the send and then written again later without being * read in between. Luckily for us, we already track that * information and use it to modify the writemask for the * instruction, so that is a guide for whether a workaround is * needed. */ if (writemask != WRITEMASK_XYZW) { GLuint dst_offset = 0; GLuint i, newmask = 0, len = 0; for (i = 0; i < 4; i++) { if (writemask & (1<<i)) break; dst_offset += 2; } for (; i < 4; i++) { if (!(writemask & (1<<i))) break; newmask |= 1<<i; len++; } if (newmask != writemask) { need_stall = 1; /* _mesa_printf("need stall %x %x\n", newmask , writemask); */ } else { struct brw_reg m1 = brw_message_reg(msg_reg_nr); newmask = ~newmask & WRITEMASK_XYZW; brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_set_mask_control(p, BRW_MASK_DISABLE); brw_MOV(p, m1, brw_vec8_grf(0,0)); brw_MOV(p, get_element_ud(m1, 2), brw_imm_ud(newmask << 12)); brw_pop_insn_state(p); src0 = retype(brw_null_reg(), BRW_REGISTER_TYPE_UW); dest = offset(dest, dst_offset); response_length = len * 2; } } { struct brw_instruction *insn = next_insn(p, BRW_OPCODE_SEND); insn->header.predicate_control = 0; /* XXX */ insn->header.compression_control = BRW_COMPRESSION_NONE; insn->header.destreg__conditionalmod = msg_reg_nr; brw_set_dest(insn, dest); brw_set_src0(insn, src0); brw_set_sampler_message(p->brw, insn, binding_table_index, sampler, msg_type, response_length, msg_length, eot, header_present, simd_mode); } if (need_stall) { struct brw_reg reg = vec8(offset(dest, response_length-1)); /* mov (8) r9.0<1>:f r9.0<8;8,1>:f { Align1 } */ brw_push_insn_state(p); brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_MOV(p, reg, reg); brw_pop_insn_state(p); } }
static void brw_wm_projective_st(struct brw_compile *p, int dw, int channel, int msg) { int uv; if (dw == 16) { brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); uv = p->gen >= 060 ? 6 : 3; } else { brw_set_compression_control(p, BRW_COMPRESSION_NONE); uv = p->gen >= 060 ? 4 : 3; } uv += 2*channel; msg++; if (p->gen >= 060) { /* First compute 1/z */ brw_PLN(p, brw_vec8_grf(30, 0), brw_vec1_grf(uv+1, 0), brw_vec8_grf(2, 0)); if (dw == 16) { brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_math_invert(p, brw_vec8_grf(30, 0), brw_vec8_grf(30, 0)); brw_math_invert(p, brw_vec8_grf(31, 0), brw_vec8_grf(31, 0)); brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); } else brw_math_invert(p, brw_vec8_grf(30, 0), brw_vec8_grf(30, 0)); brw_PLN(p, brw_vec8_grf(26, 0), brw_vec1_grf(uv, 0), brw_vec8_grf(2, 0)); brw_PLN(p, brw_vec8_grf(28, 0), brw_vec1_grf(uv, 4), brw_vec8_grf(2, 0)); brw_MUL(p, brw_message_reg(msg), brw_vec8_grf(26, 0), brw_vec8_grf(30, 0)); brw_MUL(p, brw_message_reg(msg + dw/8), brw_vec8_grf(28, 0), brw_vec8_grf(30, 0)); } else { struct brw_reg r = brw_vec1_grf(uv, 0); /* First compute 1/z */ brw_LINE(p, brw_null_reg(), brw_vec1_grf(uv+1, 0), brw_vec8_grf(X16, 0)); brw_MAC(p, brw_vec8_grf(30, 0), brw_vec1_grf(uv+1, 1), brw_vec8_grf(Y16, 0)); if (dw == 16) { brw_set_compression_control(p, BRW_COMPRESSION_NONE); brw_math_invert(p, brw_vec8_grf(30, 0), brw_vec8_grf(30, 0)); brw_math_invert(p, brw_vec8_grf(31, 0), brw_vec8_grf(31, 0)); brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); } else brw_math_invert(p, brw_vec8_grf(30, 0), brw_vec8_grf(30, 0)); /* Now compute the output s,t values */ brw_LINE(p, brw_null_reg(), __suboffset(r, 0), brw_vec8_grf(X16, 0)); brw_MAC(p, brw_vec8_grf(28, 0), __suboffset(r, 1), brw_vec8_grf(Y16, 0)); brw_MUL(p, brw_message_reg(msg), brw_vec8_grf(28, 0), brw_vec8_grf(30, 0)); msg += dw/8; brw_LINE(p, brw_null_reg(), __suboffset(r, 4), brw_vec8_grf(X16, 0)); brw_MAC(p, brw_vec8_grf(28, 0), __suboffset(r, 5), brw_vec8_grf(Y16, 0)); brw_MUL(p, brw_message_reg(msg), brw_vec8_grf(28, 0), brw_vec8_grf(30, 0)); } }
/* Emit the fragment program instructions here. */ void brw_wm_emit( struct brw_wm_compile *c ) { struct brw_compile *p = &c->func; GLuint insn; brw_set_compression_control(p, BRW_COMPRESSION_COMPRESSED); /* Check if any of the payload regs need to be spilled: */ spill_values(c, c->payload.depth, 4); spill_values(c, c->creg, c->nr_creg); spill_values(c, c->payload.input_interp, FRAG_ATTRIB_MAX); for (insn = 0; insn < c->nr_insns; insn++) { struct brw_wm_instruction *inst = &c->instruction[insn]; struct brw_reg args[3][4], dst[4]; GLuint i, dst_flags; /* Get argument regs: */ for (i = 0; i < 3; i++) get_argument_regs(c, inst->src[i], args[i]); /* Get dest regs: */ for (i = 0; i < 4; i++) if (inst->dst[i]) dst[i] = inst->dst[i]->hw_reg; else dst[i] = brw_null_reg(); /* Flags */ dst_flags = inst->writemask; if (inst->saturate) dst_flags |= SATURATE; switch (inst->opcode) { /* Generated instructions for calculating triangle interpolants: */ case WM_PIXELXY: emit_pixel_xy(p, dst, dst_flags, args[0]); break; case WM_DELTAXY: emit_delta_xy(p, dst, dst_flags, args[0], args[1]); break; case WM_WPOSXY: emit_wpos_xy(c, dst, dst_flags, args[0]); break; case WM_PIXELW: emit_pixel_w(p, dst, dst_flags, args[0], args[1]); break; case WM_LINTERP: emit_linterp(p, dst, dst_flags, args[0], args[1]); break; case WM_PINTERP: emit_pinterp(p, dst, dst_flags, args[0], args[1], args[2]); break; case WM_CINTERP: emit_cinterp(p, dst, dst_flags, args[0]); break; case WM_FB_WRITE: emit_fb_write(c, args[0], args[1], args[2], inst->target, inst->eot); break; /* Straightforward arithmetic: */ case OPCODE_ADD: emit_alu2(p, brw_ADD, dst, dst_flags, args[0], args[1]); break; case OPCODE_FRC: emit_alu1(p, brw_FRC, dst, dst_flags, args[0]); break; case OPCODE_FLR: emit_alu1(p, brw_RNDD, dst, dst_flags, args[0]); break; case OPCODE_DP3: /* */ emit_dp3(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_DP4: emit_dp4(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_DPH: emit_dph(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_LRP: /* */ emit_lrp(p, dst, dst_flags, args[0], args[1], args[2]); break; case OPCODE_MAD: emit_mad(p, dst, dst_flags, args[0], args[1], args[2]); break; case OPCODE_MOV: case OPCODE_SWZ: emit_alu1(p, brw_MOV, dst, dst_flags, args[0]); break; case OPCODE_MUL: emit_alu2(p, brw_MUL, dst, dst_flags, args[0], args[1]); break; case OPCODE_XPD: emit_xpd(p, dst, dst_flags, args[0], args[1]); break; /* Higher math functions: */ case OPCODE_RCP: emit_math1(p, BRW_MATH_FUNCTION_INV, dst, dst_flags, args[0]); break; case OPCODE_RSQ: emit_math1(p, BRW_MATH_FUNCTION_RSQ, dst, dst_flags, args[0]); break; case OPCODE_SIN: emit_math1(p, BRW_MATH_FUNCTION_SIN, dst, dst_flags, args[0]); break; case OPCODE_COS: emit_math1(p, BRW_MATH_FUNCTION_COS, dst, dst_flags, args[0]); break; case OPCODE_EX2: emit_math1(p, BRW_MATH_FUNCTION_EXP, dst, dst_flags, args[0]); break; case OPCODE_LG2: emit_math1(p, BRW_MATH_FUNCTION_LOG, dst, dst_flags, args[0]); break; case OPCODE_SCS: /* There is an scs math function, but it would need some * fixup for 16-element execution. */ if (dst_flags & WRITEMASK_X) emit_math1(p, BRW_MATH_FUNCTION_COS, dst, (dst_flags&SATURATE)|WRITEMASK_X, args[0]); if (dst_flags & WRITEMASK_Y) emit_math1(p, BRW_MATH_FUNCTION_SIN, dst+1, (dst_flags&SATURATE)|WRITEMASK_X, args[0]); break; case OPCODE_POW: emit_math2(p, BRW_MATH_FUNCTION_POW, dst, dst_flags, args[0], args[1]); break; /* Comparisons: */ case OPCODE_CMP: emit_cmp(p, dst, dst_flags, args[0], args[1], args[2]); break; case OPCODE_MAX: emit_max(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_MIN: emit_min(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SLT: emit_slt(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SLE: emit_sle(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SGT: emit_sgt(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SGE: emit_sge(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SEQ: emit_seq(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_SNE: emit_sne(p, dst, dst_flags, args[0], args[1]); break; case OPCODE_LIT: emit_lit(p, dst, dst_flags, args[0]); break; /* Texturing operations: */ case OPCODE_TEX: emit_tex(c, inst, dst, dst_flags, args[0]); break; case OPCODE_TXB: emit_txb(c, inst, dst, dst_flags, args[0]); break; case OPCODE_KIL: emit_kil(c, args[0]); break; default: _mesa_printf("unsupport opcode %d in fragment program\n", inst->opcode); } for (i = 0; i < 4; i++) if (inst->dst[i] && inst->dst[i]->spill_slot) emit_spill(c, inst->dst[i]->hw_reg, inst->dst[i]->spill_slot); } }