From e04bdeae82797dbdcf6f544a997a4626fdfd4aee Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Fri, 21 Oct 2011 17:20:32 -0700 Subject: [PATCH] i965/gen6+: Parameterize barycentric interpolation modes. This patch modifies the fragment shader back-end so that instead of using a single delta_x/delta_y register pair to store barycentric coordinates, it uses an array of such register pairs, one for each possible intepolation mode. When setting up the WM, we intstruct it to only provide the barycentric coordinates that are actually needed by the fragment shader--that is computed by brw_compute_barycentric_interp_modes(). Currently this function returns just BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC, because this is the only interpolation mode we support. However, that will change in a later patch. Reviewed-by: Eric Anholt --- src/mesa/drivers/dri/i965/brw_context.h | 5 +++ src/mesa/drivers/dri/i965/brw_defines.h | 18 ++++++---- src/mesa/drivers/dri/i965/brw_fs.cpp | 25 ++++++++++---- src/mesa/drivers/dri/i965/brw_fs.h | 4 +-- src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp | 11 +++++- src/mesa/drivers/dri/i965/brw_fs_visitor.cpp | 29 ++++++++++------ src/mesa/drivers/dri/i965/brw_wm.c | 42 +++++++++++++++++------ src/mesa/drivers/dri/i965/brw_wm.h | 1 + src/mesa/drivers/dri/i965/gen6_wm_state.c | 3 +- src/mesa/drivers/dri/i965/gen7_wm_state.c | 3 +- 10 files changed, 103 insertions(+), 38 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h index ff25b09..4ae8580 100644 --- a/src/mesa/drivers/dri/i965/brw_context.h +++ b/src/mesa/drivers/dri/i965/brw_context.h @@ -976,6 +976,11 @@ void brw_compute_vue_map(struct brw_vue_map *vue_map, GLbitfield64 outputs_written); gl_clip_plane *brw_select_clip_planes(struct gl_context *ctx); +/* brw_wm.c */ +unsigned +brw_compute_barycentric_interp_modes(void); + + /*====================================================================== * Inline conversion functions. These are better-typed than the diff --git a/src/mesa/drivers/dri/i965/brw_defines.h b/src/mesa/drivers/dri/i965/brw_defines.h index 61a739c..d302a61 100644 --- a/src/mesa/drivers/dri/i965/brw_defines.h +++ b/src/mesa/drivers/dri/i965/brw_defines.h @@ -1215,6 +1215,16 @@ enum brw_message_target { /* DW12: attr 0-7 wrap shortest enables */ /* DW13: attr 8-16 wrap shortest enables */ +enum brw_wm_barycentric_interp_mode { + BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC = 0, + BRW_WM_PERSPECTIVE_CENTROID_BARYCENTRIC = 1, + BRW_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC = 2, + BRW_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC = 3, + BRW_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC = 4, + BRW_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC = 5, + BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT = 6 +}; + #define _3DSTATE_WM 0x7814 /* GEN6+ */ /* DW1: kernel pointer */ /* DW2 */ @@ -1269,6 +1279,7 @@ enum brw_message_target { # define GEN6_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 12) # define GEN6_WM_PERSPECTIVE_CENTROID_BARYCENTRIC (1 << 11) # define GEN6_WM_PERSPECTIVE_PIXEL_BARYCENTRIC (1 << 10) +# define GEN6_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT 10 # define GEN6_WM_POINT_RASTRULE_UPPER_RIGHT (1 << 9) # define GEN6_WM_MSRAST_OFF_PIXEL (0 << 1) # define GEN6_WM_MSRAST_OFF_PATTERN (1 << 1) @@ -1306,12 +1317,7 @@ enum brw_message_target { # define GEN7_WM_POSITION_ZW_PIXEL (0 << 17) # define GEN7_WM_POSITION_ZW_CENTROID (2 << 17) # define GEN7_WM_POSITION_ZW_SAMPLE (3 << 17) -# define GEN7_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 16) -# define GEN7_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC (1 << 15) -# define GEN7_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC (1 << 14) -# define GEN7_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 13) -# define GEN7_WM_PERSPECTIVE_CENTROID_BARYCENTRIC (1 << 12) -# define GEN7_WM_PERSPECTIVE_PIXEL_BARYCENTRIC (1 << 11) +# define GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT 11 # define GEN7_WM_USES_INPUT_COVERAGE_MASK (1 << 10) # define GEN7_WM_LINE_END_CAP_AA_WIDTH_0_5 (0 << 8) # define GEN7_WM_LINE_END_CAP_AA_WIDTH_1_0 (1 << 8) diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index 3848915..b3ad505 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -407,8 +407,10 @@ fs_visitor::emit_fragcoord_interpolation(ir_variable *ir) emit(BRW_OPCODE_MOV, wpos, fs_reg(brw_vec8_grf(c->source_depth_reg, 0))); } else { - emit(FS_OPCODE_LINTERP, wpos, this->delta_x, this->delta_y, - interp_reg(FRAG_ATTRIB_WPOS, 2)); + emit(FS_OPCODE_LINTERP, wpos, + this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC], + this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC], + interp_reg(FRAG_ATTRIB_WPOS, 2)); } wpos.reg_offset++; @@ -481,8 +483,11 @@ fs_visitor::emit_general_interpolation(ir_variable *ir) emit(BRW_OPCODE_MOV, attr, fs_reg(1.0f)); } else { struct brw_reg interp = interp_reg(location, k); - emit(FS_OPCODE_LINTERP, attr, - this->delta_x, this->delta_y, fs_reg(interp)); + brw_wm_barycentric_interp_mode barycoord_mode = + BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC; + emit(FS_OPCODE_LINTERP, attr, + this->delta_x[barycoord_mode], + this->delta_y[barycoord_mode], fs_reg(interp)); } attr.reg_offset++; } @@ -768,9 +773,15 @@ fs_visitor::split_virtual_grfs() split_grf[i] = false; } - if (brw->has_pln && this->delta_x.file == GRF) { - /* PLN opcodes rely on the delta_xy being contiguous. */ - split_grf[this->delta_x.reg] = false; + if (brw->has_pln && + this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC].file == GRF) { + /* PLN opcodes rely on the delta_xy being contiguous. We only have to + * check this for BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC, because prior to + * Gen6, that was the only supported interpolation mode, and since Gen6, + * delta_x and delta_y are in fixed hardware registers. + */ + split_grf[this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC].reg] = + false; } foreach_list(node, &this->instructions) { diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h index f5af9ea..e2ad649 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.h +++ b/src/mesa/drivers/dri/i965/brw_fs.h @@ -594,8 +594,8 @@ public: fs_reg pixel_y; fs_reg wpos_w; fs_reg pixel_w; - fs_reg delta_x; - fs_reg delta_y; + fs_reg delta_x[BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT]; + fs_reg delta_y[BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT]; fs_reg reg_null_cmp; int grf_used; 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 6e38cc2..3f875cc 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp @@ -202,8 +202,17 @@ fs_visitor::assign_regs() for (int i = 0; i < this->virtual_grf_next; i++) { for (int c = 0; c < class_count; c++) { if (class_sizes[c] == this->virtual_grf_sizes[i]) { + /* Special case: on pre-GEN6 hardware that supports PLN, the + * second operand of a PLN instruction needs to be an + * even-numbered register, so we have a special register class + * wm_aligned_pairs_class to handle this case. pre-GEN6 always + * uses this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] as the + * second operand of a PLN instruction (since it doesn't support + * any other interpolation modes). So all we need to do is find + * that register and set it to the appropriate class. + */ if (brw->wm.aligned_pairs_class >= 0 && - this->delta_x.reg == i) { + this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC].reg == i) { ra_set_node_class(g, i, brw->wm.aligned_pairs_class); } else { ra_set_node_class(g, i, brw->wm.classes[c]); diff --git a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp index 215cdcd..2f95014 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp @@ -1754,16 +1754,20 @@ fs_visitor::emit_interpolation_setup_gen4() this->current_annotation = "compute pixel deltas from v0"; if (brw->has_pln) { - this->delta_x = fs_reg(this, glsl_type::vec2_type); - this->delta_y = this->delta_x; - this->delta_y.reg_offset++; + this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] = + fs_reg(this, glsl_type::vec2_type); + this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] = + this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC]; + this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC].reg_offset++; } else { - this->delta_x = fs_reg(this, glsl_type::float_type); - this->delta_y = fs_reg(this, glsl_type::float_type); + this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] = + fs_reg(this, glsl_type::float_type); + this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] = + fs_reg(this, glsl_type::float_type); } - emit(BRW_OPCODE_ADD, this->delta_x, + emit(BRW_OPCODE_ADD, this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC], this->pixel_x, fs_reg(negate(brw_vec1_grf(1, 0)))); - emit(BRW_OPCODE_ADD, this->delta_y, + emit(BRW_OPCODE_ADD, this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC], this->pixel_y, fs_reg(negate(brw_vec1_grf(1, 1)))); this->current_annotation = "compute pos.w and 1/pos.w"; @@ -1771,7 +1775,9 @@ fs_visitor::emit_interpolation_setup_gen4() * interpolate the other attributes. */ this->wpos_w = fs_reg(this, glsl_type::float_type); - emit(FS_OPCODE_LINTERP, wpos_w, this->delta_x, this->delta_y, + emit(FS_OPCODE_LINTERP, wpos_w, + this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC], + this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC], interp_reg(FRAG_ATTRIB_WPOS, 3)); /* Compute the pixel 1/W value from wpos.w. */ this->pixel_w = fs_reg(this, glsl_type::float_type); @@ -1814,8 +1820,11 @@ fs_visitor::emit_interpolation_setup_gen6() this->wpos_w = fs_reg(this, glsl_type::float_type); emit_math(SHADER_OPCODE_RCP, this->wpos_w, this->pixel_w); - this->delta_x = fs_reg(brw_vec8_grf(2, 0)); - this->delta_y = fs_reg(brw_vec8_grf(3, 0)); + for (int i = 0; i < BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT; ++i) { + uint8_t reg = c->barycentric_coord_reg[i]; + this->delta_x[i] = fs_reg(brw_vec8_grf(reg, 0)); + this->delta_y[i] = fs_reg(brw_vec8_grf(reg + 1, 0)); + } this->current_annotation = NULL; } diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c index b60173e..81dad4f 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.c +++ b/src/mesa/drivers/dri/i965/brw_wm.c @@ -123,6 +123,19 @@ brw_wm_non_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c) brw_wm_emit(c); } + +/** + * Return a bitfield where bit n is set if barycentric interpolation mode n + * (see enum brw_wm_barycentric_interp_mode) is needed by the fragment shader. + */ +unsigned +brw_compute_barycentric_interp_modes(void) +{ + /* At the moment the only interpolation mode we support is perspective. */ + return (1 << BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC); +} + + void brw_wm_payload_setup(struct brw_context *brw, struct brw_wm_compile *c) @@ -130,22 +143,31 @@ brw_wm_payload_setup(struct brw_context *brw, struct intel_context *intel = &brw->intel; bool uses_depth = (c->fp->program.Base.InputsRead & (1 << FRAG_ATTRIB_WPOS)) != 0; + unsigned barycentric_interp_modes = + brw_compute_barycentric_interp_modes(); + int i; if (intel->gen >= 6) { /* R0-1: masks, pixel X/Y coordinates. */ c->nr_payload_regs = 2; /* R2: only for 32-pixel dispatch.*/ - /* R3-4: perspective pixel location barycentric */ - c->nr_payload_regs += 2; - /* R5-6: perspective pixel location bary for dispatch width != 8 */ - if (c->dispatch_width == 16) { - c->nr_payload_regs += 2; + + /* R3-26: barycentric interpolation coordinates. These appear in the + * same order that they appear in the brw_wm_barycentric_interp_mode + * enum. Each set of coordinates occupies 2 registers if dispatch width + * == 8 and 4 registers if dispatch width == 16. Coordinates only + * appear if they were enabled using the "Barycentric Interpolation + * Mode" bits in WM_STATE. + */ + for (i = 0; i < BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT; ++i) { + if (barycentric_interp_modes & (1 << i)) { + c->barycentric_coord_reg[i] = c->nr_payload_regs; + c->nr_payload_regs += 2; + if (c->dispatch_width == 16) { + c->nr_payload_regs += 2; + } + } } - /* R7-10: perspective centroid barycentric */ - /* R11-14: perspective sample barycentric */ - /* R15-18: linear pixel location barycentric */ - /* R19-22: linear centroid barycentric */ - /* R23-26: linear sample barycentric */ /* R27: interpolated depth if uses source depth */ if (uses_depth) { diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h index efd18e9..76cf453 100644 --- a/src/mesa/drivers/dri/i965/brw_wm.h +++ b/src/mesa/drivers/dri/i965/brw_wm.h @@ -215,6 +215,7 @@ struct brw_wm_compile { uint8_t source_w_reg; uint8_t aa_dest_stencil_reg; uint8_t dest_depth_reg; + uint8_t barycentric_coord_reg[BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT]; uint8_t nr_payload_regs; GLuint computes_depth:1; /* could be derived from program string */ GLuint source_depth_to_render_target:1; diff --git a/src/mesa/drivers/dri/i965/gen6_wm_state.c b/src/mesa/drivers/dri/i965/gen6_wm_state.c index 24fc81d..178375f 100644 --- a/src/mesa/drivers/dri/i965/gen6_wm_state.c +++ b/src/mesa/drivers/dri/i965/gen6_wm_state.c @@ -178,7 +178,8 @@ upload_wm_state(struct brw_context *brw) dw5 |= GEN6_WM_DISPATCH_ENABLE; } - dw6 |= GEN6_WM_PERSPECTIVE_PIXEL_BARYCENTRIC; + dw6 |= brw_compute_barycentric_interp_modes() << + GEN6_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT; dw6 |= _mesa_bitcount_64(brw->fragment_program->Base.InputsRead) << GEN6_WM_NUM_SF_OUTPUTS_SHIFT; diff --git a/src/mesa/drivers/dri/i965/gen7_wm_state.c b/src/mesa/drivers/dri/i965/gen7_wm_state.c index aae3c11..fc23c2e 100644 --- a/src/mesa/drivers/dri/i965/gen7_wm_state.c +++ b/src/mesa/drivers/dri/i965/gen7_wm_state.c @@ -72,7 +72,8 @@ upload_wm_state(struct brw_context *brw) dw1 |= GEN7_WM_DISPATCH_ENABLE; } - dw1 |= GEN7_WM_PERSPECTIVE_PIXEL_BARYCENTRIC; + dw1 |= brw_compute_barycentric_interp_modes() << + GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT; BEGIN_BATCH(3); OUT_BATCH(_3DSTATE_WM << 16 | (3 - 2)); -- 2.7.4