From: Jason Ekstrand Date: Fri, 30 Oct 2015 05:24:54 +0000 (-0700) Subject: anv: Add better push constant support X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3883728730f293b763a5641560375b18d4f97782;p=mesa.git anv: Add better push constant support What we had before was kind of a hack where we made certain untrue assumptions about the incoming data. This new support, while it still doesn't support indirects properly (that will come), at least pulls the offsets and strides from SPIR-V like it's supposed to. --- diff --git a/src/vulkan/Makefile.am b/src/vulkan/Makefile.am index 475fa4f2ad2..0d6c9df6b67 100644 --- a/src/vulkan/Makefile.am +++ b/src/vulkan/Makefile.am @@ -69,6 +69,7 @@ VULKAN_SOURCES = \ anv_meta.c \ anv_nir_apply_dynamic_offsets.c \ anv_nir_apply_pipeline_layout.c \ + anv_nir_lower_push_constants.c \ anv_pass.c \ anv_pipeline.c \ anv_private.h \ diff --git a/src/vulkan/anv_nir.h b/src/vulkan/anv_nir.h index af95e3a8849..b164ae581e1 100644 --- a/src/vulkan/anv_nir.h +++ b/src/vulkan/anv_nir.h @@ -37,6 +37,8 @@ anv_vk_shader_stage_for_mesa_stage(gl_shader_stage stage) return (VkShaderStage)(int)stage; } +void anv_nir_lower_push_constants(nir_shader *shader, bool is_scalar); + void anv_nir_apply_dynamic_offsets(struct anv_pipeline *pipeline, nir_shader *shader, struct brw_stage_prog_data *prog_data); diff --git a/src/vulkan/anv_nir_lower_push_constants.c b/src/vulkan/anv_nir_lower_push_constants.c new file mode 100644 index 00000000000..af48470522a --- /dev/null +++ b/src/vulkan/anv_nir_lower_push_constants.c @@ -0,0 +1,107 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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, sublicense, + * 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 NONINFRINGEMENT. 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 "anv_nir.h" + +struct lower_push_constants_state { + nir_shader *shader; + bool is_scalar; +}; + +static bool +lower_push_constants_block(nir_block *block, void *void_state) +{ + struct lower_push_constants_state *state = void_state; + + nir_foreach_instr(block, instr) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + + /* TODO: Handle indirect push constants */ + if (intrin->intrinsic != nir_intrinsic_load_push_constant) + continue; + + assert(intrin->const_index[0] % 4 == 0); + unsigned dword_offset = intrin->const_index[0] / 4; + + /* We just turn them into uniform loads with the appropreate offset */ + intrin->intrinsic = nir_intrinsic_load_uniform; + intrin->const_index[0] = 0; + if (state->is_scalar) { + intrin->const_index[1] = dword_offset; + } else { + unsigned shift = dword_offset % 4; + /* Can't cross the vec4 boundary */ + assert(shift + intrin->num_components <= 4); + + /* vec4 shifts are in units of vec4's */ + intrin->const_index[1] = dword_offset / 4; + + if (shift) { + /* If there's a non-zero shift then we need to load a whole vec4 + * and use a move to swizzle it into place. + */ + assert(intrin->dest.is_ssa); + nir_alu_instr *mov = nir_alu_instr_create(state->shader, + nir_op_imov); + mov->src[0].src = nir_src_for_ssa(&intrin->dest.ssa); + for (unsigned i = 0; i < intrin->num_components; i++) + mov->src[0].swizzle[i] = i + shift; + mov->dest.write_mask = (1 << intrin->num_components) - 1; + nir_ssa_dest_init(&intrin->instr, &intrin->dest, + intrin->num_components, NULL); + + nir_ssa_def_rewrite_uses(&intrin->dest.ssa, + nir_src_for_ssa(&mov->dest.dest.ssa)); + nir_instr_insert_after(&intrin->instr, &mov->instr); + + /* Stomp the number of components to 4 */ + intrin->num_components = 4; + } + } + } + + return true; +} + +void +anv_nir_lower_push_constants(nir_shader *shader, bool is_scalar) +{ + struct lower_push_constants_state state = { + .shader = shader, + .is_scalar = is_scalar, + }; + + nir_foreach_overload(shader, overload) { + if (overload->impl) + nir_foreach_block(overload->impl, lower_push_constants_block, &state); + } + + assert(shader->num_uniforms % 4 == 0); + if (is_scalar) + shader->num_uniforms /= 4; + else + shader->num_uniforms = DIV_ROUND_UP(shader->num_uniforms, 16); +} diff --git a/src/vulkan/anv_pipeline.c b/src/vulkan/anv_pipeline.c index 59f304f55df..9fb5ddba20b 100644 --- a/src/vulkan/anv_pipeline.c +++ b/src/vulkan/anv_pipeline.c @@ -357,22 +357,12 @@ anv_pipeline_compile(struct anv_pipeline *pipeline, if (nir == NULL) return NULL; - bool have_push_constants = false; - nir_foreach_variable(var, &nir->uniforms) { - const struct glsl_type *type = var->type; - if (glsl_type_is_array(type)) - type = glsl_get_array_element(type); - - if (!glsl_type_is_sampler(type)) { - have_push_constants = true; - break; - } - } + anv_nir_lower_push_constants(nir, is_scalar_shader_stage(compiler, stage)); /* Figure out the number of parameters */ prog_data->nr_params = 0; - if (have_push_constants) { + if (nir->num_uniforms > 0) { /* If the shader uses any push constants at all, we'll just give * them the maximum possible number */ @@ -394,7 +384,7 @@ anv_pipeline_compile(struct anv_pipeline *pipeline, * params array, it doesn't really matter what we put here. */ struct anv_push_constants *null_data = NULL; - if (have_push_constants) { + if (nir->num_uniforms > 0) { /* Fill out the push constants section of the param array */ for (unsigned i = 0; i < MAX_PUSH_CONSTANTS_SIZE / sizeof(float); i++) prog_data->param[i] = (const gl_constant_value *)