intel/brw: Reduce scope of some FS specific functions
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30169>
This commit is contained in:
@@ -19,6 +19,622 @@
|
|||||||
|
|
||||||
using namespace brw;
|
using namespace brw;
|
||||||
|
|
||||||
|
static fs_inst *
|
||||||
|
brw_emit_single_fb_write(fs_visitor &s, const fs_builder &bld,
|
||||||
|
brw_reg color0, brw_reg color1,
|
||||||
|
brw_reg src0_alpha, unsigned components)
|
||||||
|
{
|
||||||
|
assert(s.stage == MESA_SHADER_FRAGMENT);
|
||||||
|
struct brw_wm_prog_data *prog_data = brw_wm_prog_data(s.prog_data);
|
||||||
|
|
||||||
|
/* Hand over gl_FragDepth or the payload depth. */
|
||||||
|
const brw_reg dst_depth = fetch_payload_reg(bld, s.fs_payload().dest_depth_reg);
|
||||||
|
brw_reg src_depth, src_stencil;
|
||||||
|
|
||||||
|
if (s.nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH))
|
||||||
|
src_depth = s.frag_depth;
|
||||||
|
|
||||||
|
if (s.nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_STENCIL))
|
||||||
|
src_stencil = s.frag_stencil;
|
||||||
|
|
||||||
|
const brw_reg sources[] = {
|
||||||
|
color0, color1, src0_alpha, src_depth, dst_depth, src_stencil,
|
||||||
|
(prog_data->uses_omask ? s.sample_mask : brw_reg()),
|
||||||
|
brw_imm_ud(components)
|
||||||
|
};
|
||||||
|
assert(ARRAY_SIZE(sources) - 1 == FB_WRITE_LOGICAL_SRC_COMPONENTS);
|
||||||
|
fs_inst *write = bld.emit(FS_OPCODE_FB_WRITE_LOGICAL, brw_reg(),
|
||||||
|
sources, ARRAY_SIZE(sources));
|
||||||
|
|
||||||
|
if (prog_data->uses_kill) {
|
||||||
|
write->predicate = BRW_PREDICATE_NORMAL;
|
||||||
|
write->flag_subreg = sample_mask_flag_subreg(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return write;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
brw_do_emit_fb_writes(fs_visitor &s, int nr_color_regions, bool replicate_alpha)
|
||||||
|
{
|
||||||
|
const fs_builder bld = fs_builder(&s).at_end();
|
||||||
|
fs_inst *inst = NULL;
|
||||||
|
|
||||||
|
for (int target = 0; target < nr_color_regions; target++) {
|
||||||
|
/* Skip over outputs that weren't written. */
|
||||||
|
if (s.outputs[target].file == BAD_FILE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const fs_builder abld = bld.annotate(
|
||||||
|
ralloc_asprintf(s.mem_ctx, "FB write target %d", target));
|
||||||
|
|
||||||
|
brw_reg src0_alpha;
|
||||||
|
if (replicate_alpha && target != 0)
|
||||||
|
src0_alpha = offset(s.outputs[0], bld, 3);
|
||||||
|
|
||||||
|
inst = brw_emit_single_fb_write(s, abld, s.outputs[target],
|
||||||
|
s.dual_src_output, src0_alpha, 4);
|
||||||
|
inst->target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst == NULL) {
|
||||||
|
/* Even if there's no color buffers enabled, we still need to send
|
||||||
|
* alpha out the pipeline to our null renderbuffer to support
|
||||||
|
* alpha-testing, alpha-to-coverage, and so on.
|
||||||
|
*/
|
||||||
|
/* FINISHME: Factor out this frequently recurring pattern into a
|
||||||
|
* helper function.
|
||||||
|
*/
|
||||||
|
const brw_reg srcs[] = { reg_undef, reg_undef,
|
||||||
|
reg_undef, offset(s.outputs[0], bld, 3) };
|
||||||
|
const brw_reg tmp = bld.vgrf(BRW_TYPE_UD, 4);
|
||||||
|
bld.LOAD_PAYLOAD(tmp, srcs, 4, 0);
|
||||||
|
|
||||||
|
inst = brw_emit_single_fb_write(s, bld, tmp, reg_undef, reg_undef, 4);
|
||||||
|
inst->target = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inst->last_rt = true;
|
||||||
|
inst->eot = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
brw_emit_fb_writes(fs_visitor &s)
|
||||||
|
{
|
||||||
|
const struct intel_device_info *devinfo = s.devinfo;
|
||||||
|
assert(s.stage == MESA_SHADER_FRAGMENT);
|
||||||
|
struct brw_wm_prog_data *prog_data = brw_wm_prog_data(s.prog_data);
|
||||||
|
brw_wm_prog_key *key = (brw_wm_prog_key*) s.key;
|
||||||
|
|
||||||
|
if (s.nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) {
|
||||||
|
/* From the 'Render Target Write message' section of the docs:
|
||||||
|
* "Output Stencil is not supported with SIMD16 Render Target Write
|
||||||
|
* Messages."
|
||||||
|
*/
|
||||||
|
if (devinfo->ver >= 20)
|
||||||
|
s.limit_dispatch_width(16, "gl_FragStencilRefARB unsupported "
|
||||||
|
"in SIMD32+ mode.\n");
|
||||||
|
else
|
||||||
|
s.limit_dispatch_width(8, "gl_FragStencilRefARB unsupported "
|
||||||
|
"in SIMD16+ mode.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ANV doesn't know about sample mask output during the wm key creation
|
||||||
|
* so we compute if we need replicate alpha and emit alpha to coverage
|
||||||
|
* workaround here.
|
||||||
|
*/
|
||||||
|
const bool replicate_alpha = key->alpha_test_replicate_alpha ||
|
||||||
|
(key->nr_color_regions > 1 && key->alpha_to_coverage &&
|
||||||
|
s.sample_mask.file == BAD_FILE);
|
||||||
|
|
||||||
|
prog_data->dual_src_blend = (s.dual_src_output.file != BAD_FILE &&
|
||||||
|
s.outputs[0].file != BAD_FILE);
|
||||||
|
assert(!prog_data->dual_src_blend || key->nr_color_regions == 1);
|
||||||
|
|
||||||
|
/* Following condition implements Wa_14017468336:
|
||||||
|
*
|
||||||
|
* "If dual source blend is enabled do not enable SIMD32 dispatch" and
|
||||||
|
* "For a thread dispatched as SIMD32, must not issue SIMD8 message with Last
|
||||||
|
* Render Target Select set."
|
||||||
|
*/
|
||||||
|
if (devinfo->ver >= 11 && devinfo->ver <= 12 &&
|
||||||
|
prog_data->dual_src_blend) {
|
||||||
|
/* The dual-source RT write messages fail to release the thread
|
||||||
|
* dependency on ICL and TGL with SIMD32 dispatch, leading to hangs.
|
||||||
|
*
|
||||||
|
* XXX - Emit an extra single-source NULL RT-write marked LastRT in
|
||||||
|
* order to release the thread dependency without disabling
|
||||||
|
* SIMD32.
|
||||||
|
*
|
||||||
|
* The dual-source RT write messages may lead to hangs with SIMD16
|
||||||
|
* dispatch on ICL due some unknown reasons, see
|
||||||
|
* https://gitlab.freedesktop.org/mesa/mesa/-/issues/2183
|
||||||
|
*/
|
||||||
|
if (devinfo->ver >= 20)
|
||||||
|
s.limit_dispatch_width(16, "Dual source blending unsupported "
|
||||||
|
"in SIMD32 mode.\n");
|
||||||
|
else
|
||||||
|
s.limit_dispatch_width(8, "Dual source blending unsupported "
|
||||||
|
"in SIMD16 and SIMD32 modes.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
brw_do_emit_fb_writes(s, key->nr_color_regions, replicate_alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Emits the interpolation for the varying inputs. */
|
||||||
|
static void
|
||||||
|
brw_emit_interpolation_setup(fs_visitor &s)
|
||||||
|
{
|
||||||
|
const struct intel_device_info *devinfo = s.devinfo;
|
||||||
|
const fs_builder bld = fs_builder(&s).at_end();
|
||||||
|
fs_builder abld = bld.annotate("compute pixel centers");
|
||||||
|
|
||||||
|
s.pixel_x = bld.vgrf(BRW_TYPE_F);
|
||||||
|
s.pixel_y = bld.vgrf(BRW_TYPE_F);
|
||||||
|
|
||||||
|
const struct brw_wm_prog_key *wm_key = (brw_wm_prog_key*) s.key;
|
||||||
|
struct brw_wm_prog_data *wm_prog_data = brw_wm_prog_data(s.prog_data);
|
||||||
|
fs_thread_payload &payload = s.fs_payload();
|
||||||
|
|
||||||
|
brw_reg int_sample_offset_x, int_sample_offset_y; /* Used on Gen12HP+ */
|
||||||
|
brw_reg int_sample_offset_xy; /* Used on Gen8+ */
|
||||||
|
brw_reg half_int_sample_offset_x, half_int_sample_offset_y;
|
||||||
|
if (wm_prog_data->coarse_pixel_dispatch != BRW_ALWAYS) {
|
||||||
|
/* The thread payload only delivers subspan locations (ss0, ss1,
|
||||||
|
* ss2, ...). Since subspans covers 2x2 pixels blocks, we need to
|
||||||
|
* generate 4 pixel coordinates out of each subspan location. We do this
|
||||||
|
* by replicating a subspan coordinate 4 times and adding an offset of 1
|
||||||
|
* in each direction from the initial top left (tl) location to generate
|
||||||
|
* top right (tr = +1 in x), bottom left (bl = +1 in y) and bottom right
|
||||||
|
* (br = +1 in x, +1 in y).
|
||||||
|
*
|
||||||
|
* The locations we build look like this in SIMD8 :
|
||||||
|
*
|
||||||
|
* ss0.tl ss0.tr ss0.bl ss0.br ss1.tl ss1.tr ss1.bl ss1.br
|
||||||
|
*
|
||||||
|
* The value 0x11001010 is a vector of 8 half byte vector. It adds
|
||||||
|
* following to generate the 4 pixels coordinates out of the subspan0:
|
||||||
|
*
|
||||||
|
* 0x
|
||||||
|
* 1 : ss0.y + 1 -> ss0.br.y
|
||||||
|
* 1 : ss0.y + 1 -> ss0.bl.y
|
||||||
|
* 0 : ss0.y + 0 -> ss0.tr.y
|
||||||
|
* 0 : ss0.y + 0 -> ss0.tl.y
|
||||||
|
* 1 : ss0.x + 1 -> ss0.br.x
|
||||||
|
* 0 : ss0.x + 0 -> ss0.bl.x
|
||||||
|
* 1 : ss0.x + 1 -> ss0.tr.x
|
||||||
|
* 0 : ss0.x + 0 -> ss0.tl.x
|
||||||
|
*
|
||||||
|
* By doing a SIMD16 add in a SIMD8 shader, we can generate the 8 pixels
|
||||||
|
* coordinates out of 2 subspans coordinates in a single ADD instruction
|
||||||
|
* (twice the operation above).
|
||||||
|
*/
|
||||||
|
int_sample_offset_xy = brw_reg(brw_imm_v(0x11001010));
|
||||||
|
half_int_sample_offset_x = brw_reg(brw_imm_uw(0));
|
||||||
|
half_int_sample_offset_y = brw_reg(brw_imm_uw(0));
|
||||||
|
/* On Gfx12.5, because of regioning restrictions, the interpolation code
|
||||||
|
* is slightly different and works off X & Y only inputs. The ordering
|
||||||
|
* of the half bytes here is a bit odd, with each subspan replicated
|
||||||
|
* twice and every other element is discarded :
|
||||||
|
*
|
||||||
|
* ss0.tl ss0.tl ss0.tr ss0.tr ss0.bl ss0.bl ss0.br ss0.br
|
||||||
|
* X offset: 0 0 1 0 0 0 1 0
|
||||||
|
* Y offset: 0 0 0 0 1 0 1 0
|
||||||
|
*/
|
||||||
|
int_sample_offset_x = brw_reg(brw_imm_v(0x01000100));
|
||||||
|
int_sample_offset_y = brw_reg(brw_imm_v(0x01010000));
|
||||||
|
}
|
||||||
|
|
||||||
|
brw_reg int_coarse_offset_x, int_coarse_offset_y; /* Used on Gen12HP+ */
|
||||||
|
brw_reg int_coarse_offset_xy; /* Used on Gen8+ */
|
||||||
|
brw_reg half_int_coarse_offset_x, half_int_coarse_offset_y;
|
||||||
|
if (wm_prog_data->coarse_pixel_dispatch != BRW_NEVER) {
|
||||||
|
/* In coarse pixel dispatch we have to do the same ADD instruction that
|
||||||
|
* we do in normal per pixel dispatch, except this time we're not adding
|
||||||
|
* 1 in each direction, but instead the coarse pixel size.
|
||||||
|
*
|
||||||
|
* The coarse pixel size is delivered as 2 u8 in r1.0
|
||||||
|
*/
|
||||||
|
struct brw_reg r1_0 = retype(brw_vec1_reg(BRW_GENERAL_REGISTER_FILE, 1, 0), BRW_TYPE_UB);
|
||||||
|
|
||||||
|
const fs_builder dbld =
|
||||||
|
abld.exec_all().group(MIN2(16, s.dispatch_width) * 2, 0);
|
||||||
|
|
||||||
|
if (devinfo->verx10 >= 125) {
|
||||||
|
/* To build the array of half bytes we do and AND operation with the
|
||||||
|
* right mask in X.
|
||||||
|
*/
|
||||||
|
int_coarse_offset_x = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
dbld.AND(int_coarse_offset_x, byte_offset(r1_0, 0), brw_imm_v(0x0f000f00));
|
||||||
|
|
||||||
|
/* And the right mask in Y. */
|
||||||
|
int_coarse_offset_y = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
dbld.AND(int_coarse_offset_y, byte_offset(r1_0, 1), brw_imm_v(0x0f0f0000));
|
||||||
|
} else {
|
||||||
|
/* To build the array of half bytes we do and AND operation with the
|
||||||
|
* right mask in X.
|
||||||
|
*/
|
||||||
|
int_coarse_offset_x = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
dbld.AND(int_coarse_offset_x, byte_offset(r1_0, 0), brw_imm_v(0x0000f0f0));
|
||||||
|
|
||||||
|
/* And the right mask in Y. */
|
||||||
|
int_coarse_offset_y = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
dbld.AND(int_coarse_offset_y, byte_offset(r1_0, 1), brw_imm_v(0xff000000));
|
||||||
|
|
||||||
|
/* Finally OR the 2 registers. */
|
||||||
|
int_coarse_offset_xy = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
dbld.OR(int_coarse_offset_xy, int_coarse_offset_x, int_coarse_offset_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also compute the half coarse size used to center coarses. */
|
||||||
|
half_int_coarse_offset_x = bld.vgrf(BRW_TYPE_UW);
|
||||||
|
half_int_coarse_offset_y = bld.vgrf(BRW_TYPE_UW);
|
||||||
|
|
||||||
|
bld.SHR(half_int_coarse_offset_x, suboffset(r1_0, 0), brw_imm_ud(1));
|
||||||
|
bld.SHR(half_int_coarse_offset_y, suboffset(r1_0, 1), brw_imm_ud(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
brw_reg int_pixel_offset_x, int_pixel_offset_y; /* Used on Gen12HP+ */
|
||||||
|
brw_reg int_pixel_offset_xy; /* Used on Gen8+ */
|
||||||
|
brw_reg half_int_pixel_offset_x, half_int_pixel_offset_y;
|
||||||
|
switch (wm_prog_data->coarse_pixel_dispatch) {
|
||||||
|
case BRW_NEVER:
|
||||||
|
int_pixel_offset_x = int_sample_offset_x;
|
||||||
|
int_pixel_offset_y = int_sample_offset_y;
|
||||||
|
int_pixel_offset_xy = int_sample_offset_xy;
|
||||||
|
half_int_pixel_offset_x = half_int_sample_offset_x;
|
||||||
|
half_int_pixel_offset_y = half_int_sample_offset_y;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BRW_SOMETIMES: {
|
||||||
|
const fs_builder dbld =
|
||||||
|
abld.exec_all().group(MIN2(16, s.dispatch_width) * 2, 0);
|
||||||
|
|
||||||
|
check_dynamic_msaa_flag(dbld, wm_prog_data,
|
||||||
|
INTEL_MSAA_FLAG_COARSE_RT_WRITES);
|
||||||
|
|
||||||
|
int_pixel_offset_x = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
set_predicate(BRW_PREDICATE_NORMAL,
|
||||||
|
dbld.SEL(int_pixel_offset_x,
|
||||||
|
int_coarse_offset_x,
|
||||||
|
int_sample_offset_x));
|
||||||
|
|
||||||
|
int_pixel_offset_y = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
set_predicate(BRW_PREDICATE_NORMAL,
|
||||||
|
dbld.SEL(int_pixel_offset_y,
|
||||||
|
int_coarse_offset_y,
|
||||||
|
int_sample_offset_y));
|
||||||
|
|
||||||
|
int_pixel_offset_xy = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
set_predicate(BRW_PREDICATE_NORMAL,
|
||||||
|
dbld.SEL(int_pixel_offset_xy,
|
||||||
|
int_coarse_offset_xy,
|
||||||
|
int_sample_offset_xy));
|
||||||
|
|
||||||
|
half_int_pixel_offset_x = bld.vgrf(BRW_TYPE_UW);
|
||||||
|
set_predicate(BRW_PREDICATE_NORMAL,
|
||||||
|
bld.SEL(half_int_pixel_offset_x,
|
||||||
|
half_int_coarse_offset_x,
|
||||||
|
half_int_sample_offset_x));
|
||||||
|
|
||||||
|
half_int_pixel_offset_y = bld.vgrf(BRW_TYPE_UW);
|
||||||
|
set_predicate(BRW_PREDICATE_NORMAL,
|
||||||
|
bld.SEL(half_int_pixel_offset_y,
|
||||||
|
half_int_coarse_offset_y,
|
||||||
|
half_int_sample_offset_y));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BRW_ALWAYS:
|
||||||
|
int_pixel_offset_x = int_coarse_offset_x;
|
||||||
|
int_pixel_offset_y = int_coarse_offset_y;
|
||||||
|
int_pixel_offset_xy = int_coarse_offset_xy;
|
||||||
|
half_int_pixel_offset_x = half_int_coarse_offset_x;
|
||||||
|
half_int_pixel_offset_y = half_int_coarse_offset_y;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < DIV_ROUND_UP(s.dispatch_width, 16); i++) {
|
||||||
|
const fs_builder hbld = abld.group(MIN2(16, s.dispatch_width), i);
|
||||||
|
/* According to the "PS Thread Payload for Normal Dispatch"
|
||||||
|
* pages on the BSpec, subspan X/Y coordinates are stored in
|
||||||
|
* R1.2-R1.5/R2.2-R2.5 on gfx6+, and on R0.10-R0.13/R1.10-R1.13
|
||||||
|
* on gfx20+. gi_reg is the 32B section of the GRF that
|
||||||
|
* contains the subspan coordinates.
|
||||||
|
*/
|
||||||
|
const struct brw_reg gi_reg = devinfo->ver >= 20 ? xe2_vec1_grf(i, 8) :
|
||||||
|
brw_vec1_grf(i + 1, 0);
|
||||||
|
const struct brw_reg gi_uw = retype(gi_reg, BRW_TYPE_UW);
|
||||||
|
|
||||||
|
if (devinfo->verx10 >= 125) {
|
||||||
|
const fs_builder dbld =
|
||||||
|
abld.exec_all().group(hbld.dispatch_width() * 2, 0);
|
||||||
|
const brw_reg int_pixel_x = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
const brw_reg int_pixel_y = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
|
||||||
|
dbld.ADD(int_pixel_x,
|
||||||
|
brw_reg(stride(suboffset(gi_uw, 4), 2, 8, 0)),
|
||||||
|
int_pixel_offset_x);
|
||||||
|
dbld.ADD(int_pixel_y,
|
||||||
|
brw_reg(stride(suboffset(gi_uw, 5), 2, 8, 0)),
|
||||||
|
int_pixel_offset_y);
|
||||||
|
|
||||||
|
if (wm_prog_data->coarse_pixel_dispatch != BRW_NEVER) {
|
||||||
|
fs_inst *addx = dbld.ADD(int_pixel_x, int_pixel_x,
|
||||||
|
horiz_stride(half_int_pixel_offset_x, 0));
|
||||||
|
fs_inst *addy = dbld.ADD(int_pixel_y, int_pixel_y,
|
||||||
|
horiz_stride(half_int_pixel_offset_y, 0));
|
||||||
|
if (wm_prog_data->coarse_pixel_dispatch != BRW_ALWAYS) {
|
||||||
|
addx->predicate = BRW_PREDICATE_NORMAL;
|
||||||
|
addy->predicate = BRW_PREDICATE_NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hbld.MOV(offset(s.pixel_x, hbld, i), horiz_stride(int_pixel_x, 2));
|
||||||
|
hbld.MOV(offset(s.pixel_y, hbld, i), horiz_stride(int_pixel_y, 2));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* The "Register Region Restrictions" page says for BDW (and newer,
|
||||||
|
* presumably):
|
||||||
|
*
|
||||||
|
* "When destination spans two registers, the source may be one or
|
||||||
|
* two registers. The destination elements must be evenly split
|
||||||
|
* between the two registers."
|
||||||
|
*
|
||||||
|
* Thus we can do a single add(16) in SIMD8 or an add(32) in SIMD16
|
||||||
|
* to compute our pixel centers.
|
||||||
|
*/
|
||||||
|
const fs_builder dbld =
|
||||||
|
abld.exec_all().group(hbld.dispatch_width() * 2, 0);
|
||||||
|
brw_reg int_pixel_xy = dbld.vgrf(BRW_TYPE_UW);
|
||||||
|
|
||||||
|
dbld.ADD(int_pixel_xy,
|
||||||
|
brw_reg(stride(suboffset(gi_uw, 4), 1, 4, 0)),
|
||||||
|
int_pixel_offset_xy);
|
||||||
|
|
||||||
|
hbld.emit(FS_OPCODE_PIXEL_X, offset(s.pixel_x, hbld, i), int_pixel_xy,
|
||||||
|
horiz_stride(half_int_pixel_offset_x, 0));
|
||||||
|
hbld.emit(FS_OPCODE_PIXEL_Y, offset(s.pixel_y, hbld, i), int_pixel_xy,
|
||||||
|
horiz_stride(half_int_pixel_offset_y, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abld = bld.annotate("compute pos.z");
|
||||||
|
brw_reg coarse_z;
|
||||||
|
if (wm_prog_data->coarse_pixel_dispatch != BRW_NEVER &&
|
||||||
|
wm_prog_data->uses_depth_w_coefficients) {
|
||||||
|
/* In coarse pixel mode, the HW doesn't interpolate Z coordinate
|
||||||
|
* properly. In the same way we have to add the coarse pixel size to
|
||||||
|
* pixels locations, here we recompute the Z value with 2 coefficients
|
||||||
|
* in X & Y axis.
|
||||||
|
*/
|
||||||
|
brw_reg coef_payload = brw_vec8_grf(payload.depth_w_coef_reg, 0);
|
||||||
|
const brw_reg x_start = brw_vec1_grf(coef_payload.nr, 2);
|
||||||
|
const brw_reg y_start = brw_vec1_grf(coef_payload.nr, 6);
|
||||||
|
const brw_reg z_cx = brw_vec1_grf(coef_payload.nr, 1);
|
||||||
|
const brw_reg z_cy = brw_vec1_grf(coef_payload.nr, 0);
|
||||||
|
const brw_reg z_c0 = brw_vec1_grf(coef_payload.nr, 3);
|
||||||
|
|
||||||
|
const brw_reg float_pixel_x = abld.vgrf(BRW_TYPE_F);
|
||||||
|
const brw_reg float_pixel_y = abld.vgrf(BRW_TYPE_F);
|
||||||
|
|
||||||
|
abld.ADD(float_pixel_x, s.pixel_x, negate(x_start));
|
||||||
|
abld.ADD(float_pixel_y, s.pixel_y, negate(y_start));
|
||||||
|
|
||||||
|
/* r1.0 - 0:7 ActualCoarsePixelShadingSize.X */
|
||||||
|
const brw_reg u8_cps_width = brw_reg(retype(brw_vec1_grf(1, 0), BRW_TYPE_UB));
|
||||||
|
/* r1.0 - 15:8 ActualCoarsePixelShadingSize.Y */
|
||||||
|
const brw_reg u8_cps_height = byte_offset(u8_cps_width, 1);
|
||||||
|
const brw_reg u32_cps_width = abld.vgrf(BRW_TYPE_UD);
|
||||||
|
const brw_reg u32_cps_height = abld.vgrf(BRW_TYPE_UD);
|
||||||
|
abld.MOV(u32_cps_width, u8_cps_width);
|
||||||
|
abld.MOV(u32_cps_height, u8_cps_height);
|
||||||
|
|
||||||
|
const brw_reg f_cps_width = abld.vgrf(BRW_TYPE_F);
|
||||||
|
const brw_reg f_cps_height = abld.vgrf(BRW_TYPE_F);
|
||||||
|
abld.MOV(f_cps_width, u32_cps_width);
|
||||||
|
abld.MOV(f_cps_height, u32_cps_height);
|
||||||
|
|
||||||
|
/* Center in the middle of the coarse pixel. */
|
||||||
|
abld.MAD(float_pixel_x, float_pixel_x, brw_imm_f(0.5f), f_cps_width);
|
||||||
|
abld.MAD(float_pixel_y, float_pixel_y, brw_imm_f(0.5f), f_cps_height);
|
||||||
|
|
||||||
|
coarse_z = abld.vgrf(BRW_TYPE_F);
|
||||||
|
abld.MAD(coarse_z, z_c0, z_cx, float_pixel_x);
|
||||||
|
abld.MAD(coarse_z, coarse_z, z_cy, float_pixel_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wm_prog_data->uses_src_depth)
|
||||||
|
s.pixel_z = fetch_payload_reg(bld, payload.source_depth_reg);
|
||||||
|
|
||||||
|
if (wm_prog_data->uses_depth_w_coefficients ||
|
||||||
|
wm_prog_data->uses_src_depth) {
|
||||||
|
brw_reg sample_z = s.pixel_z;
|
||||||
|
|
||||||
|
switch (wm_prog_data->coarse_pixel_dispatch) {
|
||||||
|
case BRW_NEVER:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BRW_SOMETIMES:
|
||||||
|
assert(wm_prog_data->uses_src_depth);
|
||||||
|
assert(wm_prog_data->uses_depth_w_coefficients);
|
||||||
|
s.pixel_z = abld.vgrf(BRW_TYPE_F);
|
||||||
|
|
||||||
|
/* We re-use the check_dynamic_msaa_flag() call from above */
|
||||||
|
set_predicate(BRW_PREDICATE_NORMAL,
|
||||||
|
abld.SEL(s.pixel_z, coarse_z, sample_z));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BRW_ALWAYS:
|
||||||
|
assert(!wm_prog_data->uses_src_depth);
|
||||||
|
assert(wm_prog_data->uses_depth_w_coefficients);
|
||||||
|
s.pixel_z = coarse_z;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wm_prog_data->uses_src_w) {
|
||||||
|
abld = bld.annotate("compute pos.w");
|
||||||
|
s.pixel_w = fetch_payload_reg(abld, payload.source_w_reg);
|
||||||
|
s.wpos_w = bld.vgrf(BRW_TYPE_F);
|
||||||
|
abld.emit(SHADER_OPCODE_RCP, s.wpos_w, s.pixel_w);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wm_key->persample_interp == BRW_SOMETIMES) {
|
||||||
|
assert(!devinfo->needs_unlit_centroid_workaround);
|
||||||
|
|
||||||
|
const fs_builder ubld = bld.exec_all().group(16, 0);
|
||||||
|
bool loaded_flag = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < BRW_BARYCENTRIC_MODE_COUNT; ++i) {
|
||||||
|
if (!(wm_prog_data->barycentric_interp_modes & BITFIELD_BIT(i)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* The sample mode will always be the top bit set in the perspective
|
||||||
|
* or non-perspective section. In the case where no SAMPLE mode was
|
||||||
|
* requested, wm_prog_data_barycentric_modes() will swap out the top
|
||||||
|
* mode for SAMPLE so this works regardless of whether SAMPLE was
|
||||||
|
* requested or not.
|
||||||
|
*/
|
||||||
|
int sample_mode;
|
||||||
|
if (BITFIELD_BIT(i) & BRW_BARYCENTRIC_NONPERSPECTIVE_BITS) {
|
||||||
|
sample_mode = util_last_bit(wm_prog_data->barycentric_interp_modes &
|
||||||
|
BRW_BARYCENTRIC_NONPERSPECTIVE_BITS) - 1;
|
||||||
|
} else {
|
||||||
|
sample_mode = util_last_bit(wm_prog_data->barycentric_interp_modes &
|
||||||
|
BRW_BARYCENTRIC_PERSPECTIVE_BITS) - 1;
|
||||||
|
}
|
||||||
|
assert(wm_prog_data->barycentric_interp_modes &
|
||||||
|
BITFIELD_BIT(sample_mode));
|
||||||
|
|
||||||
|
if (i == sample_mode)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t *barys = payload.barycentric_coord_reg[i];
|
||||||
|
|
||||||
|
uint8_t *sample_barys = payload.barycentric_coord_reg[sample_mode];
|
||||||
|
assert(barys[0] && sample_barys[0]);
|
||||||
|
|
||||||
|
if (!loaded_flag) {
|
||||||
|
check_dynamic_msaa_flag(ubld, wm_prog_data,
|
||||||
|
INTEL_MSAA_FLAG_PERSAMPLE_INTERP);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned j = 0; j < s.dispatch_width / 8; j++) {
|
||||||
|
set_predicate(
|
||||||
|
BRW_PREDICATE_NORMAL,
|
||||||
|
ubld.MOV(brw_vec8_grf(barys[j / 2] + (j % 2) * 2, 0),
|
||||||
|
brw_vec8_grf(sample_barys[j / 2] + (j % 2) * 2, 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < BRW_BARYCENTRIC_MODE_COUNT; ++i) {
|
||||||
|
s.delta_xy[i] = fetch_barycentric_reg(
|
||||||
|
bld, payload.barycentric_coord_reg[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t centroid_modes = wm_prog_data->barycentric_interp_modes &
|
||||||
|
(1 << BRW_BARYCENTRIC_PERSPECTIVE_CENTROID |
|
||||||
|
1 << BRW_BARYCENTRIC_NONPERSPECTIVE_CENTROID);
|
||||||
|
|
||||||
|
if (devinfo->needs_unlit_centroid_workaround && centroid_modes) {
|
||||||
|
/* Get the pixel/sample mask into f0 so that we know which
|
||||||
|
* pixels are lit. Then, for each channel that is unlit,
|
||||||
|
* replace the centroid data with non-centroid data.
|
||||||
|
*/
|
||||||
|
for (unsigned i = 0; i < DIV_ROUND_UP(s.dispatch_width, 16); i++) {
|
||||||
|
bld.exec_all().group(1, 0)
|
||||||
|
.MOV(retype(brw_flag_reg(0, i), BRW_TYPE_UW),
|
||||||
|
retype(brw_vec1_grf(1 + i, 7), BRW_TYPE_UW));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < BRW_BARYCENTRIC_MODE_COUNT; ++i) {
|
||||||
|
if (!(centroid_modes & (1 << i)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const brw_reg centroid_delta_xy = s.delta_xy[i];
|
||||||
|
const brw_reg &pixel_delta_xy = s.delta_xy[i - 1];
|
||||||
|
|
||||||
|
s.delta_xy[i] = bld.vgrf(BRW_TYPE_F, 2);
|
||||||
|
|
||||||
|
for (unsigned c = 0; c < 2; c++) {
|
||||||
|
for (unsigned q = 0; q < s.dispatch_width / 8; q++) {
|
||||||
|
set_predicate(BRW_PREDICATE_NORMAL,
|
||||||
|
bld.quarter(q).SEL(
|
||||||
|
quarter(offset(s.delta_xy[i], bld, c), q),
|
||||||
|
quarter(offset(centroid_delta_xy, bld, c), q),
|
||||||
|
quarter(offset(pixel_delta_xy, bld, c), q)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Once we've generated code, try to convert normal FS_OPCODE_FB_WRITE
|
||||||
|
* instructions to FS_OPCODE_REP_FB_WRITE.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
brw_emit_repclear_shader(fs_visitor &s)
|
||||||
|
{
|
||||||
|
brw_wm_prog_key *key = (brw_wm_prog_key*) s.key;
|
||||||
|
fs_inst *write = NULL;
|
||||||
|
|
||||||
|
assert(s.devinfo->ver < 20);
|
||||||
|
assert(s.uniforms == 0);
|
||||||
|
assume(key->nr_color_regions > 0);
|
||||||
|
|
||||||
|
brw_reg color_output = retype(brw_vec4_grf(127, 0), BRW_TYPE_UD);
|
||||||
|
brw_reg header = retype(brw_vec8_grf(125, 0), BRW_TYPE_UD);
|
||||||
|
|
||||||
|
/* We pass the clear color as a flat input. Copy it to the output. */
|
||||||
|
brw_reg color_input =
|
||||||
|
brw_make_reg(BRW_GENERAL_REGISTER_FILE, 2, 3, 0, 0, BRW_TYPE_UD,
|
||||||
|
BRW_VERTICAL_STRIDE_8, BRW_WIDTH_2, BRW_HORIZONTAL_STRIDE_4,
|
||||||
|
BRW_SWIZZLE_XYZW, WRITEMASK_XYZW);
|
||||||
|
|
||||||
|
const fs_builder bld = fs_builder(&s).at_end();
|
||||||
|
bld.exec_all().group(4, 0).MOV(color_output, color_input);
|
||||||
|
|
||||||
|
if (key->nr_color_regions > 1) {
|
||||||
|
/* Copy g0..g1 as the message header */
|
||||||
|
bld.exec_all().group(16, 0)
|
||||||
|
.MOV(header, retype(brw_vec8_grf(0, 0), BRW_TYPE_UD));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < key->nr_color_regions; ++i) {
|
||||||
|
if (i > 0)
|
||||||
|
bld.exec_all().group(1, 0).MOV(component(header, 2), brw_imm_ud(i));
|
||||||
|
|
||||||
|
write = bld.emit(SHADER_OPCODE_SEND);
|
||||||
|
write->resize_sources(3);
|
||||||
|
write->sfid = GFX6_SFID_DATAPORT_RENDER_CACHE;
|
||||||
|
write->src[0] = brw_imm_ud(0);
|
||||||
|
write->src[1] = brw_imm_ud(0);
|
||||||
|
write->src[2] = i == 0 ? color_output : header;
|
||||||
|
write->check_tdr = true;
|
||||||
|
write->send_has_side_effects = true;
|
||||||
|
write->desc = brw_fb_write_desc(s.devinfo, i,
|
||||||
|
BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED,
|
||||||
|
i == key->nr_color_regions - 1, false);
|
||||||
|
|
||||||
|
/* We can use a headerless message for the first render target */
|
||||||
|
write->header_size = i == 0 ? 0 : 2;
|
||||||
|
write->mlen = 1 + write->header_size;
|
||||||
|
}
|
||||||
|
write->eot = true;
|
||||||
|
write->last_rt = true;
|
||||||
|
|
||||||
|
s.calculate_cfg();
|
||||||
|
|
||||||
|
s.first_non_payload_grf = s.payload().num_regs;
|
||||||
|
|
||||||
|
brw_fs_lower_scoreboard(s);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turn one of the two CENTROID barycentric modes into PIXEL mode.
|
* Turn one of the two CENTROID barycentric modes into PIXEL mode.
|
||||||
*/
|
*/
|
||||||
@@ -618,6 +1234,189 @@ gfx9_ps_header_only_workaround(struct brw_wm_prog_data *wm_prog_data)
|
|||||||
brw_compute_urb_setup_index(wm_prog_data);
|
brw_compute_urb_setup_index(wm_prog_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
brw_assign_urb_setup(fs_visitor &s)
|
||||||
|
{
|
||||||
|
assert(s.stage == MESA_SHADER_FRAGMENT);
|
||||||
|
|
||||||
|
const struct intel_device_info *devinfo = s.devinfo;
|
||||||
|
struct brw_wm_prog_data *prog_data = brw_wm_prog_data(s.prog_data);
|
||||||
|
|
||||||
|
int urb_start = s.payload().num_regs + prog_data->base.curb_read_length;
|
||||||
|
|
||||||
|
/* Offset all the urb_setup[] index by the actual position of the
|
||||||
|
* setup regs, now that the location of the constants has been chosen.
|
||||||
|
*/
|
||||||
|
foreach_block_and_inst(block, fs_inst, inst, s.cfg) {
|
||||||
|
for (int i = 0; i < inst->sources; i++) {
|
||||||
|
if (inst->src[i].file == ATTR) {
|
||||||
|
/* ATTR brw_reg::nr in the FS is in units of logical scalar
|
||||||
|
* inputs each of which consumes 16B on Gfx4-Gfx12. In
|
||||||
|
* single polygon mode this leads to the following layout
|
||||||
|
* of the vertex setup plane parameters in the ATTR
|
||||||
|
* register file:
|
||||||
|
*
|
||||||
|
* brw_reg::nr Input Comp0 Comp1 Comp2 Comp3
|
||||||
|
* 0 Attr0.x a1-a0 a2-a0 N/A a0
|
||||||
|
* 1 Attr0.y a1-a0 a2-a0 N/A a0
|
||||||
|
* 2 Attr0.z a1-a0 a2-a0 N/A a0
|
||||||
|
* 3 Attr0.w a1-a0 a2-a0 N/A a0
|
||||||
|
* 4 Attr1.x a1-a0 a2-a0 N/A a0
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* In multipolygon mode that no longer works since
|
||||||
|
* different channels may be processing polygons with
|
||||||
|
* different plane parameters, so each parameter above is
|
||||||
|
* represented as a dispatch_width-wide vector:
|
||||||
|
*
|
||||||
|
* brw_reg::nr brw_reg::offset Input Comp0 ... CompN
|
||||||
|
* 0 0 Attr0.x a1[0]-a0[0] ... a1[N]-a0[N]
|
||||||
|
* 0 4 * dispatch_width Attr0.x a2[0]-a0[0] ... a2[N]-a0[N]
|
||||||
|
* 0 8 * dispatch_width Attr0.x N/A ... N/A
|
||||||
|
* 0 12 * dispatch_width Attr0.x a0[0] ... a0[N]
|
||||||
|
* 1 0 Attr0.y a1[0]-a0[0] ... a1[N]-a0[N]
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* Note that many of the components on a single row above
|
||||||
|
* are likely to be replicated multiple times (if, say, a
|
||||||
|
* single SIMD thread is only processing 2 different
|
||||||
|
* polygons), so plane parameters aren't actually stored
|
||||||
|
* in GRF memory with that layout to avoid wasting space.
|
||||||
|
* Instead we compose ATTR register regions with a 2D
|
||||||
|
* region that walks through the parameters of each
|
||||||
|
* polygon with the correct stride, reading the parameter
|
||||||
|
* corresponding to each channel directly from the PS
|
||||||
|
* thread payload.
|
||||||
|
*
|
||||||
|
* The latter layout corresponds to a param_width equal to
|
||||||
|
* dispatch_width, while the former (scalar parameter)
|
||||||
|
* layout has a param_width of 1.
|
||||||
|
*
|
||||||
|
* Gfx20+ represent plane parameters in a format similar
|
||||||
|
* to the above, except the parameters are packed in 12B
|
||||||
|
* and ordered like "a0, a1-a0, a2-a0" instead of the
|
||||||
|
* above vec4 representation with a missing component.
|
||||||
|
*/
|
||||||
|
const unsigned param_width = (s.max_polygons > 1 ? s.dispatch_width : 1);
|
||||||
|
|
||||||
|
/* Size of a single scalar component of a plane parameter
|
||||||
|
* in bytes.
|
||||||
|
*/
|
||||||
|
const unsigned chan_sz = 4;
|
||||||
|
struct brw_reg reg;
|
||||||
|
assert(s.max_polygons > 0);
|
||||||
|
|
||||||
|
/* Calculate the base register on the thread payload of
|
||||||
|
* either the block of vertex setup data or the block of
|
||||||
|
* per-primitive constant data depending on whether we're
|
||||||
|
* accessing a primitive or vertex input. Also calculate
|
||||||
|
* the index of the input within that block.
|
||||||
|
*/
|
||||||
|
const bool per_prim = inst->src[i].nr < prog_data->num_per_primitive_inputs;
|
||||||
|
const unsigned base = urb_start +
|
||||||
|
(per_prim ? 0 :
|
||||||
|
ALIGN(prog_data->num_per_primitive_inputs / 2,
|
||||||
|
reg_unit(devinfo)) * s.max_polygons);
|
||||||
|
const unsigned idx = per_prim ? inst->src[i].nr :
|
||||||
|
inst->src[i].nr - prog_data->num_per_primitive_inputs;
|
||||||
|
|
||||||
|
/* Translate the offset within the param_width-wide
|
||||||
|
* representation described above into an offset and a
|
||||||
|
* grf, which contains the plane parameters for the first
|
||||||
|
* polygon processed by the thread.
|
||||||
|
*/
|
||||||
|
if (devinfo->ver >= 20 && !per_prim) {
|
||||||
|
/* Gfx20+ is able to pack 5 logical input components
|
||||||
|
* per 64B register for vertex setup data.
|
||||||
|
*/
|
||||||
|
const unsigned grf = base + idx / 5 * 2 * s.max_polygons;
|
||||||
|
assert(inst->src[i].offset / param_width < 12);
|
||||||
|
const unsigned delta = idx % 5 * 12 +
|
||||||
|
inst->src[i].offset / (param_width * chan_sz) * chan_sz +
|
||||||
|
inst->src[i].offset % chan_sz;
|
||||||
|
reg = byte_offset(retype(brw_vec8_grf(grf, 0), inst->src[i].type),
|
||||||
|
delta);
|
||||||
|
} else {
|
||||||
|
/* Earlier platforms and per-primitive block pack 2 logical
|
||||||
|
* input components per 32B register.
|
||||||
|
*/
|
||||||
|
const unsigned grf = base + idx / 2 * s.max_polygons;
|
||||||
|
assert(inst->src[i].offset / param_width < REG_SIZE / 2);
|
||||||
|
const unsigned delta = (idx % 2) * (REG_SIZE / 2) +
|
||||||
|
inst->src[i].offset / (param_width * chan_sz) * chan_sz +
|
||||||
|
inst->src[i].offset % chan_sz;
|
||||||
|
reg = byte_offset(retype(brw_vec8_grf(grf, 0), inst->src[i].type),
|
||||||
|
delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.max_polygons > 1) {
|
||||||
|
assert(devinfo->ver >= 12);
|
||||||
|
/* Misaligned channel strides that would lead to
|
||||||
|
* cross-channel access in the representation above are
|
||||||
|
* disallowed.
|
||||||
|
*/
|
||||||
|
assert(inst->src[i].stride * brw_type_size_bytes(inst->src[i].type) == chan_sz);
|
||||||
|
|
||||||
|
/* Number of channels processing the same polygon. */
|
||||||
|
const unsigned poly_width = s.dispatch_width / s.max_polygons;
|
||||||
|
assert(s.dispatch_width % s.max_polygons == 0);
|
||||||
|
|
||||||
|
/* Accessing a subset of channels of a parameter vector
|
||||||
|
* starting from "chan" is necessary to handle
|
||||||
|
* SIMD-lowered instructions though.
|
||||||
|
*/
|
||||||
|
const unsigned chan = inst->src[i].offset %
|
||||||
|
(param_width * chan_sz) / chan_sz;
|
||||||
|
assert(chan < s.dispatch_width);
|
||||||
|
assert(chan % poly_width == 0);
|
||||||
|
const unsigned reg_size = reg_unit(devinfo) * REG_SIZE;
|
||||||
|
reg = byte_offset(reg, chan / poly_width * reg_size);
|
||||||
|
|
||||||
|
if (inst->exec_size > poly_width) {
|
||||||
|
/* Accessing the parameters for multiple polygons.
|
||||||
|
* Corresponding parameters for different polygons
|
||||||
|
* are stored a GRF apart on the thread payload, so
|
||||||
|
* use that as vertical stride.
|
||||||
|
*/
|
||||||
|
const unsigned vstride = reg_size / brw_type_size_bytes(inst->src[i].type);
|
||||||
|
assert(vstride <= 32);
|
||||||
|
assert(chan % poly_width == 0);
|
||||||
|
reg = stride(reg, vstride, poly_width, 0);
|
||||||
|
} else {
|
||||||
|
/* Accessing one parameter for a single polygon --
|
||||||
|
* Translate to a scalar region.
|
||||||
|
*/
|
||||||
|
assert(chan % poly_width + inst->exec_size <= poly_width);
|
||||||
|
reg = stride(reg, 0, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const unsigned width = inst->src[i].stride == 0 ?
|
||||||
|
1 : MIN2(inst->exec_size, 8);
|
||||||
|
reg = stride(reg, width * inst->src[i].stride,
|
||||||
|
width, inst->src[i].stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.abs = inst->src[i].abs;
|
||||||
|
reg.negate = inst->src[i].negate;
|
||||||
|
inst->src[i] = reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Each attribute is 4 setup channels, each of which is half a reg,
|
||||||
|
* but they may be replicated multiple times for multipolygon
|
||||||
|
* dispatch.
|
||||||
|
*/
|
||||||
|
s.first_non_payload_grf += prog_data->num_varying_inputs * 2 * s.max_polygons;
|
||||||
|
|
||||||
|
/* Unlike regular attributes, per-primitive attributes have all 4 channels
|
||||||
|
* in the same slot, so each GRF can store two slots.
|
||||||
|
*/
|
||||||
|
assert(prog_data->num_per_primitive_inputs % 2 == 0);
|
||||||
|
s.first_non_payload_grf += prog_data->num_per_primitive_inputs / 2 * s.max_polygons;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
run_fs(fs_visitor &s, bool allow_spilling, bool do_rep_send)
|
run_fs(fs_visitor &s, bool allow_spilling, bool do_rep_send)
|
||||||
{
|
{
|
||||||
@@ -636,12 +1435,12 @@ run_fs(fs_visitor &s, bool allow_spilling, bool do_rep_send)
|
|||||||
|
|
||||||
if (do_rep_send) {
|
if (do_rep_send) {
|
||||||
assert(s.dispatch_width == 16);
|
assert(s.dispatch_width == 16);
|
||||||
s.emit_repclear_shader();
|
brw_emit_repclear_shader(s);
|
||||||
} else {
|
} else {
|
||||||
if (nir->info.inputs_read > 0 ||
|
if (nir->info.inputs_read > 0 ||
|
||||||
BITSET_TEST(nir->info.system_values_read, SYSTEM_VALUE_FRAG_COORD) ||
|
BITSET_TEST(nir->info.system_values_read, SYSTEM_VALUE_FRAG_COORD) ||
|
||||||
(nir->info.outputs_read > 0 && !wm_key->coherent_fb_fetch)) {
|
(nir->info.outputs_read > 0 && !wm_key->coherent_fb_fetch)) {
|
||||||
s.emit_interpolation_setup();
|
brw_emit_interpolation_setup(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We handle discards by keeping track of the still-live pixels in f0.1.
|
/* We handle discards by keeping track of the still-live pixels in f0.1.
|
||||||
@@ -672,7 +1471,7 @@ run_fs(fs_visitor &s, bool allow_spilling, bool do_rep_send)
|
|||||||
if (s.failed)
|
if (s.failed)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
s.emit_fb_writes();
|
brw_emit_fb_writes(s);
|
||||||
|
|
||||||
s.calculate_cfg();
|
s.calculate_cfg();
|
||||||
|
|
||||||
@@ -683,7 +1482,7 @@ run_fs(fs_visitor &s, bool allow_spilling, bool do_rep_send)
|
|||||||
if (devinfo->ver == 9)
|
if (devinfo->ver == 9)
|
||||||
gfx9_ps_header_only_workaround(wm_prog_data);
|
gfx9_ps_header_only_workaround(wm_prog_data);
|
||||||
|
|
||||||
s.assign_urb_setup();
|
brw_assign_urb_setup(s);
|
||||||
|
|
||||||
brw_fs_lower_3src_null_dest(s);
|
brw_fs_lower_3src_null_dest(s);
|
||||||
brw_fs_workaround_memory_fence_before_eot(s);
|
brw_fs_workaround_memory_fence_before_eot(s);
|
||||||
|
@@ -1354,187 +1354,6 @@ brw_compute_urb_setup_index(struct brw_wm_prog_data *wm_prog_data)
|
|||||||
wm_prog_data->urb_setup_attribs_count = index;
|
wm_prog_data->urb_setup_attribs_count = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
fs_visitor::assign_urb_setup()
|
|
||||||
{
|
|
||||||
assert(stage == MESA_SHADER_FRAGMENT);
|
|
||||||
struct brw_wm_prog_data *prog_data = brw_wm_prog_data(this->prog_data);
|
|
||||||
|
|
||||||
int urb_start = payload().num_regs + prog_data->base.curb_read_length;
|
|
||||||
|
|
||||||
/* Offset all the urb_setup[] index by the actual position of the
|
|
||||||
* setup regs, now that the location of the constants has been chosen.
|
|
||||||
*/
|
|
||||||
foreach_block_and_inst(block, fs_inst, inst, cfg) {
|
|
||||||
for (int i = 0; i < inst->sources; i++) {
|
|
||||||
if (inst->src[i].file == ATTR) {
|
|
||||||
/* ATTR brw_reg::nr in the FS is in units of logical scalar
|
|
||||||
* inputs each of which consumes 16B on Gfx4-Gfx12. In
|
|
||||||
* single polygon mode this leads to the following layout
|
|
||||||
* of the vertex setup plane parameters in the ATTR
|
|
||||||
* register file:
|
|
||||||
*
|
|
||||||
* brw_reg::nr Input Comp0 Comp1 Comp2 Comp3
|
|
||||||
* 0 Attr0.x a1-a0 a2-a0 N/A a0
|
|
||||||
* 1 Attr0.y a1-a0 a2-a0 N/A a0
|
|
||||||
* 2 Attr0.z a1-a0 a2-a0 N/A a0
|
|
||||||
* 3 Attr0.w a1-a0 a2-a0 N/A a0
|
|
||||||
* 4 Attr1.x a1-a0 a2-a0 N/A a0
|
|
||||||
* ...
|
|
||||||
*
|
|
||||||
* In multipolygon mode that no longer works since
|
|
||||||
* different channels may be processing polygons with
|
|
||||||
* different plane parameters, so each parameter above is
|
|
||||||
* represented as a dispatch_width-wide vector:
|
|
||||||
*
|
|
||||||
* brw_reg::nr brw_reg::offset Input Comp0 ... CompN
|
|
||||||
* 0 0 Attr0.x a1[0]-a0[0] ... a1[N]-a0[N]
|
|
||||||
* 0 4 * dispatch_width Attr0.x a2[0]-a0[0] ... a2[N]-a0[N]
|
|
||||||
* 0 8 * dispatch_width Attr0.x N/A ... N/A
|
|
||||||
* 0 12 * dispatch_width Attr0.x a0[0] ... a0[N]
|
|
||||||
* 1 0 Attr0.y a1[0]-a0[0] ... a1[N]-a0[N]
|
|
||||||
* ...
|
|
||||||
*
|
|
||||||
* Note that many of the components on a single row above
|
|
||||||
* are likely to be replicated multiple times (if, say, a
|
|
||||||
* single SIMD thread is only processing 2 different
|
|
||||||
* polygons), so plane parameters aren't actually stored
|
|
||||||
* in GRF memory with that layout to avoid wasting space.
|
|
||||||
* Instead we compose ATTR register regions with a 2D
|
|
||||||
* region that walks through the parameters of each
|
|
||||||
* polygon with the correct stride, reading the parameter
|
|
||||||
* corresponding to each channel directly from the PS
|
|
||||||
* thread payload.
|
|
||||||
*
|
|
||||||
* The latter layout corresponds to a param_width equal to
|
|
||||||
* dispatch_width, while the former (scalar parameter)
|
|
||||||
* layout has a param_width of 1.
|
|
||||||
*
|
|
||||||
* Gfx20+ represent plane parameters in a format similar
|
|
||||||
* to the above, except the parameters are packed in 12B
|
|
||||||
* and ordered like "a0, a1-a0, a2-a0" instead of the
|
|
||||||
* above vec4 representation with a missing component.
|
|
||||||
*/
|
|
||||||
const unsigned param_width = (max_polygons > 1 ? dispatch_width : 1);
|
|
||||||
|
|
||||||
/* Size of a single scalar component of a plane parameter
|
|
||||||
* in bytes.
|
|
||||||
*/
|
|
||||||
const unsigned chan_sz = 4;
|
|
||||||
struct brw_reg reg;
|
|
||||||
assert(max_polygons > 0);
|
|
||||||
|
|
||||||
/* Calculate the base register on the thread payload of
|
|
||||||
* either the block of vertex setup data or the block of
|
|
||||||
* per-primitive constant data depending on whether we're
|
|
||||||
* accessing a primitive or vertex input. Also calculate
|
|
||||||
* the index of the input within that block.
|
|
||||||
*/
|
|
||||||
const bool per_prim = inst->src[i].nr < prog_data->num_per_primitive_inputs;
|
|
||||||
const unsigned base = urb_start +
|
|
||||||
(per_prim ? 0 :
|
|
||||||
ALIGN(prog_data->num_per_primitive_inputs / 2,
|
|
||||||
reg_unit(devinfo)) * max_polygons);
|
|
||||||
const unsigned idx = per_prim ? inst->src[i].nr :
|
|
||||||
inst->src[i].nr - prog_data->num_per_primitive_inputs;
|
|
||||||
|
|
||||||
/* Translate the offset within the param_width-wide
|
|
||||||
* representation described above into an offset and a
|
|
||||||
* grf, which contains the plane parameters for the first
|
|
||||||
* polygon processed by the thread.
|
|
||||||
*/
|
|
||||||
if (devinfo->ver >= 20 && !per_prim) {
|
|
||||||
/* Gfx20+ is able to pack 5 logical input components
|
|
||||||
* per 64B register for vertex setup data.
|
|
||||||
*/
|
|
||||||
const unsigned grf = base + idx / 5 * 2 * max_polygons;
|
|
||||||
assert(inst->src[i].offset / param_width < 12);
|
|
||||||
const unsigned delta = idx % 5 * 12 +
|
|
||||||
inst->src[i].offset / (param_width * chan_sz) * chan_sz +
|
|
||||||
inst->src[i].offset % chan_sz;
|
|
||||||
reg = byte_offset(retype(brw_vec8_grf(grf, 0), inst->src[i].type),
|
|
||||||
delta);
|
|
||||||
} else {
|
|
||||||
/* Earlier platforms and per-primitive block pack 2 logical
|
|
||||||
* input components per 32B register.
|
|
||||||
*/
|
|
||||||
const unsigned grf = base + idx / 2 * max_polygons;
|
|
||||||
assert(inst->src[i].offset / param_width < REG_SIZE / 2);
|
|
||||||
const unsigned delta = (idx % 2) * (REG_SIZE / 2) +
|
|
||||||
inst->src[i].offset / (param_width * chan_sz) * chan_sz +
|
|
||||||
inst->src[i].offset % chan_sz;
|
|
||||||
reg = byte_offset(retype(brw_vec8_grf(grf, 0), inst->src[i].type),
|
|
||||||
delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_polygons > 1) {
|
|
||||||
assert(devinfo->ver >= 12);
|
|
||||||
/* Misaligned channel strides that would lead to
|
|
||||||
* cross-channel access in the representation above are
|
|
||||||
* disallowed.
|
|
||||||
*/
|
|
||||||
assert(inst->src[i].stride * brw_type_size_bytes(inst->src[i].type) == chan_sz);
|
|
||||||
|
|
||||||
/* Number of channels processing the same polygon. */
|
|
||||||
const unsigned poly_width = dispatch_width / max_polygons;
|
|
||||||
assert(dispatch_width % max_polygons == 0);
|
|
||||||
|
|
||||||
/* Accessing a subset of channels of a parameter vector
|
|
||||||
* starting from "chan" is necessary to handle
|
|
||||||
* SIMD-lowered instructions though.
|
|
||||||
*/
|
|
||||||
const unsigned chan = inst->src[i].offset %
|
|
||||||
(param_width * chan_sz) / chan_sz;
|
|
||||||
assert(chan < dispatch_width);
|
|
||||||
assert(chan % poly_width == 0);
|
|
||||||
const unsigned reg_size = reg_unit(devinfo) * REG_SIZE;
|
|
||||||
reg = byte_offset(reg, chan / poly_width * reg_size);
|
|
||||||
|
|
||||||
if (inst->exec_size > poly_width) {
|
|
||||||
/* Accessing the parameters for multiple polygons.
|
|
||||||
* Corresponding parameters for different polygons
|
|
||||||
* are stored a GRF apart on the thread payload, so
|
|
||||||
* use that as vertical stride.
|
|
||||||
*/
|
|
||||||
const unsigned vstride = reg_size / brw_type_size_bytes(inst->src[i].type);
|
|
||||||
assert(vstride <= 32);
|
|
||||||
assert(chan % poly_width == 0);
|
|
||||||
reg = stride(reg, vstride, poly_width, 0);
|
|
||||||
} else {
|
|
||||||
/* Accessing one parameter for a single polygon --
|
|
||||||
* Translate to a scalar region.
|
|
||||||
*/
|
|
||||||
assert(chan % poly_width + inst->exec_size <= poly_width);
|
|
||||||
reg = stride(reg, 0, 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const unsigned width = inst->src[i].stride == 0 ?
|
|
||||||
1 : MIN2(inst->exec_size, 8);
|
|
||||||
reg = stride(reg, width * inst->src[i].stride,
|
|
||||||
width, inst->src[i].stride);
|
|
||||||
}
|
|
||||||
|
|
||||||
reg.abs = inst->src[i].abs;
|
|
||||||
reg.negate = inst->src[i].negate;
|
|
||||||
inst->src[i] = reg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Each attribute is 4 setup channels, each of which is half a reg,
|
|
||||||
* but they may be replicated multiple times for multipolygon
|
|
||||||
* dispatch.
|
|
||||||
*/
|
|
||||||
this->first_non_payload_grf += prog_data->num_varying_inputs * 2 * max_polygons;
|
|
||||||
|
|
||||||
/* Unlike regular attributes, per-primitive attributes have all 4 channels
|
|
||||||
* in the same slot, so each GRF can store two slots.
|
|
||||||
*/
|
|
||||||
assert(prog_data->num_per_primitive_inputs % 2 == 0);
|
|
||||||
this->first_non_payload_grf += prog_data->num_per_primitive_inputs / 2 * max_polygons;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
fs_visitor::convert_attr_sources_to_hw_regs(fs_inst *inst)
|
fs_visitor::convert_attr_sources_to_hw_regs(fs_inst *inst)
|
||||||
{
|
{
|
||||||
@@ -1704,68 +1523,6 @@ fs_visitor::get_pull_locs(const brw_reg &src,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Once we've generated code, try to convert normal FS_OPCODE_FB_WRITE
|
|
||||||
* instructions to FS_OPCODE_REP_FB_WRITE.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
fs_visitor::emit_repclear_shader()
|
|
||||||
{
|
|
||||||
brw_wm_prog_key *key = (brw_wm_prog_key*) this->key;
|
|
||||||
fs_inst *write = NULL;
|
|
||||||
|
|
||||||
assert(devinfo->ver < 20);
|
|
||||||
assert(uniforms == 0);
|
|
||||||
assume(key->nr_color_regions > 0);
|
|
||||||
|
|
||||||
brw_reg color_output = retype(brw_vec4_grf(127, 0), BRW_TYPE_UD);
|
|
||||||
brw_reg header = retype(brw_vec8_grf(125, 0), BRW_TYPE_UD);
|
|
||||||
|
|
||||||
/* We pass the clear color as a flat input. Copy it to the output. */
|
|
||||||
brw_reg color_input =
|
|
||||||
brw_make_reg(BRW_GENERAL_REGISTER_FILE, 2, 3, 0, 0, BRW_TYPE_UD,
|
|
||||||
BRW_VERTICAL_STRIDE_8, BRW_WIDTH_2, BRW_HORIZONTAL_STRIDE_4,
|
|
||||||
BRW_SWIZZLE_XYZW, WRITEMASK_XYZW);
|
|
||||||
|
|
||||||
const fs_builder bld = fs_builder(this).at_end();
|
|
||||||
bld.exec_all().group(4, 0).MOV(color_output, color_input);
|
|
||||||
|
|
||||||
if (key->nr_color_regions > 1) {
|
|
||||||
/* Copy g0..g1 as the message header */
|
|
||||||
bld.exec_all().group(16, 0)
|
|
||||||
.MOV(header, retype(brw_vec8_grf(0, 0), BRW_TYPE_UD));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < key->nr_color_regions; ++i) {
|
|
||||||
if (i > 0)
|
|
||||||
bld.exec_all().group(1, 0).MOV(component(header, 2), brw_imm_ud(i));
|
|
||||||
|
|
||||||
write = bld.emit(SHADER_OPCODE_SEND);
|
|
||||||
write->resize_sources(3);
|
|
||||||
write->sfid = GFX6_SFID_DATAPORT_RENDER_CACHE;
|
|
||||||
write->src[0] = brw_imm_ud(0);
|
|
||||||
write->src[1] = brw_imm_ud(0);
|
|
||||||
write->src[2] = i == 0 ? color_output : header;
|
|
||||||
write->check_tdr = true;
|
|
||||||
write->send_has_side_effects = true;
|
|
||||||
write->desc = brw_fb_write_desc(devinfo, i,
|
|
||||||
BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED,
|
|
||||||
i == key->nr_color_regions - 1, false);
|
|
||||||
|
|
||||||
/* We can use a headerless message for the first render target */
|
|
||||||
write->header_size = i == 0 ? 0 : 2;
|
|
||||||
write->mlen = 1 + write->header_size;
|
|
||||||
}
|
|
||||||
write->eot = true;
|
|
||||||
write->last_rt = true;
|
|
||||||
|
|
||||||
calculate_cfg();
|
|
||||||
|
|
||||||
this->first_non_payload_grf = payload().num_regs;
|
|
||||||
|
|
||||||
brw_fs_lower_scoreboard(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mask of SIMD channels enabled during dispatch and not yet disabled
|
* Get the mask of SIMD channels enabled during dispatch and not yet disabled
|
||||||
* by discard. Due to the layout of the sample mask in the fragment shader
|
* by discard. Due to the layout of the sample mask in the fragment shader
|
||||||
|
@@ -304,7 +304,6 @@ public:
|
|||||||
void allocate_registers(bool allow_spilling);
|
void allocate_registers(bool allow_spilling);
|
||||||
uint32_t compute_max_register_pressure();
|
uint32_t compute_max_register_pressure();
|
||||||
void assign_curb_setup();
|
void assign_curb_setup();
|
||||||
void assign_urb_setup();
|
|
||||||
void convert_attr_sources_to_hw_regs(fs_inst *inst);
|
void convert_attr_sources_to_hw_regs(fs_inst *inst);
|
||||||
void assign_tcs_urb_setup();
|
void assign_tcs_urb_setup();
|
||||||
void assign_tes_urb_setup();
|
void assign_tes_urb_setup();
|
||||||
@@ -327,16 +326,8 @@ public:
|
|||||||
void fail(const char *msg, ...);
|
void fail(const char *msg, ...);
|
||||||
void limit_dispatch_width(unsigned n, const char *msg);
|
void limit_dispatch_width(unsigned n, const char *msg);
|
||||||
|
|
||||||
void emit_repclear_shader();
|
|
||||||
void emit_interpolation_setup();
|
|
||||||
|
|
||||||
void set_tcs_invocation_id();
|
void set_tcs_invocation_id();
|
||||||
|
|
||||||
fs_inst *emit_single_fb_write(const brw::fs_builder &bld,
|
|
||||||
brw_reg color1, brw_reg color2,
|
|
||||||
brw_reg src0_alpha, unsigned components);
|
|
||||||
void do_emit_fb_writes(int nr_color_regions, bool replicate_alpha);
|
|
||||||
void emit_fb_writes();
|
|
||||||
void emit_urb_writes(const brw_reg &gs_vertex_count = brw_reg());
|
void emit_urb_writes(const brw_reg &gs_vertex_count = brw_reg());
|
||||||
void emit_gs_control_data_bits(const brw_reg &vertex_count);
|
void emit_gs_control_data_bits(const brw_reg &vertex_count);
|
||||||
brw_reg gs_urb_channel_mask(const brw_reg &dword_index);
|
brw_reg gs_urb_channel_mask(const brw_reg &dword_index);
|
||||||
|
@@ -115,555 +115,6 @@ fs_visitor::per_primitive_reg(const fs_builder &bld, int location, unsigned comp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Emits the interpolation for the varying inputs. */
|
|
||||||
void
|
|
||||||
fs_visitor::emit_interpolation_setup()
|
|
||||||
{
|
|
||||||
const fs_builder bld = fs_builder(this).at_end();
|
|
||||||
fs_builder abld = bld.annotate("compute pixel centers");
|
|
||||||
|
|
||||||
this->pixel_x = bld.vgrf(BRW_TYPE_F);
|
|
||||||
this->pixel_y = bld.vgrf(BRW_TYPE_F);
|
|
||||||
|
|
||||||
const struct brw_wm_prog_key *wm_key = (brw_wm_prog_key*) this->key;
|
|
||||||
struct brw_wm_prog_data *wm_prog_data = brw_wm_prog_data(prog_data);
|
|
||||||
|
|
||||||
brw_reg int_sample_offset_x, int_sample_offset_y; /* Used on Gen12HP+ */
|
|
||||||
brw_reg int_sample_offset_xy; /* Used on Gen8+ */
|
|
||||||
brw_reg half_int_sample_offset_x, half_int_sample_offset_y;
|
|
||||||
if (wm_prog_data->coarse_pixel_dispatch != BRW_ALWAYS) {
|
|
||||||
/* The thread payload only delivers subspan locations (ss0, ss1,
|
|
||||||
* ss2, ...). Since subspans covers 2x2 pixels blocks, we need to
|
|
||||||
* generate 4 pixel coordinates out of each subspan location. We do this
|
|
||||||
* by replicating a subspan coordinate 4 times and adding an offset of 1
|
|
||||||
* in each direction from the initial top left (tl) location to generate
|
|
||||||
* top right (tr = +1 in x), bottom left (bl = +1 in y) and bottom right
|
|
||||||
* (br = +1 in x, +1 in y).
|
|
||||||
*
|
|
||||||
* The locations we build look like this in SIMD8 :
|
|
||||||
*
|
|
||||||
* ss0.tl ss0.tr ss0.bl ss0.br ss1.tl ss1.tr ss1.bl ss1.br
|
|
||||||
*
|
|
||||||
* The value 0x11001010 is a vector of 8 half byte vector. It adds
|
|
||||||
* following to generate the 4 pixels coordinates out of the subspan0:
|
|
||||||
*
|
|
||||||
* 0x
|
|
||||||
* 1 : ss0.y + 1 -> ss0.br.y
|
|
||||||
* 1 : ss0.y + 1 -> ss0.bl.y
|
|
||||||
* 0 : ss0.y + 0 -> ss0.tr.y
|
|
||||||
* 0 : ss0.y + 0 -> ss0.tl.y
|
|
||||||
* 1 : ss0.x + 1 -> ss0.br.x
|
|
||||||
* 0 : ss0.x + 0 -> ss0.bl.x
|
|
||||||
* 1 : ss0.x + 1 -> ss0.tr.x
|
|
||||||
* 0 : ss0.x + 0 -> ss0.tl.x
|
|
||||||
*
|
|
||||||
* By doing a SIMD16 add in a SIMD8 shader, we can generate the 8 pixels
|
|
||||||
* coordinates out of 2 subspans coordinates in a single ADD instruction
|
|
||||||
* (twice the operation above).
|
|
||||||
*/
|
|
||||||
int_sample_offset_xy = brw_reg(brw_imm_v(0x11001010));
|
|
||||||
half_int_sample_offset_x = brw_reg(brw_imm_uw(0));
|
|
||||||
half_int_sample_offset_y = brw_reg(brw_imm_uw(0));
|
|
||||||
/* On Gfx12.5, because of regioning restrictions, the interpolation code
|
|
||||||
* is slightly different and works off X & Y only inputs. The ordering
|
|
||||||
* of the half bytes here is a bit odd, with each subspan replicated
|
|
||||||
* twice and every other element is discarded :
|
|
||||||
*
|
|
||||||
* ss0.tl ss0.tl ss0.tr ss0.tr ss0.bl ss0.bl ss0.br ss0.br
|
|
||||||
* X offset: 0 0 1 0 0 0 1 0
|
|
||||||
* Y offset: 0 0 0 0 1 0 1 0
|
|
||||||
*/
|
|
||||||
int_sample_offset_x = brw_reg(brw_imm_v(0x01000100));
|
|
||||||
int_sample_offset_y = brw_reg(brw_imm_v(0x01010000));
|
|
||||||
}
|
|
||||||
|
|
||||||
brw_reg int_coarse_offset_x, int_coarse_offset_y; /* Used on Gen12HP+ */
|
|
||||||
brw_reg int_coarse_offset_xy; /* Used on Gen8+ */
|
|
||||||
brw_reg half_int_coarse_offset_x, half_int_coarse_offset_y;
|
|
||||||
if (wm_prog_data->coarse_pixel_dispatch != BRW_NEVER) {
|
|
||||||
/* In coarse pixel dispatch we have to do the same ADD instruction that
|
|
||||||
* we do in normal per pixel dispatch, except this time we're not adding
|
|
||||||
* 1 in each direction, but instead the coarse pixel size.
|
|
||||||
*
|
|
||||||
* The coarse pixel size is delivered as 2 u8 in r1.0
|
|
||||||
*/
|
|
||||||
struct brw_reg r1_0 = retype(brw_vec1_reg(BRW_GENERAL_REGISTER_FILE, 1, 0), BRW_TYPE_UB);
|
|
||||||
|
|
||||||
const fs_builder dbld =
|
|
||||||
abld.exec_all().group(MIN2(16, dispatch_width) * 2, 0);
|
|
||||||
|
|
||||||
if (devinfo->verx10 >= 125) {
|
|
||||||
/* To build the array of half bytes we do and AND operation with the
|
|
||||||
* right mask in X.
|
|
||||||
*/
|
|
||||||
int_coarse_offset_x = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
dbld.AND(int_coarse_offset_x, byte_offset(r1_0, 0), brw_imm_v(0x0f000f00));
|
|
||||||
|
|
||||||
/* And the right mask in Y. */
|
|
||||||
int_coarse_offset_y = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
dbld.AND(int_coarse_offset_y, byte_offset(r1_0, 1), brw_imm_v(0x0f0f0000));
|
|
||||||
} else {
|
|
||||||
/* To build the array of half bytes we do and AND operation with the
|
|
||||||
* right mask in X.
|
|
||||||
*/
|
|
||||||
int_coarse_offset_x = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
dbld.AND(int_coarse_offset_x, byte_offset(r1_0, 0), brw_imm_v(0x0000f0f0));
|
|
||||||
|
|
||||||
/* And the right mask in Y. */
|
|
||||||
int_coarse_offset_y = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
dbld.AND(int_coarse_offset_y, byte_offset(r1_0, 1), brw_imm_v(0xff000000));
|
|
||||||
|
|
||||||
/* Finally OR the 2 registers. */
|
|
||||||
int_coarse_offset_xy = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
dbld.OR(int_coarse_offset_xy, int_coarse_offset_x, int_coarse_offset_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Also compute the half coarse size used to center coarses. */
|
|
||||||
half_int_coarse_offset_x = bld.vgrf(BRW_TYPE_UW);
|
|
||||||
half_int_coarse_offset_y = bld.vgrf(BRW_TYPE_UW);
|
|
||||||
|
|
||||||
bld.SHR(half_int_coarse_offset_x, suboffset(r1_0, 0), brw_imm_ud(1));
|
|
||||||
bld.SHR(half_int_coarse_offset_y, suboffset(r1_0, 1), brw_imm_ud(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
brw_reg int_pixel_offset_x, int_pixel_offset_y; /* Used on Gen12HP+ */
|
|
||||||
brw_reg int_pixel_offset_xy; /* Used on Gen8+ */
|
|
||||||
brw_reg half_int_pixel_offset_x, half_int_pixel_offset_y;
|
|
||||||
switch (wm_prog_data->coarse_pixel_dispatch) {
|
|
||||||
case BRW_NEVER:
|
|
||||||
int_pixel_offset_x = int_sample_offset_x;
|
|
||||||
int_pixel_offset_y = int_sample_offset_y;
|
|
||||||
int_pixel_offset_xy = int_sample_offset_xy;
|
|
||||||
half_int_pixel_offset_x = half_int_sample_offset_x;
|
|
||||||
half_int_pixel_offset_y = half_int_sample_offset_y;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BRW_SOMETIMES: {
|
|
||||||
const fs_builder dbld =
|
|
||||||
abld.exec_all().group(MIN2(16, dispatch_width) * 2, 0);
|
|
||||||
|
|
||||||
check_dynamic_msaa_flag(dbld, wm_prog_data,
|
|
||||||
INTEL_MSAA_FLAG_COARSE_RT_WRITES);
|
|
||||||
|
|
||||||
int_pixel_offset_x = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
set_predicate(BRW_PREDICATE_NORMAL,
|
|
||||||
dbld.SEL(int_pixel_offset_x,
|
|
||||||
int_coarse_offset_x,
|
|
||||||
int_sample_offset_x));
|
|
||||||
|
|
||||||
int_pixel_offset_y = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
set_predicate(BRW_PREDICATE_NORMAL,
|
|
||||||
dbld.SEL(int_pixel_offset_y,
|
|
||||||
int_coarse_offset_y,
|
|
||||||
int_sample_offset_y));
|
|
||||||
|
|
||||||
int_pixel_offset_xy = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
set_predicate(BRW_PREDICATE_NORMAL,
|
|
||||||
dbld.SEL(int_pixel_offset_xy,
|
|
||||||
int_coarse_offset_xy,
|
|
||||||
int_sample_offset_xy));
|
|
||||||
|
|
||||||
half_int_pixel_offset_x = bld.vgrf(BRW_TYPE_UW);
|
|
||||||
set_predicate(BRW_PREDICATE_NORMAL,
|
|
||||||
bld.SEL(half_int_pixel_offset_x,
|
|
||||||
half_int_coarse_offset_x,
|
|
||||||
half_int_sample_offset_x));
|
|
||||||
|
|
||||||
half_int_pixel_offset_y = bld.vgrf(BRW_TYPE_UW);
|
|
||||||
set_predicate(BRW_PREDICATE_NORMAL,
|
|
||||||
bld.SEL(half_int_pixel_offset_y,
|
|
||||||
half_int_coarse_offset_y,
|
|
||||||
half_int_sample_offset_y));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case BRW_ALWAYS:
|
|
||||||
int_pixel_offset_x = int_coarse_offset_x;
|
|
||||||
int_pixel_offset_y = int_coarse_offset_y;
|
|
||||||
int_pixel_offset_xy = int_coarse_offset_xy;
|
|
||||||
half_int_pixel_offset_x = half_int_coarse_offset_x;
|
|
||||||
half_int_pixel_offset_y = half_int_coarse_offset_y;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < DIV_ROUND_UP(dispatch_width, 16); i++) {
|
|
||||||
const fs_builder hbld = abld.group(MIN2(16, dispatch_width), i);
|
|
||||||
/* According to the "PS Thread Payload for Normal Dispatch"
|
|
||||||
* pages on the BSpec, subspan X/Y coordinates are stored in
|
|
||||||
* R1.2-R1.5/R2.2-R2.5 on gfx6+, and on R0.10-R0.13/R1.10-R1.13
|
|
||||||
* on gfx20+. gi_reg is the 32B section of the GRF that
|
|
||||||
* contains the subspan coordinates.
|
|
||||||
*/
|
|
||||||
const struct brw_reg gi_reg = devinfo->ver >= 20 ? xe2_vec1_grf(i, 8) :
|
|
||||||
brw_vec1_grf(i + 1, 0);
|
|
||||||
const struct brw_reg gi_uw = retype(gi_reg, BRW_TYPE_UW);
|
|
||||||
|
|
||||||
if (devinfo->verx10 >= 125) {
|
|
||||||
const fs_builder dbld =
|
|
||||||
abld.exec_all().group(hbld.dispatch_width() * 2, 0);
|
|
||||||
const brw_reg int_pixel_x = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
const brw_reg int_pixel_y = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
|
|
||||||
dbld.ADD(int_pixel_x,
|
|
||||||
brw_reg(stride(suboffset(gi_uw, 4), 2, 8, 0)),
|
|
||||||
int_pixel_offset_x);
|
|
||||||
dbld.ADD(int_pixel_y,
|
|
||||||
brw_reg(stride(suboffset(gi_uw, 5), 2, 8, 0)),
|
|
||||||
int_pixel_offset_y);
|
|
||||||
|
|
||||||
if (wm_prog_data->coarse_pixel_dispatch != BRW_NEVER) {
|
|
||||||
fs_inst *addx = dbld.ADD(int_pixel_x, int_pixel_x,
|
|
||||||
horiz_stride(half_int_pixel_offset_x, 0));
|
|
||||||
fs_inst *addy = dbld.ADD(int_pixel_y, int_pixel_y,
|
|
||||||
horiz_stride(half_int_pixel_offset_y, 0));
|
|
||||||
if (wm_prog_data->coarse_pixel_dispatch != BRW_ALWAYS) {
|
|
||||||
addx->predicate = BRW_PREDICATE_NORMAL;
|
|
||||||
addy->predicate = BRW_PREDICATE_NORMAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hbld.MOV(offset(pixel_x, hbld, i), horiz_stride(int_pixel_x, 2));
|
|
||||||
hbld.MOV(offset(pixel_y, hbld, i), horiz_stride(int_pixel_y, 2));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* The "Register Region Restrictions" page says for BDW (and newer,
|
|
||||||
* presumably):
|
|
||||||
*
|
|
||||||
* "When destination spans two registers, the source may be one or
|
|
||||||
* two registers. The destination elements must be evenly split
|
|
||||||
* between the two registers."
|
|
||||||
*
|
|
||||||
* Thus we can do a single add(16) in SIMD8 or an add(32) in SIMD16
|
|
||||||
* to compute our pixel centers.
|
|
||||||
*/
|
|
||||||
const fs_builder dbld =
|
|
||||||
abld.exec_all().group(hbld.dispatch_width() * 2, 0);
|
|
||||||
brw_reg int_pixel_xy = dbld.vgrf(BRW_TYPE_UW);
|
|
||||||
|
|
||||||
dbld.ADD(int_pixel_xy,
|
|
||||||
brw_reg(stride(suboffset(gi_uw, 4), 1, 4, 0)),
|
|
||||||
int_pixel_offset_xy);
|
|
||||||
|
|
||||||
hbld.emit(FS_OPCODE_PIXEL_X, offset(pixel_x, hbld, i), int_pixel_xy,
|
|
||||||
horiz_stride(half_int_pixel_offset_x, 0));
|
|
||||||
hbld.emit(FS_OPCODE_PIXEL_Y, offset(pixel_y, hbld, i), int_pixel_xy,
|
|
||||||
horiz_stride(half_int_pixel_offset_y, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abld = bld.annotate("compute pos.z");
|
|
||||||
brw_reg coarse_z;
|
|
||||||
if (wm_prog_data->coarse_pixel_dispatch != BRW_NEVER &&
|
|
||||||
wm_prog_data->uses_depth_w_coefficients) {
|
|
||||||
/* In coarse pixel mode, the HW doesn't interpolate Z coordinate
|
|
||||||
* properly. In the same way we have to add the coarse pixel size to
|
|
||||||
* pixels locations, here we recompute the Z value with 2 coefficients
|
|
||||||
* in X & Y axis.
|
|
||||||
*/
|
|
||||||
brw_reg coef_payload = brw_vec8_grf(fs_payload().depth_w_coef_reg, 0);
|
|
||||||
const brw_reg x_start = brw_vec1_grf(coef_payload.nr, 2);
|
|
||||||
const brw_reg y_start = brw_vec1_grf(coef_payload.nr, 6);
|
|
||||||
const brw_reg z_cx = brw_vec1_grf(coef_payload.nr, 1);
|
|
||||||
const brw_reg z_cy = brw_vec1_grf(coef_payload.nr, 0);
|
|
||||||
const brw_reg z_c0 = brw_vec1_grf(coef_payload.nr, 3);
|
|
||||||
|
|
||||||
const brw_reg float_pixel_x = abld.vgrf(BRW_TYPE_F);
|
|
||||||
const brw_reg float_pixel_y = abld.vgrf(BRW_TYPE_F);
|
|
||||||
|
|
||||||
abld.ADD(float_pixel_x, this->pixel_x, negate(x_start));
|
|
||||||
abld.ADD(float_pixel_y, this->pixel_y, negate(y_start));
|
|
||||||
|
|
||||||
/* r1.0 - 0:7 ActualCoarsePixelShadingSize.X */
|
|
||||||
const brw_reg u8_cps_width = brw_reg(retype(brw_vec1_grf(1, 0), BRW_TYPE_UB));
|
|
||||||
/* r1.0 - 15:8 ActualCoarsePixelShadingSize.Y */
|
|
||||||
const brw_reg u8_cps_height = byte_offset(u8_cps_width, 1);
|
|
||||||
const brw_reg u32_cps_width = abld.vgrf(BRW_TYPE_UD);
|
|
||||||
const brw_reg u32_cps_height = abld.vgrf(BRW_TYPE_UD);
|
|
||||||
abld.MOV(u32_cps_width, u8_cps_width);
|
|
||||||
abld.MOV(u32_cps_height, u8_cps_height);
|
|
||||||
|
|
||||||
const brw_reg f_cps_width = abld.vgrf(BRW_TYPE_F);
|
|
||||||
const brw_reg f_cps_height = abld.vgrf(BRW_TYPE_F);
|
|
||||||
abld.MOV(f_cps_width, u32_cps_width);
|
|
||||||
abld.MOV(f_cps_height, u32_cps_height);
|
|
||||||
|
|
||||||
/* Center in the middle of the coarse pixel. */
|
|
||||||
abld.MAD(float_pixel_x, float_pixel_x, brw_imm_f(0.5f), f_cps_width);
|
|
||||||
abld.MAD(float_pixel_y, float_pixel_y, brw_imm_f(0.5f), f_cps_height);
|
|
||||||
|
|
||||||
coarse_z = abld.vgrf(BRW_TYPE_F);
|
|
||||||
abld.MAD(coarse_z, z_c0, z_cx, float_pixel_x);
|
|
||||||
abld.MAD(coarse_z, coarse_z, z_cy, float_pixel_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wm_prog_data->uses_src_depth)
|
|
||||||
this->pixel_z = fetch_payload_reg(bld, fs_payload().source_depth_reg);
|
|
||||||
|
|
||||||
if (wm_prog_data->uses_depth_w_coefficients ||
|
|
||||||
wm_prog_data->uses_src_depth) {
|
|
||||||
brw_reg sample_z = this->pixel_z;
|
|
||||||
|
|
||||||
switch (wm_prog_data->coarse_pixel_dispatch) {
|
|
||||||
case BRW_NEVER:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BRW_SOMETIMES:
|
|
||||||
assert(wm_prog_data->uses_src_depth);
|
|
||||||
assert(wm_prog_data->uses_depth_w_coefficients);
|
|
||||||
this->pixel_z = abld.vgrf(BRW_TYPE_F);
|
|
||||||
|
|
||||||
/* We re-use the check_dynamic_msaa_flag() call from above */
|
|
||||||
set_predicate(BRW_PREDICATE_NORMAL,
|
|
||||||
abld.SEL(this->pixel_z, coarse_z, sample_z));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BRW_ALWAYS:
|
|
||||||
assert(!wm_prog_data->uses_src_depth);
|
|
||||||
assert(wm_prog_data->uses_depth_w_coefficients);
|
|
||||||
this->pixel_z = coarse_z;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wm_prog_data->uses_src_w) {
|
|
||||||
abld = bld.annotate("compute pos.w");
|
|
||||||
this->pixel_w = fetch_payload_reg(abld, fs_payload().source_w_reg);
|
|
||||||
this->wpos_w = bld.vgrf(BRW_TYPE_F);
|
|
||||||
abld.emit(SHADER_OPCODE_RCP, this->wpos_w, this->pixel_w);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wm_key->persample_interp == BRW_SOMETIMES) {
|
|
||||||
assert(!devinfo->needs_unlit_centroid_workaround);
|
|
||||||
|
|
||||||
const fs_builder ubld = bld.exec_all().group(16, 0);
|
|
||||||
bool loaded_flag = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < BRW_BARYCENTRIC_MODE_COUNT; ++i) {
|
|
||||||
if (!(wm_prog_data->barycentric_interp_modes & BITFIELD_BIT(i)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* The sample mode will always be the top bit set in the perspective
|
|
||||||
* or non-perspective section. In the case where no SAMPLE mode was
|
|
||||||
* requested, wm_prog_data_barycentric_modes() will swap out the top
|
|
||||||
* mode for SAMPLE so this works regardless of whether SAMPLE was
|
|
||||||
* requested or not.
|
|
||||||
*/
|
|
||||||
int sample_mode;
|
|
||||||
if (BITFIELD_BIT(i) & BRW_BARYCENTRIC_NONPERSPECTIVE_BITS) {
|
|
||||||
sample_mode = util_last_bit(wm_prog_data->barycentric_interp_modes &
|
|
||||||
BRW_BARYCENTRIC_NONPERSPECTIVE_BITS) - 1;
|
|
||||||
} else {
|
|
||||||
sample_mode = util_last_bit(wm_prog_data->barycentric_interp_modes &
|
|
||||||
BRW_BARYCENTRIC_PERSPECTIVE_BITS) - 1;
|
|
||||||
}
|
|
||||||
assert(wm_prog_data->barycentric_interp_modes &
|
|
||||||
BITFIELD_BIT(sample_mode));
|
|
||||||
|
|
||||||
if (i == sample_mode)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
uint8_t *barys = fs_payload().barycentric_coord_reg[i];
|
|
||||||
|
|
||||||
uint8_t *sample_barys = fs_payload().barycentric_coord_reg[sample_mode];
|
|
||||||
assert(barys[0] && sample_barys[0]);
|
|
||||||
|
|
||||||
if (!loaded_flag) {
|
|
||||||
check_dynamic_msaa_flag(ubld, wm_prog_data,
|
|
||||||
INTEL_MSAA_FLAG_PERSAMPLE_INTERP);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (unsigned j = 0; j < dispatch_width / 8; j++) {
|
|
||||||
set_predicate(
|
|
||||||
BRW_PREDICATE_NORMAL,
|
|
||||||
ubld.MOV(brw_vec8_grf(barys[j / 2] + (j % 2) * 2, 0),
|
|
||||||
brw_vec8_grf(sample_barys[j / 2] + (j % 2) * 2, 0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < BRW_BARYCENTRIC_MODE_COUNT; ++i) {
|
|
||||||
this->delta_xy[i] = fetch_barycentric_reg(
|
|
||||||
bld, fs_payload().barycentric_coord_reg[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t centroid_modes = wm_prog_data->barycentric_interp_modes &
|
|
||||||
(1 << BRW_BARYCENTRIC_PERSPECTIVE_CENTROID |
|
|
||||||
1 << BRW_BARYCENTRIC_NONPERSPECTIVE_CENTROID);
|
|
||||||
|
|
||||||
if (devinfo->needs_unlit_centroid_workaround && centroid_modes) {
|
|
||||||
/* Get the pixel/sample mask into f0 so that we know which
|
|
||||||
* pixels are lit. Then, for each channel that is unlit,
|
|
||||||
* replace the centroid data with non-centroid data.
|
|
||||||
*/
|
|
||||||
for (unsigned i = 0; i < DIV_ROUND_UP(dispatch_width, 16); i++) {
|
|
||||||
bld.exec_all().group(1, 0)
|
|
||||||
.MOV(retype(brw_flag_reg(0, i), BRW_TYPE_UW),
|
|
||||||
retype(brw_vec1_grf(1 + i, 7), BRW_TYPE_UW));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < BRW_BARYCENTRIC_MODE_COUNT; ++i) {
|
|
||||||
if (!(centroid_modes & (1 << i)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const brw_reg centroid_delta_xy = delta_xy[i];
|
|
||||||
const brw_reg &pixel_delta_xy = delta_xy[i - 1];
|
|
||||||
|
|
||||||
delta_xy[i] = bld.vgrf(BRW_TYPE_F, 2);
|
|
||||||
|
|
||||||
for (unsigned c = 0; c < 2; c++) {
|
|
||||||
for (unsigned q = 0; q < dispatch_width / 8; q++) {
|
|
||||||
set_predicate(BRW_PREDICATE_NORMAL,
|
|
||||||
bld.quarter(q).SEL(
|
|
||||||
quarter(offset(delta_xy[i], bld, c), q),
|
|
||||||
quarter(offset(centroid_delta_xy, bld, c), q),
|
|
||||||
quarter(offset(pixel_delta_xy, bld, c), q)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fs_inst *
|
|
||||||
fs_visitor::emit_single_fb_write(const fs_builder &bld,
|
|
||||||
brw_reg color0, brw_reg color1,
|
|
||||||
brw_reg src0_alpha, unsigned components)
|
|
||||||
{
|
|
||||||
assert(stage == MESA_SHADER_FRAGMENT);
|
|
||||||
struct brw_wm_prog_data *prog_data = brw_wm_prog_data(this->prog_data);
|
|
||||||
|
|
||||||
/* Hand over gl_FragDepth or the payload depth. */
|
|
||||||
const brw_reg dst_depth = fetch_payload_reg(bld, fs_payload().dest_depth_reg);
|
|
||||||
brw_reg src_depth, src_stencil;
|
|
||||||
|
|
||||||
if (nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH))
|
|
||||||
src_depth = frag_depth;
|
|
||||||
|
|
||||||
if (nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_STENCIL))
|
|
||||||
src_stencil = frag_stencil;
|
|
||||||
|
|
||||||
const brw_reg sources[] = {
|
|
||||||
color0, color1, src0_alpha, src_depth, dst_depth, src_stencil,
|
|
||||||
(prog_data->uses_omask ? sample_mask : brw_reg()),
|
|
||||||
brw_imm_ud(components)
|
|
||||||
};
|
|
||||||
assert(ARRAY_SIZE(sources) - 1 == FB_WRITE_LOGICAL_SRC_COMPONENTS);
|
|
||||||
fs_inst *write = bld.emit(FS_OPCODE_FB_WRITE_LOGICAL, brw_reg(),
|
|
||||||
sources, ARRAY_SIZE(sources));
|
|
||||||
|
|
||||||
if (prog_data->uses_kill) {
|
|
||||||
write->predicate = BRW_PREDICATE_NORMAL;
|
|
||||||
write->flag_subreg = sample_mask_flag_subreg(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return write;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fs_visitor::do_emit_fb_writes(int nr_color_regions, bool replicate_alpha)
|
|
||||||
{
|
|
||||||
const fs_builder bld = fs_builder(this).at_end();
|
|
||||||
fs_inst *inst = NULL;
|
|
||||||
|
|
||||||
for (int target = 0; target < nr_color_regions; target++) {
|
|
||||||
/* Skip over outputs that weren't written. */
|
|
||||||
if (this->outputs[target].file == BAD_FILE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const fs_builder abld = bld.annotate(
|
|
||||||
ralloc_asprintf(this->mem_ctx, "FB write target %d", target));
|
|
||||||
|
|
||||||
brw_reg src0_alpha;
|
|
||||||
if (replicate_alpha && target != 0)
|
|
||||||
src0_alpha = offset(outputs[0], bld, 3);
|
|
||||||
|
|
||||||
inst = emit_single_fb_write(abld, this->outputs[target],
|
|
||||||
this->dual_src_output, src0_alpha, 4);
|
|
||||||
inst->target = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inst == NULL) {
|
|
||||||
/* Even if there's no color buffers enabled, we still need to send
|
|
||||||
* alpha out the pipeline to our null renderbuffer to support
|
|
||||||
* alpha-testing, alpha-to-coverage, and so on.
|
|
||||||
*/
|
|
||||||
/* FINISHME: Factor out this frequently recurring pattern into a
|
|
||||||
* helper function.
|
|
||||||
*/
|
|
||||||
const brw_reg srcs[] = { reg_undef, reg_undef,
|
|
||||||
reg_undef, offset(this->outputs[0], bld, 3) };
|
|
||||||
const brw_reg tmp = bld.vgrf(BRW_TYPE_UD, 4);
|
|
||||||
bld.LOAD_PAYLOAD(tmp, srcs, 4, 0);
|
|
||||||
|
|
||||||
inst = emit_single_fb_write(bld, tmp, reg_undef, reg_undef, 4);
|
|
||||||
inst->target = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inst->last_rt = true;
|
|
||||||
inst->eot = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
fs_visitor::emit_fb_writes()
|
|
||||||
{
|
|
||||||
assert(stage == MESA_SHADER_FRAGMENT);
|
|
||||||
struct brw_wm_prog_data *prog_data = brw_wm_prog_data(this->prog_data);
|
|
||||||
brw_wm_prog_key *key = (brw_wm_prog_key*) this->key;
|
|
||||||
|
|
||||||
if (nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) {
|
|
||||||
/* From the 'Render Target Write message' section of the docs:
|
|
||||||
* "Output Stencil is not supported with SIMD16 Render Target Write
|
|
||||||
* Messages."
|
|
||||||
*/
|
|
||||||
if (devinfo->ver >= 20)
|
|
||||||
limit_dispatch_width(16, "gl_FragStencilRefARB unsupported "
|
|
||||||
"in SIMD32+ mode.\n");
|
|
||||||
else
|
|
||||||
limit_dispatch_width(8, "gl_FragStencilRefARB unsupported "
|
|
||||||
"in SIMD16+ mode.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ANV doesn't know about sample mask output during the wm key creation
|
|
||||||
* so we compute if we need replicate alpha and emit alpha to coverage
|
|
||||||
* workaround here.
|
|
||||||
*/
|
|
||||||
const bool replicate_alpha = key->alpha_test_replicate_alpha ||
|
|
||||||
(key->nr_color_regions > 1 && key->alpha_to_coverage &&
|
|
||||||
sample_mask.file == BAD_FILE);
|
|
||||||
|
|
||||||
prog_data->dual_src_blend = (this->dual_src_output.file != BAD_FILE &&
|
|
||||||
this->outputs[0].file != BAD_FILE);
|
|
||||||
assert(!prog_data->dual_src_blend || key->nr_color_regions == 1);
|
|
||||||
|
|
||||||
/* Following condition implements Wa_14017468336:
|
|
||||||
*
|
|
||||||
* "If dual source blend is enabled do not enable SIMD32 dispatch" and
|
|
||||||
* "For a thread dispatched as SIMD32, must not issue SIMD8 message with Last
|
|
||||||
* Render Target Select set."
|
|
||||||
*/
|
|
||||||
if (devinfo->ver >= 11 && devinfo->ver <= 12 &&
|
|
||||||
prog_data->dual_src_blend) {
|
|
||||||
/* The dual-source RT write messages fail to release the thread
|
|
||||||
* dependency on ICL and TGL with SIMD32 dispatch, leading to hangs.
|
|
||||||
*
|
|
||||||
* XXX - Emit an extra single-source NULL RT-write marked LastRT in
|
|
||||||
* order to release the thread dependency without disabling
|
|
||||||
* SIMD32.
|
|
||||||
*
|
|
||||||
* The dual-source RT write messages may lead to hangs with SIMD16
|
|
||||||
* dispatch on ICL due some unknown reasons, see
|
|
||||||
* https://gitlab.freedesktop.org/mesa/mesa/-/issues/2183
|
|
||||||
*/
|
|
||||||
if (devinfo->ver >= 20)
|
|
||||||
limit_dispatch_width(16, "Dual source blending unsupported "
|
|
||||||
"in SIMD32 mode.\n");
|
|
||||||
else
|
|
||||||
limit_dispatch_width(8, "Dual source blending unsupported "
|
|
||||||
"in SIMD16 and SIMD32 modes.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
do_emit_fb_writes(key->nr_color_regions, replicate_alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
fs_visitor::emit_urb_writes(const brw_reg &gs_vertex_count)
|
fs_visitor::emit_urb_writes(const brw_reg &gs_vertex_count)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user