1/* 2 * Copyright © 2018 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "nir.h" 25#include "nir_gl_types.h" 26#include "nir_xfb_info.h" 27#include "gl_nir_linker.h" 28#include "linker_util.h" 29#include "util/u_math.h" 30#include "main/shader_types.h" 31#include "main/consts_exts.h" 32 33/** 34 * This file does the linking of GLSL transform feedback using NIR. 35 */ 36 37void 38gl_nir_link_assign_xfb_resources(const struct gl_constants *consts, 39 struct gl_shader_program *prog) 40{ 41 /* 42 * From ARB_gl_spirv spec: 43 * 44 * "- If the *Xfb* Execution Mode is set, any output variable that is at 45 * least partially captured: 46 * * must be decorated with an *XfbBuffer*, declaring the capturing buffer 47 * * must have at least one captured output variable in the capturing 48 * buffer decorated with an *XfbStride* (and all such *XfbStride* values 49 * for the capturing buffer must be equal) 50 * - If the *Xfb* Execution Mode is set, any captured output: 51 * * must be a non-structure decorated with *Offset* or a member of a 52 * structure whose type member is decorated with *Offset*" 53 * 54 * Note the "must be", meaning that explicit buffer, offset and stride are 55 * mandatory. So as this is intended to work with SPIR-V shaders we don't 56 * need to calculate the offset or the stride. 57 */ 58 59 struct gl_program *xfb_prog = prog->last_vert_prog; 60 61 if (xfb_prog == NULL) 62 return; 63 64 /* free existing varyings, if any */ 65 for (unsigned i = 0; i < prog->TransformFeedback.NumVarying; i++) 66 free(prog->TransformFeedback.VaryingNames[i]); 67 free(prog->TransformFeedback.VaryingNames); 68 69 nir_xfb_info *xfb_info = NULL; 70 nir_xfb_varyings_info *varyings_info = NULL; 71 72 /* Find last stage before fragment shader */ 73 for (int stage = MESA_SHADER_FRAGMENT - 1; stage >= 0; stage--) { 74 struct gl_linked_shader *sh = prog->_LinkedShaders[stage]; 75 76 if (sh && stage != MESA_SHADER_TESS_CTRL) { 77 nir_gather_xfb_info_with_varyings(sh->Program->nir, NULL, &varyings_info); 78 xfb_info = sh->Program->nir->xfb_info; 79 break; 80 } 81 } 82 83 struct gl_transform_feedback_info *linked_xfb = 84 rzalloc(xfb_prog, struct gl_transform_feedback_info); 85 xfb_prog->sh.LinkedTransformFeedback = linked_xfb; 86 87 if (!xfb_info) { 88 prog->TransformFeedback.NumVarying = 0; 89 linked_xfb->NumOutputs = 0; 90 linked_xfb->NumVarying = 0; 91 linked_xfb->ActiveBuffers = 0; 92 return; 93 } 94 95 for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++) 96 prog->TransformFeedback.BufferStride[buf] = xfb_info->buffers[buf].stride; 97 98 prog->TransformFeedback.NumVarying = varyings_info->varying_count; 99 prog->TransformFeedback.VaryingNames = 100 malloc(sizeof(GLchar *) * varyings_info->varying_count); 101 102 linked_xfb->Outputs = 103 rzalloc_array(xfb_prog, 104 struct gl_transform_feedback_output, 105 xfb_info->output_count); 106 linked_xfb->NumOutputs = xfb_info->output_count; 107 108 linked_xfb->Varyings = 109 rzalloc_array(xfb_prog, 110 struct gl_transform_feedback_varying_info, 111 varyings_info->varying_count); 112 linked_xfb->NumVarying = varyings_info->varying_count; 113 114 int buffer_index = 0; /* Corresponds to GL_TRANSFORM_FEEDBACK_BUFFER_INDEX */ 115 int xfb_buffer = 116 (varyings_info->varying_count > 0) ? 117 xfb_info->outputs[0].buffer : 0; 118 119 for (unsigned i = 0; i < varyings_info->varying_count; i++) { 120 nir_xfb_varying_info *xfb_varying = &varyings_info->varyings[i]; 121 122 /* From ARB_gl_spirv spec: 123 * 124 * "19. How should the program interface query operations behave for 125 * program objects created from SPIR-V shaders? 126 * 127 * DISCUSSION: we previously said we didn't need reflection to work 128 * for SPIR-V shaders (at least for the first version), however we 129 * are left with specifying how it should "not work". The primary 130 * issue is that SPIR-V binaries are not required to have names 131 * associated with variables. They can be associated in debug 132 * information, but there is no requirement for that to be present, 133 * and it should not be relied upon." 134 * 135 * Options:" 136 * 137 * <skip> 138 * 139 * "RESOLVED. Pick (c), but also allow debug names to be returned 140 * if an implementation wants to." 141 * 142 * So names are considered optional debug info, so the linker needs to 143 * work without them, and returning them is optional. For simplicity at 144 * this point we are ignoring names 145 */ 146 prog->TransformFeedback.VaryingNames[i] = NULL; 147 148 if (xfb_buffer != xfb_varying->buffer) { 149 buffer_index++; 150 xfb_buffer = xfb_varying->buffer; 151 } 152 153 struct gl_transform_feedback_varying_info *varying = 154 linked_xfb->Varyings + i; 155 156 /* ARB_gl_spirv: see above. */ 157 varying->name.string = NULL; 158 resource_name_updated(&varying->name); 159 varying->Type = glsl_get_gl_type(xfb_varying->type); 160 varying->BufferIndex = buffer_index; 161 varying->Size = glsl_type_is_array(xfb_varying->type) ? 162 glsl_get_length(xfb_varying->type) : 1; 163 varying->Offset = xfb_varying->offset; 164 } 165 166 for (unsigned i = 0; i < xfb_info->output_count; i++) { 167 nir_xfb_output_info *xfb_output = &xfb_info->outputs[i]; 168 169 struct gl_transform_feedback_output *output = 170 linked_xfb->Outputs + i; 171 172 output->OutputRegister = xfb_output->location; 173 output->OutputBuffer = xfb_output->buffer; 174 output->NumComponents = util_bitcount(xfb_output->component_mask); 175 output->StreamId = xfb_info->buffer_to_stream[xfb_output->buffer]; 176 output->DstOffset = xfb_output->offset / 4; 177 output->ComponentOffset = xfb_output->component_offset; 178 } 179 180 /* Make sure MaxTransformFeedbackBuffers is <= 32 so the bitmask for 181 * tracking the number of buffers doesn't overflow. 182 */ 183 unsigned buffers = 0; 184 assert(consts->MaxTransformFeedbackBuffers <= sizeof(buffers) * 8); 185 186 for (unsigned buf = 0; buf < MAX_FEEDBACK_BUFFERS; buf++) { 187 if (xfb_info->buffers[buf].stride > 0) { 188 linked_xfb->Buffers[buf].Stride = xfb_info->buffers[buf].stride / 4; 189 linked_xfb->Buffers[buf].NumVaryings = xfb_info->buffers[buf].varying_count; 190 buffers |= 1 << buf; 191 } 192 } 193 194 linked_xfb->ActiveBuffers = buffers; 195 196 ralloc_free(varyings_info); 197} 198 199struct nir_xfb_info * 200gl_to_nir_xfb_info(struct gl_transform_feedback_info *info, void *mem_ctx) 201{ 202 if (info == NULL || info->NumOutputs == 0) 203 return NULL; 204 205 nir_xfb_info *xfb = 206 rzalloc_size(mem_ctx, nir_xfb_info_size(info->NumOutputs)); 207 208 xfb->output_count = info->NumOutputs; 209 210 for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) { 211 xfb->buffers[i].stride = info->Buffers[i].Stride * 4; 212 xfb->buffers[i].varying_count = info->Buffers[i].NumVaryings; 213 xfb->buffer_to_stream[i] = info->Buffers[i].Stream; 214 } 215 216 for (unsigned i = 0; i < info->NumOutputs; i++) { 217 xfb->outputs[i].buffer = info->Outputs[i].OutputBuffer; 218 xfb->outputs[i].offset = info->Outputs[i].DstOffset * 4; 219 xfb->outputs[i].location = info->Outputs[i].OutputRegister; 220 xfb->outputs[i].component_offset = info->Outputs[i].ComponentOffset; 221 xfb->outputs[i].component_mask = 222 BITFIELD_RANGE(info->Outputs[i].ComponentOffset, 223 info->Outputs[i].NumComponents); 224 xfb->buffers_written |= BITFIELD_BIT(info->Outputs[i].OutputBuffer); 225 xfb->streams_written |= BITFIELD_BIT(info->Outputs[i].StreamId); 226 } 227 228 return xfb; 229} 230