| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- /*
- * Copyright © 2018 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 "nir.h"
- #include "nir_xfb_info.h"
- #include "gl_nir_linker.h"
- #include "linker_util.h"
- #include "main/context.h"
- #include "util/u_math.h"
-
- /*
- * This file does the linking of GLSL transform feedback using NIR.
- *
- * Note: This linking pass is currently tailored for ARB_gl_spirv needs and
- * particularities.
- */
-
- void
- gl_nir_link_assign_xfb_resources(struct gl_context *ctx,
- struct gl_shader_program *prog)
- {
- /*
- * From ARB_gl_spirv spec:
- *
- * "- If the *Xfb* Execution Mode is set, any output variable that is at
- * least partially captured:
- * * must be decorated with an *XfbBuffer*, declaring the capturing buffer
- * * must have at least one captured output variable in the capturing
- * buffer decorated with an *XfbStride* (and all such *XfbStride* values
- * for the capturing buffer must be equal)
- * - If the *Xfb* Execution Mode is set, any captured output:
- * * must be a non-structure decorated with *Offset* or a member of a
- * structure whose type member is decorated with *Offset*"
- *
- * Note the "must be", meaning that explicit buffer, offset and stride are
- * mandatory. So as this is intended to work with SPIR-V shaders we don't
- * need to calculate the offset or the stride.
- */
-
- struct gl_program *xfb_prog = prog->last_vert_prog;
-
- if (xfb_prog == NULL)
- return;
-
- /* free existing varyings, if any */
- for (unsigned i = 0; i < prog->TransformFeedback.NumVarying; i++)
- free(prog->TransformFeedback.VaryingNames[i]);
- free(prog->TransformFeedback.VaryingNames);
-
- nir_xfb_info *xfb_info = NULL;
-
- /* Find last stage before fragment shader */
- for (int stage = MESA_SHADER_FRAGMENT - 1; stage >= 0; stage--) {
- struct gl_linked_shader *sh = prog->_LinkedShaders[stage];
-
- 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,
- xfb_info->output_count);
- linked_xfb->NumOutputs = xfb_info->output_count;
-
- linked_xfb->Varyings =
- rzalloc_array(xfb_prog,
- struct gl_transform_feedback_varying_info,
- xfb_info->varying_count);
- linked_xfb->NumVarying = xfb_info->varying_count;
-
- int buffer_index = 0; /* Corresponds to GL_TRANSFORM_FEEDBACK_BUFFER_INDEX */
- int xfb_buffer =
- (xfb_info->varying_count > 0) ?
- xfb_info->outputs[0].buffer : 0;
-
- 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:
- *
- * "19. How should the program interface query operations behave for
- * program objects created from SPIR-V shaders?
- *
- * DISCUSSION: we previously said we didn't need reflection to work
- * for SPIR-V shaders (at least for the first version), however we
- * are left with specifying how it should "not work". The primary
- * issue is that SPIR-V binaries are not required to have names
- * associated with variables. They can be associated in debug
- * information, but there is no requirement for that to be present,
- * and it should not be relied upon."
- *
- * Options:"
- *
- * <skip>
- *
- * "RESOLVED. Pick (c), but also allow debug names to be returned
- * if an implementation wants to."
- *
- * So names are considered optional debug info, so the linker needs to
- * work without them, and returning them is optional. For simplicity at
- * this point we are ignoring names
- */
- prog->TransformFeedback.VaryingNames[i] = NULL;
-
- if (xfb_buffer != xfb_varying->buffer) {
- buffer_index++;
- xfb_buffer = xfb_varying->buffer;
- }
-
- 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(xfb_varying->type);
- varying->BufferIndex = buffer_index;
- varying->Size = glsl_type_is_array(xfb_varying->type) ?
- glsl_get_length(xfb_varying->type) : 1;
- 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
- * tracking the number of buffers doesn't overflow.
- */
- unsigned buffers = 0;
- assert(ctx->Const.MaxTransformFeedbackBuffers <= sizeof(buffers) * 8);
-
- for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++) {
- 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;
-
- ralloc_free(xfb_info);
- }
|