2017-05-20 16:58:25 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2017 Advanced Micro Devices, Inc.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* on 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 AUTHOR(S) AND/OR THEIR SUPPLIERS 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2019-02-28 09:53:11 +00:00
|
|
|
* Remap load_uniform intrinsics to UBO accesses of UBO binding point 0.
|
2017-05-20 16:58:25 +01:00
|
|
|
* Simultaneously, remap existing UBO accesses by increasing their binding
|
|
|
|
* point by 1.
|
2019-02-28 09:53:11 +00:00
|
|
|
*
|
2020-08-14 21:22:27 +01:00
|
|
|
* Note that nir_intrinsic_load_uniform base/ranges can be set in different
|
|
|
|
* units, and the multiplier argument caters to supporting these different
|
|
|
|
* units.
|
2019-02-28 09:53:11 +00:00
|
|
|
*
|
|
|
|
* For example:
|
2020-08-14 21:22:27 +01:00
|
|
|
* - st_glsl_to_nir for PIPE_CAP_PACKED_UNIFORMS uses dwords (4 bytes) so the
|
|
|
|
* multiplier should be 4
|
|
|
|
* - st_glsl_to_nir for !PIPE_CAP_PACKED_UNIFORMS uses vec4s so the
|
|
|
|
* multiplier should be 16
|
|
|
|
* - tgsi_to_nir uses vec4s, so the multiplier should be 16
|
2017-05-20 16:58:25 +01:00
|
|
|
*/
|
|
|
|
|
2019-02-08 21:36:37 +00:00
|
|
|
#include "nir.h"
|
|
|
|
#include "nir_builder.h"
|
2018-03-09 01:30:01 +00:00
|
|
|
|
2017-05-20 16:58:25 +01:00
|
|
|
static bool
|
2019-02-28 09:53:11 +00:00
|
|
|
lower_instr(nir_intrinsic_instr *instr, nir_builder *b, int multiplier)
|
2017-05-20 16:58:25 +01:00
|
|
|
{
|
|
|
|
b->cursor = nir_before_instr(&instr->instr);
|
|
|
|
|
2019-10-19 00:49:44 +01:00
|
|
|
/* Increase all UBO binding points by 1. */
|
|
|
|
if (instr->intrinsic == nir_intrinsic_load_ubo &&
|
|
|
|
!b->shader->info.first_ubo_is_default_ubo) {
|
2017-05-20 16:58:25 +01:00
|
|
|
nir_ssa_def *old_idx = nir_ssa_for_src(b, instr->src[0], 1);
|
|
|
|
nir_ssa_def *new_idx = nir_iadd(b, old_idx, nir_imm_int(b, 1));
|
|
|
|
nir_instr_rewrite_src(&instr->instr, &instr->src[0],
|
|
|
|
nir_src_for_ssa(new_idx));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (instr->intrinsic == nir_intrinsic_load_uniform) {
|
|
|
|
nir_ssa_def *ubo_idx = nir_imm_int(b, 0);
|
|
|
|
nir_ssa_def *ubo_offset =
|
2019-02-28 09:53:11 +00:00
|
|
|
nir_iadd(b, nir_imm_int(b, multiplier * nir_intrinsic_base(instr)),
|
|
|
|
nir_imul(b, nir_imm_int(b, multiplier),
|
2017-05-20 16:58:25 +01:00
|
|
|
nir_ssa_for_src(b, instr->src[0], 1)));
|
|
|
|
|
|
|
|
nir_intrinsic_instr *load =
|
|
|
|
nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_ubo);
|
|
|
|
load->num_components = instr->num_components;
|
|
|
|
load->src[0] = nir_src_for_ssa(ubo_idx);
|
|
|
|
load->src[1] = nir_src_for_ssa(ubo_offset);
|
2020-03-27 04:56:57 +00:00
|
|
|
assert(instr->dest.ssa.bit_size >= 8);
|
2020-09-09 18:21:49 +01:00
|
|
|
|
|
|
|
/* If it's const, set the alignment to our known constant offset. If
|
|
|
|
* not, set it to a pessimistic value based on the multiplier (or the
|
|
|
|
* scalar size, for qword loads).
|
|
|
|
*
|
|
|
|
* We could potentially set up stricter alignments for indirects by
|
|
|
|
* knowing what features are enabled in the APIs (see comment in
|
|
|
|
* nir_lower_ubo_vec4.c)
|
|
|
|
*/
|
|
|
|
if (nir_src_is_const(instr->src[0])) {
|
|
|
|
nir_intrinsic_set_align(load, NIR_ALIGN_MUL_MAX,
|
|
|
|
(nir_src_as_uint(instr->src[0]) +
|
|
|
|
nir_intrinsic_base(instr) * multiplier) %
|
|
|
|
NIR_ALIGN_MUL_MAX);
|
|
|
|
} else {
|
|
|
|
nir_intrinsic_set_align(load, MAX2(multiplier,
|
|
|
|
instr->dest.ssa.bit_size / 8), 0);
|
|
|
|
}
|
2017-05-20 16:58:25 +01:00
|
|
|
nir_ssa_dest_init(&load->instr, &load->dest,
|
|
|
|
load->num_components, instr->dest.ssa.bit_size,
|
|
|
|
instr->dest.ssa.name);
|
|
|
|
nir_builder_instr_insert(b, &load->instr);
|
2021-03-03 06:13:38 +00:00
|
|
|
nir_ssa_def_rewrite_uses(&instr->dest.ssa, &load->dest.ssa);
|
2017-05-20 16:58:25 +01:00
|
|
|
|
nir: Add a range_base+range to nir_intrinsic_load_ubo().
For UBO accesses to be the same performance as classic GL default uniform
block uniforms, we need to be able to push them through the same path. On
freedreno, we haven't been uploading UBOs as push constants when they're
used for indirect array access, because we don't know what range of the
UBO is needed for an access.
I believe we won't be able to calculate the range in general in spirv
given casts that can happen, so we define a [0, ~0] range to be "We don't
know anything". We use that at the moment for all UBO loads except for
nir_lower_uniforms_to_ubo, where we now avoid losing the range information
that default uniform block loads come with.
In a departure from other NIR intrinsics with a "base", I didn't make the
base an be something you have to add to the src[1] offset. This keeps us
from needing to modify all drivers (particularly since the base+offset
thing can mean needing to do addition in the backend), makes backend
tracking of ranges easy, and makes the range calculations in
load_store_vectorizer reasonable. However, this could definitely cause
some confusion for people used to the normal NIR base.
Reviewed-by: Kristian H. Kristensen <hoegsberg@google.com>
Reviewed-by: Rob Clark <robdclark@chromium.org>
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6359>
2020-08-14 21:10:02 +01:00
|
|
|
nir_intrinsic_set_range_base(load, nir_intrinsic_base(instr) * multiplier);
|
|
|
|
nir_intrinsic_set_range(load, nir_intrinsic_range(instr) * multiplier);
|
|
|
|
|
2017-05-20 16:58:25 +01:00
|
|
|
nir_instr_remove(&instr->instr);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2019-02-28 09:53:11 +00:00
|
|
|
nir_lower_uniforms_to_ubo(nir_shader *shader, int multiplier)
|
2017-05-20 16:58:25 +01:00
|
|
|
{
|
|
|
|
bool progress = false;
|
|
|
|
|
|
|
|
nir_foreach_function(function, shader) {
|
|
|
|
if (function->impl) {
|
|
|
|
nir_builder builder;
|
|
|
|
nir_builder_init(&builder, function->impl);
|
|
|
|
nir_foreach_block(block, function->impl) {
|
|
|
|
nir_foreach_instr_safe(instr, block) {
|
|
|
|
if (instr->type == nir_instr_type_intrinsic)
|
|
|
|
progress |= lower_instr(nir_instr_as_intrinsic(instr),
|
2019-02-28 09:53:11 +00:00
|
|
|
&builder,
|
|
|
|
multiplier);
|
2017-05-20 16:58:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nir_metadata_preserve(function->impl, nir_metadata_block_index |
|
|
|
|
nir_metadata_dominance);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-14 07:14:07 +00:00
|
|
|
if (progress) {
|
|
|
|
if (!shader->info.first_ubo_is_default_ubo) {
|
2020-07-30 00:27:35 +01:00
|
|
|
nir_foreach_variable_with_modes(var, shader, nir_var_mem_ubo) {
|
2020-07-21 17:22:23 +01:00
|
|
|
var->data.binding++;
|
2020-07-30 00:27:35 +01:00
|
|
|
/* only increment location for ubo arrays */
|
|
|
|
if (glsl_without_array(var->type) == var->interface_type &&
|
|
|
|
glsl_type_is_array(var->type))
|
|
|
|
var->data.location++;
|
|
|
|
}
|
2020-02-14 07:14:07 +00:00
|
|
|
}
|
2020-05-11 19:53:22 +01:00
|
|
|
shader->info.num_ubos++;
|
2020-02-14 07:14:07 +00:00
|
|
|
|
|
|
|
if (shader->num_uniforms > 0) {
|
|
|
|
const struct glsl_type *type = glsl_array_type(glsl_vec4_type(),
|
|
|
|
shader->num_uniforms, 0);
|
|
|
|
nir_variable *ubo = nir_variable_create(shader, nir_var_mem_ubo, type,
|
|
|
|
"uniform_0");
|
|
|
|
ubo->data.binding = 0;
|
2020-12-02 16:40:33 +00:00
|
|
|
ubo->data.explicit_binding = 1;
|
2020-02-14 07:14:07 +00:00
|
|
|
|
|
|
|
struct glsl_struct_field field = {
|
|
|
|
.type = type,
|
|
|
|
.name = "data",
|
|
|
|
.location = -1,
|
|
|
|
};
|
|
|
|
ubo->interface_type =
|
|
|
|
glsl_interface_type(&field, 1, GLSL_INTERFACE_PACKING_STD430,
|
|
|
|
false, "__ubo0_interface");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-19 00:49:44 +01:00
|
|
|
shader->info.first_ubo_is_default_ubo = true;
|
2017-05-20 16:58:25 +01:00
|
|
|
return progress;
|
|
|
|
}
|