* two locations. For instance, if we have in the IR code a dvec3 attr0 in
* location 0 and vec4 attr1 in location 1, in NIR attr0 will use
* locations/slots 0 and 1, and attr1 will use location/slot 2 */
- if (shader->info.stage == MESA_SHADER_VERTEX)
- nir_remap_attributes(shader, options);
+ if (shader->info.stage == MESA_SHADER_VERTEX) {
+ sh->Program->DualSlotInputs = nir_get_dual_slot_attributes(shader);
+ if (options->vs_inputs_dual_locations)
+ nir_remap_dual_slot_attributes(shader, sh->Program->DualSlotInputs);
+ }
shader->info.name = ralloc_asprintf(shader, "GLSL%d", shader_prog->Name);
if (shader_prog->Label)
var->data.compact = ir->type->without_array()->is_scalar();
}
}
-
- /* Mark all the locations that require two slots */
- if (shader->info.stage == MESA_SHADER_VERTEX &&
- glsl_type_is_dual_slot(glsl_without_array(var->type))) {
- for (unsigned i = 0; i < glsl_count_attribute_slots(var->type, true); i++) {
- uint64_t bitfield = BITFIELD64_BIT(var->data.location + i);
- shader->info.vs.double_inputs |= bitfield;
- }
- }
break;
case ir_var_shader_out:
/* double inputs read is only for vertex inputs */
if (stage == MESA_SHADER_VERTEX &&
var->type->without_array()->is_dual_slot())
- prog->info.vs.double_inputs_read |= bitfield;
+ prog->DualSlotInputs |= bitfield;
if (stage == MESA_SHADER_FRAGMENT) {
prog->info.fs.uses_sample_qualifier |= var->data.sample;
struct gl_program *glprog = shader->Program;
unsigned i;
+ blob_write_uint64(metadata, glprog->DualSlotInputs);
blob_write_bytes(metadata, glprog->TexturesUsed,
sizeof(glprog->TexturesUsed));
blob_write_uint64(metadata, glprog->SamplersUsed);
{
unsigned i;
+ glprog->DualSlotInputs = blob_read_uint64(metadata);
blob_copy_bytes(metadata, (uint8_t *) glprog->TexturesUsed,
sizeof(glprog->TexturesUsed));
glprog->SamplersUsed = blob_read_uint64(metadata);
}
}
+uint64_t
+nir_get_dual_slot_attributes(nir_shader *shader)
+{
+ assert(shader->info.stage == MESA_SHADER_VERTEX);
+
+ uint64_t dual_slot = 0;
+ nir_foreach_variable(var, &shader->inputs) {
+ if (glsl_type_is_dual_slot(glsl_without_array(var->type))) {
+ unsigned slots = glsl_count_attribute_slots(var->type, true);
+ dual_slot |= BITFIELD64_MASK(slots) << var->data.location;
+ }
+ }
+
+ return dual_slot;
+}
+
/* OpenGL utility method that remaps the location attributes if they are
* doubles. Not needed for vulkan due the differences on the input location
* count for doubles on vulkan vs OpenGL
*/
void
-nir_remap_attributes(nir_shader *shader,
- const nir_shader_compiler_options *options)
-{
- if (options->vs_inputs_dual_locations) {
- nir_foreach_variable(var, &shader->inputs) {
- var->data.location +=
- _mesa_bitcount_64(shader->info.vs.double_inputs &
- BITFIELD64_MASK(var->data.location));
- }
+nir_remap_dual_slot_attributes(nir_shader *shader, uint64_t dual_slot)
+{
+ assert(shader->info.stage == MESA_SHADER_VERTEX);
+
+ nir_foreach_variable(var, &shader->inputs) {
+ var->data.location +=
+ _mesa_bitcount_64(dual_slot & BITFIELD64_MASK(var->data.location));
}
+}
- /* Once the remap is done, reset double_inputs_read, so later it will have
- * which location/slots are doubles */
- shader->info.vs.double_inputs = 0;
+/* Returns an attribute mask that has been re-compacted using the given
+ * dual_slot mask.
+ */
+uint64_t
+nir_get_single_slot_attribs_mask(uint64_t attribs, uint64_t dual_slot)
+{
+ while (dual_slot) {
+ unsigned loc = u_bit_scan64(&dual_slot);
+ /* mask of all bits up to and including loc */
+ uint64_t mask = BITFIELD64_MASK(loc + 1);
+ attribs = (attribs & mask) | ((attribs & ~mask) >> 1);
+ }
+ return attribs;
}
void nir_sweep(nir_shader *shader);
-void nir_remap_attributes(nir_shader *shader,
- const nir_shader_compiler_options *options);
+uint64_t nir_get_dual_slot_attributes(nir_shader *shader);
+void nir_remap_dual_slot_attributes(nir_shader *shader,
+ uint64_t dual_slot);
+uint64_t nir_get_single_slot_attribs_mask(uint64_t attribs, uint64_t dual_slot);
nir_intrinsic_op nir_intrinsic_from_system_value(gl_system_value val);
gl_system_value nir_system_value_from_intrinsic(nir_intrinsic_op intrin);
else
shader->info.inputs_read |= bitfield;
- /* double inputs read is only for vertex inputs */
- if (shader->info.stage == MESA_SHADER_VERTEX &&
- glsl_type_is_dual_slot(glsl_without_array(var->type)))
- shader->info.vs.double_inputs_read |= bitfield;
-
if (shader->info.stage == MESA_SHADER_FRAGMENT) {
shader->info.fs.uses_sample_qualifier |= var->data.sample;
}
shader->info.system_values_read = 0;
if (shader->info.stage == MESA_SHADER_VERTEX) {
shader->info.vs.double_inputs = 0;
- shader->info.vs.double_inputs_read = 0;
}
if (shader->info.stage == MESA_SHADER_FRAGMENT) {
shader->info.fs.uses_sample_qualifier = false;
struct {
/* Which inputs are doubles */
uint64_t double_inputs;
-
- /* Which inputs are actually read and are double */
- uint64_t double_inputs_read;
} vs;
struct {
#include "main/enums.h"
#include "main/macros.h"
#include "main/glformats.h"
+#include "nir.h"
#include "brw_draw.h"
#include "brw_defines.h"
{
const struct gen_device_info *devinfo = &brw->screen->devinfo;
struct gl_context *ctx = &brw->ctx;
+ /* BRW_NEW_VERTEX_PROGRAM */
+ const struct gl_program *vp = brw->programs[MESA_SHADER_VERTEX];
/* BRW_NEW_VS_PROG_DATA */
const struct brw_vs_prog_data *vs_prog_data =
brw_vs_prog_data(brw->vs.base.prog_data);
- GLbitfield64 vs_inputs = vs_prog_data->inputs_read;
+ GLbitfield64 vs_inputs =
+ nir_get_single_slot_attribs_mask(vs_prog_data->inputs_read,
+ vp->DualSlotInputs);
const unsigned char *ptr = NULL;
GLuint interleaved = 0;
unsigned int min_index = brw->vb.min_index + brw->basevertex;
/* Accumulate the list of enabled arrays. */
brw->vb.nr_enabled = 0;
while (vs_inputs) {
- GLuint first = ffsll(vs_inputs) - 1;
- assert (first < 64);
- GLuint index =
- first - DIV_ROUND_UP(_mesa_bitcount_64(vs_prog_data->double_inputs_read &
- BITFIELD64_MASK(first)), 2);
+ const unsigned index = ffsll(vs_inputs) - 1;
+ assert(index < 64);
+
struct brw_vertex_element *input = &brw->vb.inputs[index];
- input->is_dual_slot = (vs_prog_data->double_inputs_read & BITFIELD64_BIT(first)) != 0;
- vs_inputs &= ~BITFIELD64_BIT(first);
- if (input->is_dual_slot)
- vs_inputs &= ~BITFIELD64_BIT(first + 1);
+ input->is_dual_slot = (vp->DualSlotInputs & BITFIELD64_BIT(index)) != 0;
+ vs_inputs &= ~BITFIELD64_BIT(index);
brw->vb.enabled[brw->vb.nr_enabled++] = input;
}
.mesa = _NEW_POLYGON,
.brw = BRW_NEW_BATCH |
BRW_NEW_BLORP |
+ BRW_NEW_VERTEX_PROGRAM |
BRW_NEW_VERTICES |
BRW_NEW_VS_PROG_DATA,
},
prog->last_vert_prog = prog->_LinkedShaders[last_vert_stage - 1]->Program;
}
-static void
-nir_compute_double_inputs(nir_shader *shader,
- const nir_shader_compiler_options *options)
-{
- nir_foreach_variable(var, &shader->inputs) {
- if (glsl_type_is_dual_slot(glsl_without_array(var->type))) {
- for (unsigned i = 0; i < glsl_count_attribute_slots(var->type, true); i++) {
- uint64_t bitfield = BITFIELD64_BIT(var->data.location + i);
- shader->info.vs.double_inputs |= bitfield;
- }
- }
- }
-}
-
nir_shader *
_mesa_spirv_to_nir(struct gl_context *ctx,
const struct gl_shader_program *prog,
NIR_PASS_V(nir, nir_split_per_member_structs);
if (nir->info.stage == MESA_SHADER_VERTEX) {
- nir_compute_double_inputs(nir, options);
- nir_remap_attributes(nir, options);
+ uint64_t dual_slot_inputs = nir_get_dual_slot_attributes(nir);
+ if (options->vs_inputs_dual_locations)
+ nir_remap_dual_slot_attributes(nir, dual_slot_inputs);
+ linked_shader->Program->DualSlotInputs = dual_slot_inputs;
}
return nir;
/** Is this program written to on disk shader cache */
bool program_written_to_cache;
+ /** A bitfield indicating which vertex shader inputs consume two slots
+ *
+ * This is used for mapping from single-slot input locations in the GL API
+ * to dual-slot double input locations in the shader. This field is set
+ * once as part of linking and never updated again to ensure the mapping
+ * remains consistent.
+ *
+ * Note: There may be dual-slot variables in the original shader source
+ * which do not appear in this bitfield due to having been eliminated by
+ * the compiler prior to DualSlotInputs being calculated. There may also
+ * be bits set in this bitfield which are set but which the shader never
+ * reads due to compiler optimizations eliminating such variables after
+ * DualSlotInputs is calculated.
+ */
+ GLbitfield64 DualSlotInputs;
/** Subset of OutputsWritten outputs written with non-zero index. */
GLbitfield64 SecondaryOutputsWritten;
/** TEXTURE_x_BIT bitmask */
if ((prog->info.inputs_read & BITFIELD64_BIT(attr)) != 0) {
input_to_index[attr] = num_inputs;
num_inputs++;
- if ((prog->info.vs.double_inputs_read & BITFIELD64_BIT(attr)) != 0) {
+ if ((prog->DualSlotInputs & BITFIELD64_BIT(attr)) != 0) {
/* add placeholder for second part of a double attribute */
num_inputs++;
}
_mesa_copy_linked_program_data(shader_program, shader);
shrink_array_declarations(v->inputs, v->num_inputs,
&prog->info.inputs_read,
- prog->info.vs.double_inputs_read,
+ prog->DualSlotInputs,
&prog->info.patch_inputs_read);
shrink_array_declarations(v->outputs, v->num_outputs,
&prog->info.outputs_written, 0ULL,
stvp->input_to_index[attr] = stvp->num_inputs;
stvp->index_to_input[stvp->num_inputs] = attr;
stvp->num_inputs++;
- if ((stvp->Base.info.vs.double_inputs_read &
- BITFIELD64_BIT(attr)) != 0) {
+ if ((stvp->Base.DualSlotInputs & BITFIELD64_BIT(attr)) != 0) {
/* add placeholder for second part of a double attribute */
stvp->index_to_input[stvp->num_inputs] = ST_DOUBLE_ATTRIB_PLACEHOLDER;
stvp->num_inputs++;