diff options
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/glsl/gl_nir_link_xfb.c | 240 |
1 files changed, 54 insertions, 186 deletions
diff --git a/src/compiler/glsl/gl_nir_link_xfb.c b/src/compiler/glsl/gl_nir_link_xfb.c index f75c99ca852..bd40ce0efdd 100644 --- a/src/compiler/glsl/gl_nir_link_xfb.c +++ b/src/compiler/glsl/gl_nir_link_xfb.c @@ -22,10 +22,11 @@ */ #include "nir.h" +#include "nir_xfb_info.h" #include "gl_nir_linker.h" -#include "ir_uniform.h" /* for gl_uniform_storage */ #include "linker_util.h" #include "main/context.h" +#include "util/u_math.h" /* * This file does the linking of GLSL transform feedback using NIR. @@ -34,160 +35,6 @@ * particularities. */ -struct active_xfb_buffer { - GLuint stride; - GLuint num_varyings; -}; - -struct active_xfb_varyings { - unsigned num_varyings; - unsigned num_outputs; - unsigned buffer_size; - struct nir_variable **varyings; - struct active_xfb_buffer buffers[MAX_FEEDBACK_BUFFERS]; -}; - -static unsigned -get_num_outputs(nir_variable *var) -{ - return glsl_count_attribute_slots(var->type, - false /* is_vertex_input */); -} - -static void -add_xfb_varying(struct active_xfb_varyings *active_varyings, - nir_variable *var) -{ - if (active_varyings->num_varyings >= active_varyings->buffer_size) { - if (active_varyings->buffer_size == 0) - active_varyings->buffer_size = 1; - else - active_varyings->buffer_size *= 2; - - active_varyings->varyings = realloc(active_varyings->varyings, - sizeof(nir_variable*) * - active_varyings->buffer_size); - } - - active_varyings->varyings[active_varyings->num_varyings++] = var; - - active_varyings->num_outputs += get_num_outputs(var); -} - -static int -cmp_xfb_offset(const void *x_generic, const void *y_generic) -{ - const nir_variable *const *x = x_generic; - const nir_variable *const *y = y_generic; - - if ((*x)->data.xfb_buffer != (*y)->data.xfb_buffer) - return (*x)->data.xfb_buffer - (*y)->data.xfb_buffer; - return (*x)->data.offset - (*y)->data.offset; -} - -static void -get_active_xfb_varyings(struct gl_shader_program *prog, - struct active_xfb_varyings *active_varyings) -{ - for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) { - struct gl_linked_shader *sh = prog->_LinkedShaders[i]; - if (sh == NULL) - continue; - - nir_shader *nir = sh->Program->nir; - - nir_foreach_variable(var, &nir->outputs) { - if (var->data.explicit_xfb_buffer && - var->data.explicit_xfb_stride) { - assert(var->data.xfb_buffer < MAX_FEEDBACK_BUFFERS); - active_varyings->buffers[var->data.xfb_buffer].stride = - var->data.xfb_stride; - } - - if (!var->data.explicit_xfb_buffer || - !var->data.explicit_offset) - continue; - - active_varyings->buffers[var->data.xfb_buffer].num_varyings++; - - add_xfb_varying(active_varyings, var); - } - } - - /* The xfb_offset qualifier does not have to be used in increasing order - * however some drivers expect to receive the list of transform feedback - * declarations in order so sort it now for convenience. - */ - qsort(active_varyings->varyings, - active_varyings->num_varyings, - sizeof(*active_varyings->varyings), - cmp_xfb_offset); -} - -static unsigned -add_varying_outputs(nir_variable *var, - const struct glsl_type *type, - unsigned location_offset, - unsigned dest_offset, - struct gl_transform_feedback_output *output) -{ - unsigned num_outputs = 0; - - if (glsl_type_is_array(type) || glsl_type_is_matrix(type)) { - unsigned length = glsl_get_length(type); - const struct glsl_type *child_type = glsl_get_array_element(type); - unsigned component_slots = glsl_get_component_slots(child_type); - - for (unsigned i = 0; i < length; i++) { - unsigned child_outputs = add_varying_outputs(var, - child_type, - location_offset, - dest_offset, - output + num_outputs); - num_outputs += child_outputs; - location_offset += child_outputs; - dest_offset += component_slots; - } - } else if (glsl_type_is_struct_or_ifc(type)) { - unsigned length = glsl_get_length(type); - for (unsigned i = 0; i < length; i++) { - const struct glsl_type *child_type = glsl_get_struct_field(type, i); - unsigned child_outputs = add_varying_outputs(var, - child_type, - location_offset, - dest_offset, - output + num_outputs); - num_outputs += child_outputs; - location_offset += child_outputs; - dest_offset += glsl_get_component_slots(child_type); - } - } else { - unsigned location = var->data.location + location_offset; - unsigned location_frac = var->data.location_frac; - unsigned num_components = glsl_get_component_slots(type); - - while (num_components > 0) { - unsigned output_size = MIN2(num_components, 4 - location_frac); - - output->OutputRegister = location; - output->OutputBuffer = var->data.xfb_buffer; - output->NumComponents = output_size; - output->StreamId = var->data.stream; - output->DstOffset = var->data.offset / 4 + dest_offset; - output->ComponentOffset = location_frac; - - dest_offset += output_size; - num_components -= output_size; - num_outputs++; - output++; - location++; - location_frac = 0; - } - } - - return num_outputs; -} - void gl_nir_link_assign_xfb_resources(struct gl_context *ctx, struct gl_shader_program *prog) @@ -220,36 +67,51 @@ gl_nir_link_assign_xfb_resources(struct gl_context *ctx, free(prog->TransformFeedback.VaryingNames[i]); free(prog->TransformFeedback.VaryingNames); - struct active_xfb_varyings active_varyings = { 0 }; + nir_xfb_info *xfb_info = NULL; - get_active_xfb_varyings(prog, &active_varyings); + /* Find last stage before fragment shader */ + for (int stage = MESA_SHADER_FRAGMENT - 1; stage >= 0; stage--) { + struct gl_linked_shader *sh = prog->_LinkedShaders[stage]; - for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++) - prog->TransformFeedback.BufferStride[buf] = active_varyings.buffers[buf].stride; - - prog->TransformFeedback.NumVarying = active_varyings.num_varyings; - prog->TransformFeedback.VaryingNames = - malloc(sizeof(GLchar *) * active_varyings.num_varyings); + if (sh && stage != MESA_SHADER_TESS_CTRL) { + xfb_info = nir_gather_xfb_info(sh->Program->nir, NULL); + break; + } + } struct gl_transform_feedback_info *linked_xfb = rzalloc(xfb_prog, struct gl_transform_feedback_info); xfb_prog->sh.LinkedTransformFeedback = linked_xfb; + if (!xfb_info) { + prog->TransformFeedback.NumVarying = 0; + linked_xfb->NumOutputs = 0; + linked_xfb->NumVarying = 0; + linked_xfb->ActiveBuffers = 0; + return; + } + + for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++) + prog->TransformFeedback.BufferStride[buf] = xfb_info->buffers[buf].stride; + + prog->TransformFeedback.NumVarying = xfb_info->varying_count; + prog->TransformFeedback.VaryingNames = + malloc(sizeof(GLchar *) * xfb_info->varying_count); + linked_xfb->Outputs = rzalloc_array(xfb_prog, struct gl_transform_feedback_output, - active_varyings.num_outputs); - linked_xfb->NumOutputs = active_varyings.num_outputs; + xfb_info->output_count); + linked_xfb->NumOutputs = xfb_info->output_count; linked_xfb->Varyings = rzalloc_array(xfb_prog, struct gl_transform_feedback_varying_info, - active_varyings.num_varyings); - linked_xfb->NumVarying = active_varyings.num_varyings; + xfb_info->varying_count); + linked_xfb->NumVarying = xfb_info->varying_count; - struct gl_transform_feedback_output *output = linked_xfb->Outputs; - for (unsigned i = 0; i < active_varyings.num_varyings; i++) { - struct nir_variable *var = active_varyings.varyings[i]; + for (unsigned i = 0; i < xfb_info->varying_count; i++) { + nir_xfb_varying_info *xfb_varying = &xfb_info->varyings[i]; /* From ARB_gl_spirv spec: * @@ -277,23 +139,29 @@ gl_nir_link_assign_xfb_resources(struct gl_context *ctx, */ prog->TransformFeedback.VaryingNames[i] = NULL; - unsigned varying_outputs = add_varying_outputs(var, - var->type, - 0, /* location_offset */ - 0, /* dest_offset */ - output); - assert(varying_outputs == get_num_outputs(var)); - output = output + varying_outputs; - struct gl_transform_feedback_varying_info *varying = linked_xfb->Varyings + i; /* ARB_gl_spirv: see above. */ varying->Name = NULL; - varying->Type = glsl_get_gl_type(var->type); - varying->BufferIndex = var->data.xfb_buffer; - varying->Size = glsl_get_length(var->type); - varying->Offset = var->data.offset; + varying->Type = glsl_get_gl_type(xfb_varying->type); + varying->BufferIndex = xfb_varying->buffer; + varying->Size = glsl_get_length(xfb_varying->type); + varying->Offset = xfb_varying->offset; + } + + for (unsigned i = 0; i < xfb_info->output_count; i++) { + nir_xfb_output_info *xfb_output = &xfb_info->outputs[i]; + + struct gl_transform_feedback_output *output = + linked_xfb->Outputs + i; + + output->OutputRegister = xfb_output->location; + output->OutputBuffer = xfb_output->buffer; + output->NumComponents = util_bitcount(xfb_output->component_mask); + output->StreamId = xfb_info->buffer_to_stream[xfb_output->buffer]; + output->DstOffset = xfb_output->offset / 4; + output->ComponentOffset = xfb_output->component_offset; } /* Make sure MaxTransformFeedbackBuffers is <= 32 so the bitmask for @@ -303,14 +171,14 @@ gl_nir_link_assign_xfb_resources(struct gl_context *ctx, assert(ctx->Const.MaxTransformFeedbackBuffers <= sizeof(buffers) * 8); for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++) { - if (active_varyings.buffers[buf].stride > 0) { - linked_xfb->Buffers[buf].Stride = active_varyings.buffers[buf].stride / 4; - linked_xfb->Buffers[buf].NumVaryings = active_varyings.buffers[buf].num_varyings; + if (xfb_info->buffers[buf].stride > 0) { + linked_xfb->Buffers[buf].Stride = xfb_info->buffers[buf].stride / 4; + linked_xfb->Buffers[buf].NumVaryings = xfb_info->buffers[buf].varying_count; buffers |= 1 << buf; } } linked_xfb->ActiveBuffers = buffers; - free(active_varyings.varyings); + ralloc_free(xfb_info); } |