Thanks Kenneth, here attach my RFC prototype patch implementing these, and comments follows.
>> When working on lima gp compiler, I come across two problems about >> inserting extra uniform >> and instructions in nir for the driver and don't know where's the >> right place to do it. So I'd like >> to hear your opinion and if there's other driver already did so. >> >> 1. viewport transfer >> lima gp needs embed viewport transfer into vertex shader, so need to >> insert a uniform which >> holds the scale and transfer and some instruction to apply the >> calculation to the gl_Position >> varying output. If do this in driver callback create_vs_state(), seems >> won't affect the state >> tracker to allocate uniform space for it, maybe add something in >> st_create_vp_variant()? > > The best way to handle this is probably to use the statevars mechanism. > Extend src/mesa/program/prog_statevars.[ch] with new STATE_VIEWPORT_* > enum values, and populate it with the viewport values you need from the > GL context. > > Then, you can just refer to special built-in uniforms in NIR. See how > nir_lower_wpos_ytransform.c does this, for example. So you mean add a STATE for the viewport and implement all in a none-driver spec way? In fact my prototype just use the STATE_INTERNAL_DRIVER and add a new pipe_context callback to do all this before st_finalize_nir. I think I can move the viewport part out of driver spec way, but not the const part. > >> 2. const load >> lima gp needs const be loaded just as uniform, so I have to allocate >> uniform space for them. >> Besides the same problem as 1 (where to do it), the const node may be >> eliminated after driver >> nir optimization and won't have a base filed as uniform. > > Not sure what to recommend here. It might be best to handle it as part > of your compiler backend. Or, perhaps late in the process, you could > convert load_const into load_uniform intrinsics. You can decide on the > constant buffer layout yourself, and just set the driver locations / load > offsets yourself... If I don't allocate space before st_finalize_nir, how does st part know to reserve constant buffer space for it? > >> Seems some of these (space allocation) need be done in non-driver >> layer and some (instruction >> insertion and uniform base assign to const) can be done in driver. >> >> BTW. lima gp can only have one uniform buffer, so I can't just use a >> dedicated uniform buffer >> for viewport transfer and const uniform. > > Makes sense. That shouldn't be a problem. I mean "can't"... Regards, Qiang
From e3aa50296a87b8b4cbf4d9f83939d5c87b75e948 Mon Sep 17 00:00:00 2001 From: Qiang Yu <yuq...@gmail.com> Date: Wed, 30 Aug 2017 08:32:53 +0800 Subject: [PATCH 4/4] lima: add lower constant to uniform Signed-off-by: Qiang Yu <yuq...@gmail.com> --- src/gallium/drivers/lima/Makefile.sources | 1 + src/gallium/drivers/lima/ir/gp/gpir.h | 6 +++ src/gallium/drivers/lima/ir/gp/lower.c | 17 +++++-- src/gallium/drivers/lima/ir/gp/nir.c | 13 +++++ src/gallium/drivers/lima/lima_nir_lower_const.c | 67 +++++++++++++++++++++++++ src/gallium/drivers/lima/lima_program.c | 7 ++- src/gallium/drivers/lima/lima_program.h | 5 +- 7 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 src/gallium/drivers/lima/lima_nir_lower_const.c diff --git a/src/gallium/drivers/lima/Makefile.sources b/src/gallium/drivers/lima/Makefile.sources index f251810..083c3b3 100644 --- a/src/gallium/drivers/lima/Makefile.sources +++ b/src/gallium/drivers/lima/Makefile.sources @@ -17,4 +17,5 @@ C_SOURCES := \ lima_draw.c \ lima_program.c \ lima_nir_lower_viewport_transform.c \ + lima_nir_lower_const.c \ $(gpir_SOURCES) diff --git a/src/gallium/drivers/lima/ir/gp/gpir.h b/src/gallium/drivers/lima/ir/gp/gpir.h index 0f25fdf..76f1029 100644 --- a/src/gallium/drivers/lima/ir/gp/gpir.h +++ b/src/gallium/drivers/lima/ir/gp/gpir.h @@ -255,9 +255,15 @@ typedef struct { typedef struct gpir_compiler { struct list_head block_list; int cur_index; + /* array for searching ssa/reg node */ gpir_node **var_nodes; unsigned reg_base; + + /* constant info */ + union fi *constants; + int num_constant; + int constant_base; } gpir_compiler; typedef struct gpir_prog { diff --git a/src/gallium/drivers/lima/ir/gp/lower.c b/src/gallium/drivers/lima/ir/gp/lower.c index c12b27a..a10c412 100644 --- a/src/gallium/drivers/lima/ir/gp/lower.c +++ b/src/gallium/drivers/lima/ir/gp/lower.c @@ -33,11 +33,20 @@ static void gpir_lower_const(gpir_compiler *comp) if (node->op == gpir_op_const) { gpir_const_node *c = gpir_node_to_const(node); - fprintf(stderr, "gpir: const lower not implemented node %d value %x\n", - node->index, c->value.ui); + if (!gpir_node_is_root(node)) { + gpir_load_node *load = gpir_node_create(comp, gpir_op_load_uniform, -1); + load->index = comp->num_constant >> 2; + load->component = comp->num_constant % 4; + comp->constants[comp->num_constant++] = c->value; + gpir_node_replace_succ(&load->node, node); - if (gpir_node_is_root(node)) - gpir_node_delete(node); + list_addtail(&load->node.list, &block->node_list); + + fprintf(stderr, "gpir: lower const create uniform %d for const %d\n", + load->node.index, node->index); + } + + gpir_node_delete(node); } } } diff --git a/src/gallium/drivers/lima/ir/gp/nir.c b/src/gallium/drivers/lima/ir/gp/nir.c index a23e01b..97786a6 100644 --- a/src/gallium/drivers/lima/ir/gp/nir.c +++ b/src/gallium/drivers/lima/ir/gp/nir.c @@ -319,6 +319,10 @@ static void gpir_compiler_delete(gpir_compiler *comp) list_for_each_entry_safe(gpir_block, block, &comp->block_list, list) { gpir_block_delete(block); } + + if (comp->constants) + FREE(comp->constants); + FREE(comp); } @@ -329,6 +333,15 @@ gpir_prog *gpir_compile_nir(nir_shader *nir) if (!comp) return NULL; + nir_foreach_variable(uniform, &nir->uniforms) { + if (!strcmp(uniform->name, "gl_limaConstant")) { + comp->constant_base = uniform->data.driver_location; + comp->constants = CALLOC(1, 4 * glsl_get_length(uniform->type) * sizeof(union fi)); + if (!comp->constants) + return NULL; + } + } + if (!gpir_emit_cf_list(comp, &func->body)) { gpir_compiler_delete(comp); return NULL; diff --git a/src/gallium/drivers/lima/lima_nir_lower_const.c b/src/gallium/drivers/lima/lima_nir_lower_const.c new file mode 100644 index 0000000..d637e8a --- /dev/null +++ b/src/gallium/drivers/lima/lima_nir_lower_const.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017 Lima Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "compiler/nir/nir_builder.h" +#include "lima_program.h" + +/* lower const load into uniform load + * + * This is needed for lima gp which has no immediate number support in ISA. + * Declare all const value in uniform. Left lowering the load instr to gpir + * after constant foldering. + */ + +static void +lima_nir_do_lower_const(nir_shader *shader, int num_const) +{ + static const int tokens[STATE_LENGTH] = { + STATE_INTERNAL, STATE_LIMA_CONSTANT + }; + + lima_nir_create_array_var( + shader, "gl_limaConstant", tokens, (num_const + 3) >> 2); +} + +void +lima_nir_lower_const(nir_shader *shader) +{ + assert(shader->stage == MESA_SHADER_VERTEX); + + int num_const = 0; + nir_foreach_function(function, shader) { + if (function->impl) { + nir_foreach_block(block, function->impl) { + nir_foreach_instr_safe(instr, block) { + if (instr->type == nir_instr_type_load_const) { + nir_load_const_instr *load = nir_instr_as_load_const(instr); + num_const += load->def.num_components; + } + } + } + } + } + + if (num_const) + lima_nir_do_lower_const(shader, num_const); +} diff --git a/src/gallium/drivers/lima/lima_program.c b/src/gallium/drivers/lima/lima_program.c index 148c091..8ac5830 100644 --- a/src/gallium/drivers/lima/lima_program.c +++ b/src/gallium/drivers/lima/lima_program.c @@ -210,7 +210,7 @@ lima_delete_vs_state(struct pipe_context *pctx, void *hwcso) } nir_variable * -lima_nir_create_array_var(nir_shader *shader, const char *name, int *tokens, int n) +lima_nir_create_array_var(nir_shader *shader, const char *name, const int *tokens, int n) { nir_variable *var = nir_variable_create( shader, nir_var_uniform, @@ -224,14 +224,13 @@ lima_nir_create_array_var(nir_shader *shader, const char *name, int *tokens, int return var; } -static void * +static void lima_vs_nir_before_finalize(struct pipe_context *pctx, void *pnir) { nir_shader *nir = pnir; NIR_PASS_V(nir, lima_nir_lower_viewport_transform); - - return NULL; + NIR_PASS_V(nir, lima_nir_lower_const); } void diff --git a/src/gallium/drivers/lima/lima_program.h b/src/gallium/drivers/lima/lima_program.h index 5219f18..6155fd8 100644 --- a/src/gallium/drivers/lima/lima_program.h +++ b/src/gallium/drivers/lima/lima_program.h @@ -27,17 +27,20 @@ #include "program/prog_statevars.h" #include "pipe/p_defines.h" +#include "util/u_math.h" struct nir_variable; struct nir_shader; #define STATE_LIMA_VIEWPORT_TRANSFORM (STATE_INTERNAL_DRIVER + 0) +#define STATE_LIMA_CONSTANT (STATE_INTERNAL_DRIVER + 1) struct nir_variable *lima_nir_create_array_var( struct nir_shader *shader, const char *name, - int *tokens, int n); + const int *tokens, int n); void lima_nir_lower_viewport_transform(struct nir_shader *shader); +void lima_nir_lower_const(struct nir_shader *shader); void lima_program_optimize_nir(struct nir_shader *s); const void *lima_program_get_compiler_options(enum pipe_shader_type shader); -- 1.9.1
From 2820fff6acfde69e37a34749959c4357551c3df8 Mon Sep 17 00:00:00 2001 From: Qiang Yu <yuq...@gmail.com> Date: Tue, 29 Aug 2017 10:24:34 +0800 Subject: [PATCH 3/4] lima: add lower viewport transform pass Signed-off-by: Qiang Yu <yuq...@gmail.com> --- src/gallium/drivers/lima/Makefile.am | 2 + src/gallium/drivers/lima/Makefile.sources | 1 + .../lima/lima_nir_lower_viewport_transform.c | 118 +++++++++++++++++++++ src/gallium/drivers/lima/lima_program.c | 27 +++++ src/gallium/drivers/lima/lima_program.h | 10 ++ 5 files changed, 158 insertions(+) create mode 100644 src/gallium/drivers/lima/lima_nir_lower_viewport_transform.c diff --git a/src/gallium/drivers/lima/Makefile.am b/src/gallium/drivers/lima/Makefile.am index 11f3710..ae8f6d6 100644 --- a/src/gallium/drivers/lima/Makefile.am +++ b/src/gallium/drivers/lima/Makefile.am @@ -23,6 +23,8 @@ include Makefile.sources include $(top_srcdir)/src/gallium/Automake.inc AM_CFLAGS = \ + -I$(top_builddir)/src/compiler/nir \ + -I$(top_srcdir)/src/mesa \ $(GALLIUM_DRIVER_CFLAGS) \ $(LIMA_CFLAGS) diff --git a/src/gallium/drivers/lima/Makefile.sources b/src/gallium/drivers/lima/Makefile.sources index eca31db..f251810 100644 --- a/src/gallium/drivers/lima/Makefile.sources +++ b/src/gallium/drivers/lima/Makefile.sources @@ -16,4 +16,5 @@ C_SOURCES := \ lima_state.c \ lima_draw.c \ lima_program.c \ + lima_nir_lower_viewport_transform.c \ $(gpir_SOURCES) diff --git a/src/gallium/drivers/lima/lima_nir_lower_viewport_transform.c b/src/gallium/drivers/lima/lima_nir_lower_viewport_transform.c new file mode 100644 index 0000000..4dfc960 --- /dev/null +++ b/src/gallium/drivers/lima/lima_nir_lower_viewport_transform.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2017 Lima Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "compiler/nir/nir_builder.h" +#include "lima_program.h" + +/* lower viewport transform into vertext shader + * + * This is needed for lima gp which has no viewport transform hw. + * Declare viewport transform parameters in uniform and use them + * to apply on the gl_Position varying output. + */ + +typedef struct { + nir_shader *shader; + nir_builder b; + nir_variable *transform; +} lower_viewport_transform_state; + +static nir_ssa_def * +get_transform_offset(lower_viewport_transform_state *state, int offset) +{ + static const int tokens[STATE_LENGTH] = { + STATE_INTERNAL, STATE_LIMA_VIEWPORT_TRANSFORM + }; + + if (state->transform == NULL) + state->transform = lima_nir_create_array_var( + state->shader, "gl_limaViewportTransform", tokens, 2); + + return nir_load_array_var(&state->b, state->transform, offset); +} + +static nir_ssa_def * +get_scale(lower_viewport_transform_state *state) +{ + return get_transform_offset(state, 0); +} + +static nir_ssa_def * +get_bias(lower_viewport_transform_state *state) +{ + return get_transform_offset(state, 1); +} + +static void +lower_viewport_transform_block(lower_viewport_transform_state *state, nir_block *block) +{ + nir_foreach_instr_safe(instr, block) { + if (instr->type == nir_instr_type_intrinsic) { + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + if (intr->intrinsic == nir_intrinsic_store_var) { + nir_deref_var *dvar = intr->variables[0]; + nir_variable *var = dvar->var; + + if (var->data.mode == nir_var_shader_out && + var->data.location == VARYING_SLOT_POS) { + assert(intr->num_components == 4); + + state->b.cursor = nir_before_instr(instr); + + nir_ssa_def *def = nir_ssa_for_src(&state->b, intr->src[0], intr->num_components); + def = nir_fmul(&state->b, def, get_scale(state)); + def = nir_fadd(&state->b, def, get_bias(state)); + nir_instr_rewrite_src(instr, &intr->src[0], nir_src_for_ssa(def)); + } + } + } + } +} + +static void +lower_viewport_transform_impl(lower_viewport_transform_state *state, nir_function_impl *impl) +{ + nir_builder_init(&state->b, impl); + + nir_foreach_block(block, impl) { + lower_viewport_transform_block(state, block); + } + nir_metadata_preserve(impl, nir_metadata_block_index | + nir_metadata_dominance); +} + +void +lima_nir_lower_viewport_transform(nir_shader *shader) +{ + lower_viewport_transform_state state = { + .shader = shader, + }; + + assert(shader->stage == MESA_SHADER_VERTEX); + + nir_foreach_function(function, shader) { + if (function->impl) + lower_viewport_transform_impl(&state, function->impl); + } +} diff --git a/src/gallium/drivers/lima/lima_program.c b/src/gallium/drivers/lima/lima_program.c index 8ba6511..148c091 100644 --- a/src/gallium/drivers/lima/lima_program.c +++ b/src/gallium/drivers/lima/lima_program.c @@ -209,9 +209,36 @@ lima_delete_vs_state(struct pipe_context *pctx, void *hwcso) FREE(so); } +nir_variable * +lima_nir_create_array_var(nir_shader *shader, const char *name, int *tokens, int n) +{ + nir_variable *var = nir_variable_create( + shader, nir_var_uniform, + glsl_array_type(glsl_vec4_type(), n), + name); + + var->num_state_slots = 1; + var->state_slots = ralloc_array(var, nir_state_slot, 1); + memcpy(var->state_slots[0].tokens, tokens, + sizeof(var->state_slots[0].tokens)); + return var; +} + +static void * +lima_vs_nir_before_finalize(struct pipe_context *pctx, void *pnir) +{ + nir_shader *nir = pnir; + + NIR_PASS_V(nir, lima_nir_lower_viewport_transform); + + return NULL; +} + void lima_program_init(struct lima_context *ctx) { + ctx->base.vs_nir_before_finalize = lima_vs_nir_before_finalize; + ctx->base.create_fs_state = lima_create_fs_state; ctx->base.bind_fs_state = lima_bind_fs_state; ctx->base.delete_fs_state = lima_delete_fs_state; diff --git a/src/gallium/drivers/lima/lima_program.h b/src/gallium/drivers/lima/lima_program.h index 55d970c..5219f18 100644 --- a/src/gallium/drivers/lima/lima_program.h +++ b/src/gallium/drivers/lima/lima_program.h @@ -25,10 +25,20 @@ #ifndef H_LIMA_PROGRAM #define H_LIMA_PROGRAM +#include "program/prog_statevars.h" #include "pipe/p_defines.h" +struct nir_variable; struct nir_shader; +#define STATE_LIMA_VIEWPORT_TRANSFORM (STATE_INTERNAL_DRIVER + 0) + +struct nir_variable *lima_nir_create_array_var( + struct nir_shader *shader, const char *name, + int *tokens, int n); + +void lima_nir_lower_viewport_transform(struct nir_shader *shader); + void lima_program_optimize_nir(struct nir_shader *s); const void *lima_program_get_compiler_options(enum pipe_shader_type shader); -- 1.9.1
From 86ab0e40b225a37d0f5b23c4600a72dfc67185a3 Mon Sep 17 00:00:00 2001 From: Qiang Yu <yuq...@gmail.com> Date: Tue, 29 Aug 2017 14:28:34 +0800 Subject: [PATCH 2/4] nir: add nir_load_array_var This is a helper function for create a load instruction for array var with an index into it. Signed-off-by: Qiang Yu <yuq...@gmail.com> --- src/compiler/nir/nir_builder.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/compiler/nir/nir_builder.h b/src/compiler/nir/nir_builder.h index 7dbf8ef..b3e5b21 100644 --- a/src/compiler/nir/nir_builder.h +++ b/src/compiler/nir/nir_builder.h @@ -544,6 +544,29 @@ nir_load_deref_var(nir_builder *build, nir_deref_var *deref) return &load->dest.ssa; } +static inline nir_ssa_def * +nir_load_array_var(nir_builder *build, nir_variable *var, int offset) +{ + const struct glsl_type *type = glsl_get_array_element(var->type); + const unsigned num_components = glsl_get_vector_elements(type); + + nir_intrinsic_instr *load = + nir_intrinsic_instr_create(build->shader, nir_intrinsic_load_var); + + nir_deref_var *deref = nir_deref_var_create(load, var); + nir_deref_array *deref_arr = nir_deref_array_create(deref); + deref_arr->base_offset = offset; + deref_arr->deref.type = type; + deref->deref.child = &deref_arr->deref; + + load->num_components = num_components; + load->variables[0] = deref; + nir_ssa_dest_init(&load->instr, &load->dest, num_components, + glsl_get_bit_size(type), NULL); + nir_builder_instr_insert(build, &load->instr); + return &load->dest.ssa; +} + static inline void nir_store_var(nir_builder *build, nir_variable *var, nir_ssa_def *value, unsigned writemask) -- 1.9.1
From ddf81a4fc31a9de304865a1af00abf1a0cb997e5 Mon Sep 17 00:00:00 2001 From: Qiang Yu <yuq...@gmail.com> Date: Tue, 29 Aug 2017 10:19:31 +0800 Subject: [PATCH 1/4] gallium/st: add pipe_context::vs_nir_before_finalize This is added for GPU like Mali400 GP which needs to insert some uniform in vertex shader before NIR finalize the uniform position and usage. Signed-off-by: Qiang Yu <yuq...@gmail.com> --- src/gallium/include/pipe/p_context.h | 9 +++++++++ src/mesa/state_tracker/st_program.c | 3 +++ 2 files changed, 12 insertions(+) diff --git a/src/gallium/include/pipe/p_context.h b/src/gallium/include/pipe/p_context.h index 4d5535b..84136f2 100644 --- a/src/gallium/include/pipe/p_context.h +++ b/src/gallium/include/pipe/p_context.h @@ -770,6 +770,15 @@ struct pipe_context { unsigned last_level, unsigned first_layer, unsigned last_layer); + + /** + * Driver specific process of VS nir before finalize + * + * \param ctx pipe context + * \parem nir nir_shader for modification + * \return created data for driver usage + */ + void (*vs_nir_before_finalize)(struct pipe_context *ctx, void *nir); }; diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index 0dc3b1e..0b66e59 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -639,6 +639,9 @@ st_create_vp_variant(struct st_context *st, if (key->passthrough_edgeflags) NIR_PASS_V(vpv->tgsi.ir.nir, nir_lower_passthrough_edgeflags); + if (pipe->vs_nir_before_finalize) + pipe->vs_nir_before_finalize(pipe, vpv->tgsi.ir.nir); + st_finalize_nir(st, &stvp->Base, vpv->tgsi.ir.nir); vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi); -- 1.9.1
_______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev