i965: Automatically create a passthrough TCS when needed.

Signed-off-by: Kenneth Graunke <kenneth@whitecape.org>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
This commit is contained in:
Kenneth Graunke 2015-12-18 02:23:39 -08:00
parent 4ec3f0f4b9
commit 8bc073d601
3 changed files with 113 additions and 12 deletions

View File

@ -82,13 +82,31 @@ brw_codegen_tcs_prog(struct brw_context *brw,
struct brw_tess_ctrl_program *tcp,
struct brw_tcs_prog_key *key)
{
struct gl_context *ctx = &brw->ctx;
const struct brw_compiler *compiler = brw->intelScreen->compiler;
struct brw_stage_state *stage_state = &brw->tcs.base;
nir_shader *nir = tcp->program.Base.nir;
nir_shader *nir;
struct brw_tcs_prog_data prog_data;
bool start_busy = false;
double start_time = 0;
if (tcp) {
nir = tcp->program.Base.nir;
} else {
/* Create a dummy nir_shader. We won't actually use NIR code to
* generate assembly (it's easier to generate assembly directly),
* but the whole compiler assumes one of these exists.
*/
const nir_shader_compiler_options *options =
ctx->Const.ShaderCompilerOptions[MESA_SHADER_TESS_CTRL].NirOptions;
nir = nir_shader_create(NULL, MESA_SHADER_TESS_CTRL, options);
nir->num_uniforms = 2; /* both halves of the patch header */
nir->info.outputs_written = key->outputs_written;
nir->info.inputs_read = key->outputs_written;
nir->info.tcs.vertices_out = key->input_vertices;
nir->info.name = ralloc_strdup(nir, "passthrough");
}
memset(&prog_data, 0, sizeof(prog_data));
/* Allocate the references to the uniforms that will end up in the
@ -99,7 +117,8 @@ brw_codegen_tcs_prog(struct brw_context *brw,
* padding around uniform values below vec4 size, so the worst case is that
* every uniform is a float which gets padded to the size of a vec4.
*/
struct gl_shader *tcs = shader_prog->_LinkedShaders[MESA_SHADER_TESS_CTRL];
struct gl_shader *tcs = shader_prog ?
shader_prog->_LinkedShaders[MESA_SHADER_TESS_CTRL] : NULL;
int param_count = nir->num_uniforms;
if (!compiler->scalar_stage[MESA_SHADER_TESS_CTRL])
param_count *= 4;
@ -108,15 +127,38 @@ brw_codegen_tcs_prog(struct brw_context *brw,
rzalloc_array(NULL, const gl_constant_value *, param_count);
prog_data.base.base.pull_param =
rzalloc_array(NULL, const gl_constant_value *, param_count);
prog_data.base.base.image_param =
rzalloc_array(NULL, struct brw_image_param, tcs->NumImages);
prog_data.base.base.nr_params = param_count;
prog_data.base.base.nr_image_params = tcs->NumImages;
brw_nir_setup_glsl_uniforms(nir, shader_prog, &tcp->program.Base,
&prog_data.base.base, false);
if (tcs) {
prog_data.base.base.image_param =
rzalloc_array(NULL, struct brw_image_param, tcs->NumImages);
prog_data.base.base.nr_image_params = tcs->NumImages;
if (unlikely(INTEL_DEBUG & DEBUG_TCS))
brw_nir_setup_glsl_uniforms(nir, shader_prog, &tcp->program.Base,
&prog_data.base.base, false);
} else {
/* Upload the Patch URB Header as the first two uniforms.
* Do the annoying scrambling so the shader doesn't have to.
*/
const float **param = (const float **) prog_data.base.base.param;
static float zero = 0.0f;
for (int i = 0; i < 4; i++) {
param[7 - i] = &ctx->TessCtrlProgram.patch_default_outer_level[i];
}
if (key->tes_primitive_mode == GL_QUADS) {
param[3] = &ctx->TessCtrlProgram.patch_default_inner_level[0];
param[2] = &ctx->TessCtrlProgram.patch_default_inner_level[1];
param[1] = &zero;
param[0] = &zero;
} else if (key->tes_primitive_mode == GL_TRIANGLES) {
param[4] = &ctx->TessCtrlProgram.patch_default_inner_level[0];
for (int i = 0; i < 4; i++)
param[i] = &zero;
}
}
if (unlikely(INTEL_DEBUG & DEBUG_TCS) && tcs)
brw_dump_ir("tessellation control", shader_prog, tcs, NULL);
int st_index = -1;
@ -138,6 +180,8 @@ brw_codegen_tcs_prog(struct brw_context *brw,
if (shader_prog) {
shader_prog->LinkStatus = false;
ralloc_strcat(&shader_prog->InfoLog, error_str);
} else {
ralloc_free(nir);
}
_mesa_problem(NULL, "Failed to compile tessellation control shader: "
@ -172,6 +216,8 @@ brw_codegen_tcs_prog(struct brw_context *brw,
&prog_data, sizeof(prog_data),
&stage_state->prog_offset, &brw->tcs.prog_data);
ralloc_free(mem_ctx);
if (!tcs)
ralloc_free(nir);
return true;
}

View File

@ -38,14 +38,65 @@ vec4_tcs_visitor::vec4_tcs_visitor(const struct brw_compiler *compiler,
struct brw_tcs_prog_data *prog_data,
const nir_shader *nir,
void *mem_ctx,
int shader_time_index)
int shader_time_index,
const struct brw_vue_map *input_vue_map)
: vec4_visitor(compiler, log_data, &key->tex, &prog_data->base,
nir, mem_ctx, false, shader_time_index),
key(key)
input_vue_map(input_vue_map), key(key)
{
}
void
vec4_tcs_visitor::emit_nir_code()
{
if (key->program_string_id != 0) {
/* We have a real application-supplied TCS, emit real code. */
vec4_visitor::emit_nir_code();
} else {
/* There is no TCS; automatically generate a passthrough shader
* that writes the API-specified default tessellation levels and
* copies VS outputs to TES inputs.
*/
uniforms = 2;
uniform_size[0] = 1;
uniform_size[1] = 1;
uint64_t varyings = key->outputs_written;
src_reg vertex_offset(this, glsl_type::uint_type);
emit(MUL(dst_reg(vertex_offset), invocation_id,
brw_imm_ud(prog_data->vue_map.num_per_vertex_slots)));
while (varyings != 0) {
const int varying = ffsll(varyings) - 1;
unsigned in_offset = input_vue_map->varying_to_slot[varying];
unsigned out_offset = prog_data->vue_map.varying_to_slot[varying];
assert(out_offset >= 2);
dst_reg val(this, glsl_type::vec4_type);
emit_input_urb_read(val, invocation_id, in_offset, src_reg());
emit_urb_write(src_reg(val), WRITEMASK_XYZW, out_offset,
vertex_offset);
varyings &= ~BITFIELD64_BIT(varying);
}
/* Only write the tessellation factors from invocation 0.
* There's no point in making other threads do redundant work.
*/
emit(CMP(dst_null_d(), invocation_id, brw_imm_ud(0),
BRW_CONDITIONAL_EQ));
emit(IF(BRW_PREDICATE_NORMAL));
emit_urb_write(src_reg(UNIFORM, 0, glsl_type::vec4_type),
WRITEMASK_XYZW, 0, src_reg());
emit_urb_write(src_reg(UNIFORM, 1, glsl_type::vec4_type),
WRITEMASK_XYZW, 1, src_reg());
emit(BRW_OPCODE_ENDIF);
}
}
void
vec4_tcs_visitor::nir_setup_system_value_intrinsic(nir_intrinsic_instr *instr)
{
@ -478,7 +529,7 @@ brw_compile_tcs(const struct brw_compiler *compiler,
}
vec4_tcs_visitor v(compiler, log_data, key, prog_data,
nir, mem_ctx, shader_time_index);
nir, mem_ctx, shader_time_index, &input_vue_map);
if (!v.run()) {
if (error_str)
*error_str = ralloc_strdup(mem_ctx, v.fail_msg);

View File

@ -45,9 +45,11 @@ public:
struct brw_tcs_prog_data *prog_data,
const nir_shader *nir,
void *mem_ctx,
int shader_time_index);
int shader_time_index,
const struct brw_vue_map *input_vue_map);
protected:
virtual void emit_nir_code();
virtual dst_reg *make_reg_for_system_value(int location,
const glsl_type *type);
virtual void nir_setup_system_value_intrinsic(nir_intrinsic_instr *instr);
@ -74,6 +76,8 @@ protected:
virtual void emit_urb_write_header(int mrf) {}
virtual vec4_instruction *emit_urb_write_opcode(bool complete) { return NULL; }
const struct brw_vue_map *input_vue_map;
const struct brw_tcs_prog_key *key;
src_reg invocation_id;
};