X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_glsl_to_nir.cpp;h=2de767625af4dd99f08a2d1834bcbc77e7615735;hb=f63e05ae9ea0be38a8fb2dd0ae8f391b8699e757;hp=1912da2404a3546a5250c36dbdec0fce101fe804;hpb=ecbe1e976f279a3519aaf9ab365ebe28b60f1ace;p=mesa.git diff --git a/src/mesa/state_tracker/st_glsl_to_nir.cpp b/src/mesa/state_tracker/st_glsl_to_nir.cpp index 1912da2404a..2de767625af 100644 --- a/src/mesa/state_tracker/st_glsl_to_nir.cpp +++ b/src/mesa/state_tracker/st_glsl_to_nir.cpp @@ -88,7 +88,7 @@ st_nir_assign_vs_in_locations(struct gl_program *prog, nir_shader *nir) if ((prog->info.inputs_read & BITFIELD64_BIT(attr)) != 0) { input_to_index[attr] = num_inputs; num_inputs++; - if ((prog->info.double_inputs_read & BITFIELD64_BIT(attr)) != 0) { + if ((prog->info.vs.double_inputs_read & BITFIELD64_BIT(attr)) != 0) { /* add placeholder for second part of a double attribute */ num_inputs++; } @@ -121,6 +121,58 @@ st_nir_assign_vs_in_locations(struct gl_program *prog, nir_shader *nir) } } +static void +st_nir_assign_var_locations(struct exec_list *var_list, unsigned *size, + gl_shader_stage stage) +{ + unsigned location = 0; + unsigned assigned_locations[VARYING_SLOT_TESS_MAX]; + uint64_t processed_locs = 0; + uint32_t processed_patch_locs = 0; + + nir_foreach_variable(var, var_list) { + + const struct glsl_type *type = var->type; + if (nir_is_per_vertex_io(var, stage)) { + assert(glsl_type_is_array(type)); + type = glsl_get_array_element(type); + } + + bool processed = false; + if (var->data.patch && + var->data.location != VARYING_SLOT_TESS_LEVEL_INNER && + var->data.location != VARYING_SLOT_TESS_LEVEL_OUTER && + var->data.location != VARYING_SLOT_BOUNDING_BOX0 && + var->data.location != VARYING_SLOT_BOUNDING_BOX1) { + unsigned patch_loc = var->data.location - VARYING_SLOT_PATCH0; + if (processed_patch_locs & (1 << patch_loc)) + processed = true; + + processed_patch_locs |= (1 << patch_loc); + } else { + if (processed_locs & ((uint64_t)1 << var->data.location)) + processed = true; + + processed_locs |= ((uint64_t)1 << var->data.location); + } + + /* Because component packing allows varyings to share the same location + * we may have already have processed this location. + */ + if (processed && var->data.location >= VARYING_SLOT_VAR0) { + var->data.driver_location = assigned_locations[var->data.location]; + *size += type_size(type); + continue; + } + + assigned_locations[var->data.location] = location; + var->data.driver_location = location; + location += type_size(type); + } + + *size += location; +} + static int st_nir_lookup_parameter_index(const struct gl_program_parameter_list *params, const char *name) @@ -176,6 +228,7 @@ st_nir_assign_uniform_locations(struct gl_program *prog, { int max = 0; int shaderidx = 0; + int imageidx = 0; nir_foreach_variable(uniform, uniform_list) { int loc; @@ -188,16 +241,11 @@ st_nir_assign_uniform_locations(struct gl_program *prog, uniform->interface_type != NULL) continue; - if (uniform->type->is_sampler()) { - unsigned val = 0; - bool found = shader_program->UniformHash->get(val, uniform->name); - loc = shaderidx++; - assert(found); - (void) found; /* silence unused var warning */ - /* this ensure that nir_lower_samplers looks at the correct - * shader_program->UniformStorage[location]: - */ - uniform->data.location = val; + if (uniform->type->is_sampler() || uniform->type->is_image()) { + if (uniform->type->is_sampler()) + loc = shaderidx++; + else + loc = imageidx++; } else if (strncmp(uniform->name, "gl_", 3) == 0) { const gl_state_index *const stateTokens = (gl_state_index *)uniform->state_slots[0].tokens; /* This state reference has already been setup by ir_to_mesa, but we'll @@ -215,13 +263,43 @@ st_nir_assign_uniform_locations(struct gl_program *prog, *size = max; } -extern "C" { +static void +st_nir_opts(nir_shader *nir) +{ + bool progress; + do { + progress = false; + + NIR_PASS_V(nir, nir_lower_64bit_pack); + NIR_PASS(progress, nir, nir_copy_prop); + NIR_PASS(progress, nir, nir_opt_remove_phis); + NIR_PASS(progress, nir, nir_opt_dce); + if (nir_opt_trivial_continues(nir)) { + progress = true; + NIR_PASS(progress, nir, nir_copy_prop); + NIR_PASS(progress, nir, nir_opt_dce); + } + NIR_PASS(progress, nir, nir_opt_if); + NIR_PASS(progress, nir, nir_opt_dead_cf); + NIR_PASS(progress, nir, nir_opt_cse); + NIR_PASS(progress, nir, nir_opt_peephole_select, 8); + + NIR_PASS(progress, nir, nir_opt_algebraic); + NIR_PASS(progress, nir, nir_opt_constant_folding); + + NIR_PASS(progress, nir, nir_opt_undef); + NIR_PASS(progress, nir, nir_opt_conditional_discard); + if (nir->options->max_unroll_iterations) { + NIR_PASS(progress, nir, nir_opt_loop_unroll, (nir_variable_mode)0); + } + } while (progress); +} -/* First half of converting glsl_to_nir.. this leaves things in a pre- +/* First third of converting glsl_to_nir.. this leaves things in a pre- * nir_lower_io state, so that shader variants can more easily insert/ * replace variables, etc. */ -nir_shader * +static nir_shader * st_glsl_to_nir(struct st_context *st, struct gl_program *prog, struct gl_shader_program *shader_program, gl_shader_stage stage) @@ -229,7 +307,6 @@ st_glsl_to_nir(struct st_context *st, struct gl_program *prog, struct pipe_screen *pscreen = st->pipe->screen; enum pipe_shader_type ptarget = pipe_shader_type_from_mesa(stage); const nir_shader_compiler_options *options; - nir_shader *nir; assert(pscreen->get_compiler_options); /* drivers using NIR must implement this */ @@ -240,7 +317,21 @@ st_glsl_to_nir(struct st_context *st, struct gl_program *prog, if (prog->nir) return prog->nir; - nir = glsl_to_nir(shader_program, stage, options); + nir_shader *nir = glsl_to_nir(shader_program, stage, options); + + st_nir_opts(nir); + + return nir; +} + +/* Second third of converting glsl_to_nir. This creates uniforms, gathers + * info on varyings, etc after NIR link time opts have been applied. + */ +static void +st_glsl_to_nir_post_opts(struct st_context *st, struct gl_program *prog, + struct gl_shader_program *shader_program) +{ + nir_shader *nir = prog->nir; /* Make a pass over the IR to add state references for any built-in * uniforms that are used. This has to be done now (during linking). @@ -273,43 +364,6 @@ st_glsl_to_nir(struct st_context *st, struct gl_program *prog, */ _mesa_associate_uniform_storage(st->ctx, shader_program, prog, true); - NIR_PASS_V(nir, nir_lower_io_to_temporaries, - nir_shader_get_entrypoint(nir), - true, true); - NIR_PASS_V(nir, nir_lower_global_vars_to_local); - NIR_PASS_V(nir, nir_split_var_copies); - NIR_PASS_V(nir, nir_lower_var_copies); - - /* fragment shaders may need : */ - if (stage == MESA_SHADER_FRAGMENT) { - static const gl_state_index wposTransformState[STATE_LENGTH] = { - STATE_INTERNAL, STATE_FB_WPOS_Y_TRANSFORM - }; - nir_lower_wpos_ytransform_options wpos_options = { { 0 } }; - struct pipe_screen *pscreen = st->pipe->screen; - - memcpy(wpos_options.state_tokens, wposTransformState, - sizeof(wpos_options.state_tokens)); - wpos_options.fs_coord_origin_upper_left = - pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT); - wpos_options.fs_coord_origin_lower_left = - pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT); - wpos_options.fs_coord_pixel_center_integer = - pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER); - wpos_options.fs_coord_pixel_center_half_integer = - pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER); - - if (nir_lower_wpos_ytransform(nir, &wpos_options)) { - nir_validate_shader(nir); - _mesa_add_state_reference(prog->Parameters, wposTransformState); - } - } - - NIR_PASS_V(nir, nir_lower_system_values); - - nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir)); - prog->info = nir->info; - st_set_prog_affected_state_flags(prog); NIR_PASS_V(nir, st_nir_lower_builtin); @@ -318,15 +372,11 @@ st_glsl_to_nir(struct st_context *st, struct gl_program *prog, if (st->ctx->_Shader->Flags & GLSL_DUMP) { _mesa_log("\n"); _mesa_log("NIR IR for linked %s program %d:\n", - _mesa_shader_stage_to_string(stage), + _mesa_shader_stage_to_string(prog->info.stage), shader_program->Name); nir_print_shader(nir, _mesa_get_log_file()); _mesa_log("\n\n"); } - - prog->nir = nir; - - return nir; } /* TODO any better helper somewhere to sort a list? */ @@ -355,58 +405,49 @@ sort_varyings(struct exec_list *var_list) exec_list_move_nodes_to(&new_list, var_list); } -/* Second half of preparing nir from glsl, which happens after shader - * variant lowering. - */ -void -st_finalize_nir(struct st_context *st, struct gl_program *prog, - struct gl_shader_program *shader_program, nir_shader *nir) +static void +set_st_program(struct gl_program *prog, + struct gl_shader_program *shader_program, + nir_shader *nir) { - struct pipe_screen *screen = st->pipe->screen; - - NIR_PASS_V(nir, nir_split_var_copies); - NIR_PASS_V(nir, nir_lower_var_copies); - NIR_PASS_V(nir, nir_lower_io_types); - - if (nir->info.stage == MESA_SHADER_VERTEX) { - /* Needs special handling so drvloc matches the vbo state: */ - st_nir_assign_vs_in_locations(prog, nir); - /* Re-lower global vars, to deal with any dead VS inputs. */ - NIR_PASS_V(nir, nir_lower_global_vars_to_local); + struct st_vertex_program *stvp; + struct st_common_program *stp; + struct st_fragment_program *stfp; + struct st_compute_program *stcp; - sort_varyings(&nir->outputs); - nir_assign_var_locations(&nir->outputs, - &nir->num_outputs, - type_size); - st_nir_fixup_varying_slots(st, &nir->outputs); - } else if (nir->info.stage == MESA_SHADER_FRAGMENT) { - sort_varyings(&nir->inputs); - nir_assign_var_locations(&nir->inputs, - &nir->num_inputs, - type_size); - st_nir_fixup_varying_slots(st, &nir->inputs); - nir_assign_var_locations(&nir->outputs, - &nir->num_outputs, - type_size); - } else if (nir->info.stage == MESA_SHADER_COMPUTE) { - /* TODO? */ - } else { - unreachable("invalid shader type for tgsi bypass\n"); + switch (prog->info.stage) { + case MESA_SHADER_VERTEX: + stvp = (struct st_vertex_program *)prog; + stvp->shader_program = shader_program; + stvp->tgsi.type = PIPE_SHADER_IR_NIR; + stvp->tgsi.ir.nir = nir; + break; + case MESA_SHADER_GEOMETRY: + case MESA_SHADER_TESS_CTRL: + case MESA_SHADER_TESS_EVAL: + stp = (struct st_common_program *)prog; + stp->shader_program = shader_program; + stp->tgsi.type = PIPE_SHADER_IR_NIR; + stp->tgsi.ir.nir = nir; + break; + case MESA_SHADER_FRAGMENT: + stfp = (struct st_fragment_program *)prog; + stfp->shader_program = shader_program; + stfp->tgsi.type = PIPE_SHADER_IR_NIR; + stfp->tgsi.ir.nir = nir; + break; + case MESA_SHADER_COMPUTE: + stcp = (struct st_compute_program *)prog; + stcp->shader_program = shader_program; + stcp->tgsi.ir_type = PIPE_SHADER_IR_NIR; + stcp->tgsi.prog = nir; + break; + default: + unreachable("unknown shader stage"); } - - NIR_PASS_V(nir, nir_lower_atomics_to_ssbo, - st->ctx->Const.Program[nir->info.stage].MaxAtomicBuffers); - - st_nir_assign_uniform_locations(prog, shader_program, - &nir->uniforms, &nir->num_uniforms); - - if (screen->get_param(screen, PIPE_CAP_NIR_SAMPLERS_AS_DEREF)) - NIR_PASS_V(nir, nir_lower_samplers_as_deref, shader_program); - else - NIR_PASS_V(nir, nir_lower_samplers, shader_program); } -struct gl_program * +static void st_nir_get_mesa_program(struct gl_context *ctx, struct gl_shader_program *shader_program, struct gl_linked_shader *shader) @@ -436,47 +477,243 @@ st_nir_get_mesa_program(struct gl_context *ctx, prog->ExternalSamplersUsed = gl_external_samplers(prog); _mesa_update_shader_textures_used(shader_program, prog); - struct st_vertex_program *stvp; - struct st_common_program *stp; - struct st_fragment_program *stfp; - struct st_compute_program *stcp; - nir_shader *nir = st_glsl_to_nir(st, prog, shader_program, shader->Stage); - switch (shader->Stage) { - case MESA_SHADER_VERTEX: - stvp = (struct st_vertex_program *)prog; - stvp->shader_program = shader_program; - stvp->tgsi.type = PIPE_SHADER_IR_NIR; - stvp->tgsi.ir.nir = nir; - break; - case MESA_SHADER_GEOMETRY: - case MESA_SHADER_TESS_CTRL: - case MESA_SHADER_TESS_EVAL: - stp = (struct st_common_program *)prog; - stp->shader_program = shader_program; - stp->tgsi.type = PIPE_SHADER_IR_NIR; - stp->tgsi.ir.nir = nir; - break; - case MESA_SHADER_FRAGMENT: - stfp = (struct st_fragment_program *)prog; - stfp->shader_program = shader_program; - stfp->tgsi.type = PIPE_SHADER_IR_NIR; - stfp->tgsi.ir.nir = nir; - break; - case MESA_SHADER_COMPUTE: - stcp = (struct st_compute_program *)prog; - stcp->shader_program = shader_program; - stcp->tgsi.ir_type = PIPE_SHADER_IR_NIR; - stcp->tgsi.prog = nir_shader_clone(NULL, nir); - break; - default: - assert(!"should not be reached"); - return NULL; + set_st_program(prog, shader_program, nir); + prog->nir = nir; + + if (nir->info.stage != MESA_SHADER_TESS_CTRL && + nir->info.stage != MESA_SHADER_TESS_EVAL) { + NIR_PASS_V(nir, nir_lower_io_to_temporaries, + nir_shader_get_entrypoint(nir), + true, true); + } + NIR_PASS_V(nir, nir_lower_global_vars_to_local); + NIR_PASS_V(nir, nir_split_var_copies); + NIR_PASS_V(nir, nir_lower_var_copies); +} + +static void +st_nir_link_shaders(nir_shader **producer, nir_shader **consumer) +{ + nir_lower_io_arrays_to_elements(*producer, *consumer); + + NIR_PASS_V(*producer, nir_remove_dead_variables, nir_var_shader_out); + NIR_PASS_V(*consumer, nir_remove_dead_variables, nir_var_shader_in); + + if (nir_remove_unused_varyings(*producer, *consumer)) { + NIR_PASS_V(*producer, nir_lower_global_vars_to_local); + NIR_PASS_V(*consumer, nir_lower_global_vars_to_local); + + /* The backend might not be able to handle indirects on + * temporaries so we need to lower indirects on any of the + * varyings we have demoted here. + * + * TODO: radeonsi shouldn't need to do this, however LLVM isn't + * currently smart enough to handle indirects without causing excess + * spilling causing the gpu to hang. + * + * See the following thread for more details of the problem: + * https://lists.freedesktop.org/archives/mesa-dev/2017-July/162106.html + */ + nir_variable_mode indirect_mask = nir_var_local; + + NIR_PASS_V(*producer, nir_lower_indirect_derefs, indirect_mask); + NIR_PASS_V(*consumer, nir_lower_indirect_derefs, indirect_mask); + + st_nir_opts(*producer); + st_nir_opts(*consumer); + } +} + +extern "C" { + +bool +st_link_nir(struct gl_context *ctx, + struct gl_shader_program *shader_program) +{ + struct st_context *st = st_context(ctx); + + /* Determine first and last stage. */ + unsigned first = MESA_SHADER_STAGES; + unsigned last = 0; + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + if (!shader_program->_LinkedShaders[i]) + continue; + if (first == MESA_SHADER_STAGES) + first = i; + last = i; + } + + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader *shader = shader_program->_LinkedShaders[i]; + if (shader == NULL) + continue; + + st_nir_get_mesa_program(ctx, shader_program, shader); + + nir_variable_mode mask = (nir_variable_mode) 0; + if (i != first) + mask = (nir_variable_mode)(mask | nir_var_shader_in); + + if (i != last) + mask = (nir_variable_mode)(mask | nir_var_shader_out); + + nir_shader *nir = shader->Program->nir; + nir_lower_io_to_scalar_early(nir, mask); + st_nir_opts(nir); + } + + /* Linking the stages in the opposite order (from fragment to vertex) + * ensures that inter-shader outputs written to in an earlier stage + * are eliminated if they are (transitively) not used in a later + * stage. + */ + int next = last; + for (int i = next - 1; i >= 0; i--) { + struct gl_linked_shader *shader = shader_program->_LinkedShaders[i]; + if (shader == NULL) + continue; + + st_nir_link_shaders(&shader->Program->nir, + &shader_program->_LinkedShaders[next]->Program->nir); + next = i; } + int prev = -1; + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader *shader = shader_program->_LinkedShaders[i]; + if (shader == NULL) + continue; + + nir_shader *nir = shader->Program->nir; + + /* fragment shaders may need : */ + if (nir->info.stage == MESA_SHADER_FRAGMENT) { + static const gl_state_index wposTransformState[STATE_LENGTH] = { + STATE_INTERNAL, STATE_FB_WPOS_Y_TRANSFORM + }; + nir_lower_wpos_ytransform_options wpos_options = { { 0 } }; + struct pipe_screen *pscreen = st->pipe->screen; + + memcpy(wpos_options.state_tokens, wposTransformState, + sizeof(wpos_options.state_tokens)); + wpos_options.fs_coord_origin_upper_left = + pscreen->get_param(pscreen, + PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT); + wpos_options.fs_coord_origin_lower_left = + pscreen->get_param(pscreen, + PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT); + wpos_options.fs_coord_pixel_center_integer = + pscreen->get_param(pscreen, + PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER); + wpos_options.fs_coord_pixel_center_half_integer = + pscreen->get_param(pscreen, + PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER); + + if (nir_lower_wpos_ytransform(nir, &wpos_options)) { + nir_validate_shader(nir); + _mesa_add_state_reference(shader->Program->Parameters, + wposTransformState); + } + } + + NIR_PASS_V(nir, nir_lower_system_values); + + nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir)); + shader->Program->info = nir->info; + + if (prev != -1) { + nir_compact_varyings(shader_program->_LinkedShaders[prev]->Program->nir, + nir, ctx->API != API_OPENGL_COMPAT); + } + prev = i; + } + + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_linked_shader *shader = shader_program->_LinkedShaders[i]; + if (shader == NULL) + continue; + + st_glsl_to_nir_post_opts(st, shader->Program, shader_program); + + assert(shader->Program); + if (!ctx->Driver.ProgramStringNotify(ctx, + _mesa_shader_stage_to_program(i), + shader->Program)) { + _mesa_reference_program(ctx, &shader->Program, NULL); + return false; + } + } + + return true; +} + +/* Last third of preparing nir from glsl, which happens after shader + * variant lowering. + */ +void +st_finalize_nir(struct st_context *st, struct gl_program *prog, + struct gl_shader_program *shader_program, nir_shader *nir) +{ + struct pipe_screen *screen = st->pipe->screen; + + NIR_PASS_V(nir, nir_split_var_copies); + NIR_PASS_V(nir, nir_lower_var_copies); + if (nir->info.stage != MESA_SHADER_TESS_CTRL && + nir->info.stage != MESA_SHADER_TESS_EVAL) + NIR_PASS_V(nir, nir_lower_io_arrays_to_elements_no_indirects); + + if (nir->info.stage == MESA_SHADER_VERTEX) { + /* Needs special handling so drvloc matches the vbo state: */ + st_nir_assign_vs_in_locations(prog, nir); + /* Re-lower global vars, to deal with any dead VS inputs. */ + NIR_PASS_V(nir, nir_lower_global_vars_to_local); + + sort_varyings(&nir->outputs); + st_nir_assign_var_locations(&nir->outputs, + &nir->num_outputs, + nir->info.stage); + st_nir_fixup_varying_slots(st, &nir->outputs); + } else if (nir->info.stage == MESA_SHADER_GEOMETRY || + nir->info.stage == MESA_SHADER_TESS_CTRL || + nir->info.stage == MESA_SHADER_TESS_EVAL) { + sort_varyings(&nir->inputs); + st_nir_assign_var_locations(&nir->inputs, + &nir->num_inputs, + nir->info.stage); + st_nir_fixup_varying_slots(st, &nir->inputs); + + sort_varyings(&nir->outputs); + st_nir_assign_var_locations(&nir->outputs, + &nir->num_outputs, + nir->info.stage); + st_nir_fixup_varying_slots(st, &nir->outputs); + } else if (nir->info.stage == MESA_SHADER_FRAGMENT) { + sort_varyings(&nir->inputs); + st_nir_assign_var_locations(&nir->inputs, + &nir->num_inputs, + nir->info.stage); + st_nir_fixup_varying_slots(st, &nir->inputs); + st_nir_assign_var_locations(&nir->outputs, + &nir->num_outputs, + nir->info.stage); + } else if (nir->info.stage == MESA_SHADER_COMPUTE) { + /* TODO? */ + } else { + unreachable("invalid shader type for tgsi bypass\n"); + } + + NIR_PASS_V(nir, nir_lower_atomics_to_ssbo, + st->ctx->Const.Program[nir->info.stage].MaxAtomicBuffers); - return prog; + st_nir_assign_uniform_locations(prog, shader_program, + &nir->uniforms, &nir->num_uniforms); + + if (screen->get_param(screen, PIPE_CAP_NIR_SAMPLERS_AS_DEREF)) + NIR_PASS_V(nir, nir_lower_samplers_as_deref, shader_program); + else + NIR_PASS_V(nir, nir_lower_samplers, shader_program); } } /* extern "C" */