if (brw->gen >= 5 || brw->is_g4x)
ctx->Const.MaxClipPlanes = 8;
- ctx->Const.LowerTessLevel = true;
+ ctx->Const.GLSLTessLevelsAsInputs = true;
ctx->Const.LowerTCSPatchVerticesIn = brw->gen >= 8;
ctx->Const.LowerTESPatchVerticesIn = true;
ctx->Const.PrimitiveRestartForPatches = true;
bld.MOV(patch_handle,
retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_UD));
- if (imm_offset == 0) {
- /* This is a read of gl_TessLevelInner[], which lives in the
- * Patch URB header. The layout depends on the domain.
- */
- dst.type = BRW_REGISTER_TYPE_F;
- switch (tcs_key->tes_primitive_mode) {
- case GL_QUADS: {
- /* DWords 3-2 (reversed) */
- fs_reg tmp = bld.vgrf(BRW_REGISTER_TYPE_F, 4);
-
- inst = bld.emit(SHADER_OPCODE_URB_READ_SIMD8, tmp, patch_handle);
- inst->offset = 0;
- inst->mlen = 1;
- inst->size_written = 4 * REG_SIZE;
-
- /* dst.xy = tmp.wz */
- bld.MOV(dst, offset(tmp, bld, 3));
- bld.MOV(offset(dst, bld, 1), offset(tmp, bld, 2));
- break;
- }
- case GL_TRIANGLES:
- /* DWord 4; hardcode offset = 1 and size_written = REG_SIZE */
- inst = bld.emit(SHADER_OPCODE_URB_READ_SIMD8, dst, patch_handle);
- inst->offset = 1;
- inst->mlen = 1;
- inst->size_written = REG_SIZE;
- break;
- case GL_ISOLINES:
- /* All channels are undefined. */
- break;
- default:
- unreachable("Bogus tessellation domain");
- }
- } else if (imm_offset == 1) {
- /* This is a read of gl_TessLevelOuter[], which lives in the
- * Patch URB header. The layout depends on the domain.
- */
- dst.type = BRW_REGISTER_TYPE_F;
-
- fs_reg tmp = bld.vgrf(BRW_REGISTER_TYPE_F, 4);
- inst = bld.emit(SHADER_OPCODE_URB_READ_SIMD8, tmp, patch_handle);
- inst->offset = 1;
- inst->mlen = 1;
- inst->size_written = 4 * REG_SIZE;
-
- /* Reswizzle: WZYX */
- fs_reg srcs[4] = {
- offset(tmp, bld, 3),
- offset(tmp, bld, 2),
- offset(tmp, bld, 1),
- offset(tmp, bld, 0),
- };
-
- unsigned num_components;
- switch (tcs_key->tes_primitive_mode) {
- case GL_QUADS:
- num_components = 4;
- break;
- case GL_TRIANGLES:
- num_components = 3;
- break;
- case GL_ISOLINES:
- /* Isolines are not reversed; swizzle .zw -> .xy */
- srcs[0] = offset(tmp, bld, 2);
- srcs[1] = offset(tmp, bld, 3);
- num_components = 2;
- break;
- default:
- unreachable("Bogus tessellation domain");
- }
- bld.LOAD_PAYLOAD(dst, srcs, num_components, 0);
- } else {
+ {
if (first_component != 0) {
unsigned read_components =
instr->num_components + first_component;
if (indirect_offset.file != BAD_FILE) {
srcs[header_regs++] = indirect_offset;
- } else if (!is_passthrough_shader) {
- if (imm_offset == 0) {
- value.type = BRW_REGISTER_TYPE_F;
-
- mask &= (1 << tesslevel_inner_components(tcs_key->tes_primitive_mode)) - 1;
-
- /* This is a write to gl_TessLevelInner[], which lives in the
- * Patch URB header. The layout depends on the domain.
- */
- switch (tcs_key->tes_primitive_mode) {
- case GL_QUADS:
- /* gl_TessLevelInner[].xy lives at DWords 3-2 (reversed).
- * We use an XXYX swizzle to reverse put .xy in the .wz
- * channels, and use a .zw writemask.
- */
- mask = writemask_for_backwards_vector(mask);
- swiz = BRW_SWIZZLE4(0, 0, 1, 0);
- break;
- case GL_TRIANGLES:
- /* gl_TessLevelInner[].x lives at DWord 4, so we set the
- * writemask to X and bump the URB offset by 1.
- */
- imm_offset = 1;
- break;
- case GL_ISOLINES:
- /* Skip; gl_TessLevelInner[] doesn't exist for isolines. */
- return;
- default:
- unreachable("Bogus tessellation domain");
- }
- } else if (imm_offset == 1) {
- /* This is a write to gl_TessLevelOuter[] which lives in the
- * Patch URB Header at DWords 4-7. However, it's reversed, so
- * instead of .xyzw we have .wzyx.
- */
- value.type = BRW_REGISTER_TYPE_F;
-
- mask &= (1 << tesslevel_outer_components(tcs_key->tes_primitive_mode)) - 1;
-
- if (tcs_key->tes_primitive_mode == GL_ISOLINES) {
- /* Isolines .xy should be stored in .zw, in order. */
- swiz = BRW_SWIZZLE4(0, 0, 0, 1);
- mask <<= 2;
- } else {
- /* Other domains are reversed; store .wzyx instead of .xyzw */
- swiz = BRW_SWIZZLE_WZYX;
- mask = writemask_for_backwards_vector(mask);
- }
- }
}
if (mask == 0)
}
break;
- case nir_intrinsic_load_tess_level_outer:
- /* When the TES reads gl_TessLevelOuter, we ensure that the patch header
- * appears as a push-model input. So, we can simply use the ATTR file
- * rather than issuing URB read messages. The data is stored in the
- * high DWords in reverse order - DWord 7 contains .x, DWord 6 contains
- * .y, and so on.
- */
- switch (tes_prog_data->domain) {
- case BRW_TESS_DOMAIN_QUAD:
- for (unsigned i = 0; i < 4; i++)
- bld.MOV(offset(dest, bld, i), component(fs_reg(ATTR, 0), 7 - i));
- break;
- case BRW_TESS_DOMAIN_TRI:
- for (unsigned i = 0; i < 3; i++)
- bld.MOV(offset(dest, bld, i), component(fs_reg(ATTR, 0), 7 - i));
- break;
- case BRW_TESS_DOMAIN_ISOLINE:
- for (unsigned i = 0; i < 2; i++)
- bld.MOV(offset(dest, bld, i), component(fs_reg(ATTR, 0), 6 + i));
- break;
- }
- break;
-
- case nir_intrinsic_load_tess_level_inner:
- /* When the TES reads gl_TessLevelInner, we ensure that the patch header
- * appears as a push-model input. So, we can simply use the ATTR file
- * rather than issuing URB read messages.
- */
- switch (tes_prog_data->domain) {
- case BRW_TESS_DOMAIN_QUAD:
- bld.MOV(dest, component(fs_reg(ATTR, 0), 3));
- bld.MOV(offset(dest, bld, 1), component(fs_reg(ATTR, 0), 2));
- break;
- case BRW_TESS_DOMAIN_TRI:
- bld.MOV(dest, component(fs_reg(ATTR, 0), 4));
- break;
- case BRW_TESS_DOMAIN_ISOLINE:
- /* ignore - value is undefined */
- break;
- }
- break;
-
case nir_intrinsic_load_input:
case nir_intrinsic_load_per_vertex_input: {
fs_reg indirect_offset = get_indirect_offset(instr);
return true;
}
+static bool
+remap_tess_levels(nir_builder *b, nir_intrinsic_instr *intr,
+ GLenum primitive_mode)
+{
+ const int location = nir_intrinsic_base(intr);
+ const unsigned component = nir_intrinsic_component(intr);
+ bool out_of_bounds;
+
+ if (location == VARYING_SLOT_TESS_LEVEL_INNER) {
+ switch (primitive_mode) {
+ case GL_QUADS:
+ /* gl_TessLevelInner[0..1] lives at DWords 3-2 (reversed). */
+ nir_intrinsic_set_base(intr, 0);
+ nir_intrinsic_set_component(intr, 3 - component);
+ out_of_bounds = false;
+ break;
+ case GL_TRIANGLES:
+ /* gl_TessLevelInner[0] lives at DWord 4. */
+ nir_intrinsic_set_base(intr, 1);
+ out_of_bounds = component > 0;
+ break;
+ case GL_ISOLINES:
+ out_of_bounds = true;
+ break;
+ default:
+ unreachable("Bogus tessellation domain");
+ }
+ } else if (location == VARYING_SLOT_TESS_LEVEL_OUTER) {
+ if (primitive_mode == GL_ISOLINES) {
+ /* gl_TessLevelOuter[0..1] lives at DWords 6-7 (in order). */
+ nir_intrinsic_set_base(intr, 1);
+ nir_intrinsic_set_component(intr, 2 + nir_intrinsic_component(intr));
+ out_of_bounds = component > 1;
+ } else {
+ /* Triangles use DWords 7-5 (reversed); Quads use 7-4 (reversed) */
+ nir_intrinsic_set_base(intr, 1);
+ nir_intrinsic_set_component(intr, 3 - nir_intrinsic_component(intr));
+ out_of_bounds = component == 3 && primitive_mode == GL_TRIANGLES;
+ }
+ } else {
+ return false;
+ }
+
+ if (out_of_bounds) {
+ if (nir_intrinsic_infos[intr->intrinsic].has_dest) {
+ b->cursor = nir_before_instr(&intr->instr);
+ nir_ssa_def *undef = nir_ssa_undef(b, 1, 32);
+ nir_ssa_def_rewrite_uses(&intr->dest.ssa, nir_src_for_ssa(undef));
+ }
+ nir_instr_remove(&intr->instr);
+ }
+
+ return true;
+}
+
static bool
remap_patch_urb_offsets(nir_block *block, nir_builder *b,
- const struct brw_vue_map *vue_map)
+ const struct brw_vue_map *vue_map,
+ GLenum tes_primitive_mode)
{
+ const bool is_passthrough_tcs = b->shader->info->name &&
+ strcmp(b->shader->info->name, "passthrough") == 0;
+
nir_foreach_instr_safe(instr, block) {
if (instr->type != nir_instr_type_intrinsic)
continue;
if ((stage == MESA_SHADER_TESS_CTRL && is_output(intrin)) ||
(stage == MESA_SHADER_TESS_EVAL && is_input(intrin))) {
+
+ if (!is_passthrough_tcs &&
+ remap_tess_levels(b, intrin, tes_primitive_mode))
+ continue;
+
int vue_slot = vue_map->varying_to_slot[intrin->const_index[0]];
assert(vue_slot != -1);
intrin->const_index[0] = vue_slot;
nir_builder b;
nir_builder_init(&b, function->impl);
nir_foreach_block(block, function->impl) {
- remap_patch_urb_offsets(block, &b, vue_map);
+ remap_patch_urb_offsets(block, &b, vue_map,
+ nir->info->tes.primitive_mode);
}
}
}
}
void
-brw_nir_lower_tcs_outputs(nir_shader *nir, const struct brw_vue_map *vue_map)
+brw_nir_lower_tcs_outputs(nir_shader *nir, const struct brw_vue_map *vue_map,
+ GLenum tes_primitive_mode)
{
nir_foreach_variable(var, &nir->outputs) {
var->data.driver_location = var->data.location;
nir_builder b;
nir_builder_init(&b, function->impl);
nir_foreach_block(block, function->impl) {
- remap_patch_urb_offsets(block, &b, vue_map);
+ remap_patch_urb_offsets(block, &b, vue_map, tes_primitive_mode);
}
}
}
const struct gen_device_info *devinfo,
const struct brw_wm_prog_key *key);
void brw_nir_lower_vue_outputs(nir_shader *nir, bool is_scalar);
-void brw_nir_lower_tcs_outputs(nir_shader *nir, const struct brw_vue_map *vue);
+void brw_nir_lower_tcs_outputs(nir_shader *nir, const struct brw_vue_map *vue,
+ GLenum tes_primitive_mode);
void brw_nir_lower_fs_outputs(nir_shader *nir);
void brw_nir_lower_cs_shared(nir_shader *nir);
*/
static inline nir_ssa_def *
-load_output(nir_builder *b, int num_components, int offset)
+load_output(nir_builder *b, int num_components, int offset, int component)
{
nir_intrinsic_instr *load =
nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_output);
load->num_components = num_components;
load->src[0] = nir_src_for_ssa(nir_imm_int(b, 0));
nir_intrinsic_set_base(load, offset);
+ nir_intrinsic_set_component(load, component);
nir_builder_instr_insert(b, &load->instr);
{
b->cursor = nir_after_block_before_jump(block);
- nir_ssa_def *inner = load_output(b, 2, 0);
- nir_ssa_def *outer = load_output(b, 4, 1);
+ nir_ssa_def *inner = load_output(b, 2, 0, 2);
+ nir_ssa_def *outer = load_output(b, 4, 1, 0);
nir_ssa_def *any_greater_than_1 =
nir_ior(b, nir_bany(b, nir_flt(b, nir_imm_float(b, 1.0f), outer)),
nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_output);
store->num_components = 2;
nir_intrinsic_set_write_mask(store, WRITEMASK_XY);
+ nir_intrinsic_set_component(store, 2);
store->src[0] = nir_src_for_ssa(inner);
store->src[1] = nir_src_for_ssa(nir_imm_int(b, 0));
nir_builder_instr_insert(b, &store->instr);
}
}
-unsigned
-tesslevel_outer_components(GLenum tes_primitive_mode)
-{
- switch (tes_primitive_mode) {
- case GL_QUADS:
- return 4;
- case GL_TRIANGLES:
- return 3;
- case GL_ISOLINES:
- return 2;
- default:
- unreachable("Bogus tessellation domain");
- }
- return 0;
-}
-
-unsigned
-tesslevel_inner_components(GLenum tes_primitive_mode)
-{
- switch (tes_primitive_mode) {
- case GL_QUADS:
- return 2;
- case GL_TRIANGLES:
- return 1;
- case GL_ISOLINES:
- return 0;
- default:
- unreachable("Bogus tessellation domain");
- }
- return 0;
-}
-
-/**
- * Given a normal .xyzw writemask, convert it to a writemask for a vector
- * that's stored backwards, i.e. .wzyx.
- */
-unsigned
-writemask_for_backwards_vector(unsigned mask)
-{
- unsigned new_mask = 0;
-
- for (int i = 0; i < 4; i++)
- new_mask |= ((mask >> i) & 1) << (3 - i);
-
- return new_mask;
-}
-
backend_shader::backend_shader(const struct brw_compiler *compiler,
void *log_data,
void *mem_ctx,
debug_enabled = INTEL_DEBUG & intel_debug_flag_for_shader_stage(stage);
stage_name = _mesa_shader_stage_to_string(stage);
stage_abbrev = _mesa_shader_stage_to_abbrev(stage);
- is_passthrough_shader =
- nir->info->name && strcmp(nir->info->name, "passthrough") == 0;
}
bool
/* URB entry sizes are stored as a multiple of 64 bytes. */
prog_data->base.urb_entry_size = ALIGN(output_size_bytes, 64) / 64;
-
- bool need_patch_header = nir->info->system_values_read &
- (BITFIELD64_BIT(SYSTEM_VALUE_TESS_LEVEL_OUTER) |
- BITFIELD64_BIT(SYSTEM_VALUE_TESS_LEVEL_INNER));
-
- /* The TES will pull most inputs using URB read messages.
- *
- * However, we push the patch header for TessLevel factors when required,
- * as it's a tiny amount of extra data.
- */
- prog_data->base.urb_read_length = need_patch_header ? 1 : 0;
+ prog_data->base.urb_read_length = 0;
if (unlikely(INTEL_DEBUG & DEBUG_TES)) {
fprintf(stderr, "TES Input ");
bool debug_enabled;
const char *stage_name;
const char *stage_abbrev;
- bool is_passthrough_shader;
brw::simple_allocator alloc;
GLboolean brw_link_shader(struct gl_context *ctx, struct gl_shader_program *prog);
struct gl_linked_shader *brw_new_shader(gl_shader_stage stage);
-unsigned tesslevel_outer_components(GLenum tes_primitive_mode);
-unsigned tesslevel_inner_components(GLenum tes_primitive_mode);
-unsigned writemask_for_backwards_vector(unsigned mask);
-
unsigned get_atomic_counter_op(nir_intrinsic_op op);
#ifdef __cplusplus
nir_ssa_def *invoc_id =
nir_load_system_value(&b, nir_intrinsic_load_invocation_id, 0);
- nir->info->inputs_read = key->outputs_written;
+ nir->info->inputs_read = key->outputs_written &
+ ~(VARYING_BIT_TESS_LEVEL_INNER | VARYING_BIT_TESS_LEVEL_OUTER);
nir->info->outputs_written = key->outputs_written;
nir->info->tcs.vertices_out = key->input_vertices;
nir->info->name = ralloc_strdup(nir, "passthrough");
}
/* Copy inputs to outputs. */
- uint64_t varyings = key->outputs_written;
+ uint64_t varyings = nir->info->inputs_read;
while (varyings != 0) {
const int varying = ffsll(varyings) - 1;
*/
if (tcp) {
struct gl_program *tcp_prog = &tcp->program;
- per_vertex_slots |= tcp_prog->info.outputs_written;
+ per_vertex_slots |= tcp_prog->info.outputs_written &
+ ~(VARYING_BIT_TESS_LEVEL_INNER | VARYING_BIT_TESS_LEVEL_OUTER);
per_patch_slots |= tcp_prog->info.patch_outputs_written;
}
- /* Ignore gl_TessLevelInner/Outer - we treat them as system values,
- * not inputs, and they're always present in the URB entry regardless
- * of whether or not we read them.
- */
- key->inputs_read = per_vertex_slots &
- ~(VARYING_BIT_TESS_LEVEL_INNER | VARYING_BIT_TESS_LEVEL_OUTER);
+ key->inputs_read = per_vertex_slots;
key->patch_inputs_read = per_patch_slots;
/* _NEW_TEXTURE */
if (shader_prog->_LinkedShaders[MESA_SHADER_TESS_CTRL]) {
struct gl_program *tcp =
shader_prog->_LinkedShaders[MESA_SHADER_TESS_CTRL]->Program;
- key.inputs_read |= tcp->nir->info->outputs_written;
+ key.inputs_read |= tcp->nir->info->outputs_written &
+ ~(VARYING_BIT_TESS_LEVEL_INNER | VARYING_BIT_TESS_LEVEL_OUTER);
key.patch_inputs_read |= tcp->nir->info->patch_outputs_written;
}
- /* Ignore gl_TessLevelInner/Outer - they're system values. */
- key.inputs_read &= ~(VARYING_BIT_TESS_LEVEL_INNER |
- VARYING_BIT_TESS_LEVEL_OUTER);
-
brw_setup_tex_for_precompile(brw, &key.tex, prog);
success = brw_codegen_tes_prog(brw, btep, &key);
dst_reg dst = get_nir_dest(instr->dest, BRW_REGISTER_TYPE_D);
dst.writemask = brw_writemask_for_size(instr->num_components);
- if (imm_offset == 0 && indirect_offset.file == BAD_FILE) {
- dst.type = BRW_REGISTER_TYPE_F;
-
- /* This is a read of gl_TessLevelInner[], which lives in the
- * Patch URB header. The layout depends on the domain.
- */
- switch (key->tes_primitive_mode) {
- case GL_QUADS: {
- /* DWords 3-2 (reversed); use offset 0 and WZYX swizzle. */
- dst_reg tmp(this, glsl_type::vec4_type);
- emit_output_urb_read(tmp, 0, 0, src_reg());
- emit(MOV(writemask(dst, WRITEMASK_XY),
- swizzle(src_reg(tmp), BRW_SWIZZLE_WZYX)));
- break;
- }
- case GL_TRIANGLES:
- /* DWord 4; use offset 1 but normal swizzle/writemask. */
- emit_output_urb_read(writemask(dst, WRITEMASK_X), 1, 0,
- src_reg());
- break;
- case GL_ISOLINES:
- /* All channels are undefined. */
- return;
- default:
- unreachable("Bogus tessellation domain");
- }
- } else if (imm_offset == 1 && indirect_offset.file == BAD_FILE) {
- dst.type = BRW_REGISTER_TYPE_F;
- unsigned swiz = BRW_SWIZZLE_WZYX;
-
- /* This is a read of gl_TessLevelOuter[], which lives in the
- * high 4 DWords of the Patch URB header, in reverse order.
- */
- switch (key->tes_primitive_mode) {
- case GL_QUADS:
- dst.writemask = WRITEMASK_XYZW;
- break;
- case GL_TRIANGLES:
- dst.writemask = WRITEMASK_XYZ;
- break;
- case GL_ISOLINES:
- /* Isolines are not reversed; swizzle .zw -> .xy */
- swiz = BRW_SWIZZLE_ZWZW;
- dst.writemask = WRITEMASK_XY;
- return;
- default:
- unreachable("Bogus tessellation domain");
- }
-
- dst_reg tmp(this, glsl_type::vec4_type);
- emit_output_urb_read(tmp, 1, 0, src_reg());
- emit(MOV(dst, swizzle(src_reg(tmp), swiz)));
- } else {
- emit_output_urb_read(dst, imm_offset, nir_intrinsic_component(instr),
- indirect_offset);
- }
+ emit_output_urb_read(dst, imm_offset, nir_intrinsic_component(instr),
+ indirect_offset);
break;
}
case nir_intrinsic_store_output:
src_reg indirect_offset = get_indirect_offset(instr);
unsigned imm_offset = instr->const_index[0];
- /* The passthrough shader writes the whole patch header as two vec4s;
- * skip all the gl_TessLevelInner/Outer swizzling.
- */
- if (indirect_offset.file == BAD_FILE && !is_passthrough_shader) {
- if (imm_offset == 0) {
- value.type = BRW_REGISTER_TYPE_F;
-
- mask &=
- (1 << tesslevel_inner_components(key->tes_primitive_mode)) - 1;
-
- /* This is a write to gl_TessLevelInner[], which lives in the
- * Patch URB header. The layout depends on the domain.
- */
- switch (key->tes_primitive_mode) {
- case GL_QUADS:
- /* gl_TessLevelInner[].xy lives at DWords 3-2 (reversed).
- * We use an XXYX swizzle to reverse put .xy in the .wz
- * channels, and use a .zw writemask.
- */
- swiz = BRW_SWIZZLE4(0, 0, 1, 0);
- mask = writemask_for_backwards_vector(mask);
- break;
- case GL_TRIANGLES:
- /* gl_TessLevelInner[].x lives at DWord 4, so we set the
- * writemask to X and bump the URB offset by 1.
- */
- imm_offset = 1;
- break;
- case GL_ISOLINES:
- /* Skip; gl_TessLevelInner[] doesn't exist for isolines. */
- return;
- default:
- unreachable("Bogus tessellation domain");
- }
- } else if (imm_offset == 1) {
- value.type = BRW_REGISTER_TYPE_F;
-
- mask &=
- (1 << tesslevel_outer_components(key->tes_primitive_mode)) - 1;
-
- /* This is a write to gl_TessLevelOuter[] which lives in the
- * Patch URB Header at DWords 4-7. However, it's reversed, so
- * instead of .xyzw we have .wzyx.
- */
- if (key->tes_primitive_mode == GL_ISOLINES) {
- /* Isolines .xy should be stored in .zw, in order. */
- swiz = BRW_SWIZZLE4(0, 0, 0, 1);
- mask <<= 2;
- } else {
- /* Other domains are reversed; store .wzyx instead of .xyzw. */
- swiz = BRW_SWIZZLE_WZYX;
- mask = writemask_for_backwards_vector(mask);
- }
- }
- }
-
unsigned first_component = nir_intrinsic_component(instr);
if (first_component) {
if (nir_src_bit_size(instr->src[0]) == 64)
nir = brw_nir_apply_sampler_key(nir, compiler, &key->tex, is_scalar);
brw_nir_lower_vue_inputs(nir, is_scalar, &input_vue_map);
- brw_nir_lower_tcs_outputs(nir, &vue_prog_data->vue_map);
+ brw_nir_lower_tcs_outputs(nir, &vue_prog_data->vue_map,
+ key->tes_primitive_mode);
if (key->quads_workaround)
brw_nir_apply_tcs_quads_workaround(nir);