1/* 2 * Copyright © 2009 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 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24/** 25 * \file prog_parameter_layout.c 26 * \brief Helper functions to layout storage for program parameters 27 * 28 * \author Ian Romanick <ian.d.romanick@intel.com> 29 */ 30 31 32#include "main/mtypes.h" 33#include "prog_parameter.h" 34#include "prog_parameter_layout.h" 35#include "prog_instruction.h" 36#include "program_parser.h" 37 38unsigned 39_mesa_combine_swizzles(unsigned base, unsigned applied) 40{ 41 unsigned swiz = 0; 42 unsigned i; 43 44 for (i = 0; i < 4; i++) { 45 const unsigned s = GET_SWZ(applied, i); 46 47 swiz |= ((s <= SWIZZLE_W) ? GET_SWZ(base, s) : s) << (i * 3); 48 } 49 50 return swiz; 51} 52 53 54/** 55 * Copy indirect access array from one parameter list to another 56 * 57 * \param src Parameter array copied from 58 * \param dst Parameter array copied to 59 * \param first Index of first element in \c src to copy 60 * \param count Number of elements to copy 61 * 62 * \return 63 * The location in \c dst of the first element copied from \c src on 64 * success. -1 on failure. 65 * 66 * \warning 67 * This function assumes that there is already enough space available in 68 * \c dst to hold all of the elements that will be copied over. 69 */ 70static int 71copy_indirect_accessed_array(struct gl_program_parameter_list *src, 72 struct gl_program_parameter_list *dst, 73 unsigned first, unsigned count) 74{ 75 const int base = dst->NumParameters; 76 unsigned i, j; 77 78 for (i = first; i < (first + count); i++) { 79 struct gl_program_parameter *curr = & src->Parameters[i]; 80 81 if (curr->Type == PROGRAM_CONSTANT) { 82 j = dst->NumParameters; 83 } else { 84 for (j = 0; j < dst->NumParameters; j++) { 85 if (memcmp(dst->Parameters[j].StateIndexes, curr->StateIndexes, 86 sizeof(curr->StateIndexes)) == 0) { 87 return -1; 88 } 89 } 90 } 91 92 assert(j == dst->NumParameters); 93 94 /* copy src parameter [i] to dest parameter [j] */ 95 memcpy(&dst->Parameters[j], curr, 96 sizeof(dst->Parameters[j])); 97 98 dst->Parameters[j].ValueOffset = dst->NumParameterValues; 99 100 gl_constant_value *pv_dst = 101 dst->ParameterValues + dst->Parameters[j].ValueOffset; 102 gl_constant_value *pv_src = 103 src->ParameterValues + src->Parameters[i].ValueOffset; 104 105 memcpy(pv_dst, pv_src, MIN2(src->Parameters[i].Size, 4) * 106 sizeof(GLfloat)); 107 dst->NumParameterValues += MIN2(dst->Parameters[j].Size, 4); 108 109 110 /* Pointer to the string name was copied. Null-out src param name 111 * to prevent double free later. 112 */ 113 curr->Name = NULL; 114 115 dst->NumParameters++; 116 } 117 118 return base; 119} 120 121 122static int compare_state_var(const void *a1, const void *a2) 123{ 124 const struct gl_program_parameter *p1 = 125 (const struct gl_program_parameter *)a1; 126 const struct gl_program_parameter *p2 = 127 (const struct gl_program_parameter *)a2; 128 129 for (unsigned i = 0; i < STATE_LENGTH; i++) { 130 if (p1->StateIndexes[i] != p2->StateIndexes[i]) 131 return p1->StateIndexes[i] - p2->StateIndexes[i]; 132 } 133 return 0; 134} 135 136 137/** 138 * Create the final program parameter list in this order: 139 * - constants and state variables with variable indexing are first 140 * - other constants are next 141 * - other state variables are last and sorted 142 * 143 * \return GL_TRUE for success, GL_FALSE for failure 144 */ 145GLboolean 146_mesa_layout_parameters(struct asm_parser_state *state) 147{ 148 struct gl_program_parameter_list *layout; 149 struct asm_instruction *inst; 150 151 layout = 152 _mesa_new_parameter_list_sized(state->prog->Parameters->NumParameters); 153 154 /* PASS 1: Move any parameters that are accessed indirectly from the 155 * original parameter list to the new parameter list. 156 */ 157 for (inst = state->inst_head; inst != NULL; inst = inst->next) { 158 for (unsigned i = 0; i < 3; i++) { 159 if (inst->SrcReg[i].Base.RelAddr) { 160 /* Only attempt to add the to the new parameter list once. 161 */ 162 if (!inst->SrcReg[i].Symbol->pass1_done) { 163 const int new_begin = 164 copy_indirect_accessed_array(state->prog->Parameters, layout, 165 inst->SrcReg[i].Symbol->param_binding_begin, 166 inst->SrcReg[i].Symbol->param_binding_length); 167 168 if (new_begin < 0) { 169 _mesa_free_parameter_list(layout); 170 return GL_FALSE; 171 } 172 173 inst->SrcReg[i].Symbol->param_binding_begin = new_begin; 174 inst->SrcReg[i].Symbol->pass1_done = 1; 175 } 176 177 /* Previously the Index was just the offset from the parameter 178 * array. Now that the base of the parameter array is known, the 179 * index can be updated to its actual value. 180 */ 181 inst->Base.SrcReg[i] = inst->SrcReg[i].Base; 182 inst->Base.SrcReg[i].Index += 183 inst->SrcReg[i].Symbol->param_binding_begin; 184 } 185 } 186 } 187 188 /* PASS 2: Move any constants that are not accessed indirectly from the 189 * original parameter list to the new parameter list. 190 */ 191 for (inst = state->inst_head; inst != NULL; inst = inst->next) { 192 for (unsigned i = 0; i < 3; i++) { 193 const int idx = inst->SrcReg[i].Base.Index; 194 const struct gl_program_parameter *const p = 195 &state->prog->Parameters->Parameters[idx]; 196 unsigned swizzle = SWIZZLE_NOOP; 197 198 if (inst->SrcReg[i].Base.RelAddr || 199 inst->SrcReg[i].Base.File <= PROGRAM_OUTPUT || 200 inst->SrcReg[i].Base.File >= PROGRAM_WRITE_ONLY || 201 p->Type != PROGRAM_CONSTANT) 202 continue; 203 204 inst->Base.SrcReg[i] = inst->SrcReg[i].Base; 205 206 unsigned pvo = state->prog->Parameters->Parameters[idx].ValueOffset; 207 const gl_constant_value *const v = 208 state->prog->Parameters->ParameterValues + pvo; 209 210 inst->Base.SrcReg[i].Index = 211 _mesa_add_unnamed_constant(layout, v, p->Size, &swizzle); 212 213 inst->Base.SrcReg[i].Swizzle = 214 _mesa_combine_swizzles(swizzle, inst->Base.SrcReg[i].Swizzle); 215 216 inst->SrcReg[i].Base.File = p->Type; 217 inst->Base.SrcReg[i].File = p->Type; 218 } 219 } 220 221 /* PASS 3: Add sorted state variables. NOTE: This pass does **not** modify 222 * the instruction with the updated index. The sorting step might 223 * invalidate the index that was calculated by _mesa_add_state_reference. 224 * Instead, it relies on PASS 4 to do this. 225 */ 226 unsigned first_state_var = layout->NumParameters; 227 228 for (inst = state->inst_head; inst != NULL; inst = inst->next) { 229 for (unsigned i = 0; i < 3; i++) { 230 const struct gl_program_parameter *p; 231 const int idx = inst->SrcReg[i].Base.Index; 232 233 p = &state->prog->Parameters->Parameters[idx]; 234 235 if (inst->SrcReg[i].Base.RelAddr || 236 inst->SrcReg[i].Base.File <= PROGRAM_OUTPUT || 237 inst->SrcReg[i].Base.File >= PROGRAM_WRITE_ONLY || 238 p->Type != PROGRAM_STATE_VAR) 239 continue; 240 241 _mesa_add_state_reference(layout, p->StateIndexes); 242 } 243 } 244 245 /* Sort if we have added at least 2 state vars. */ 246 if (first_state_var + 2 <= layout->NumParameters) { 247 /* All state vars should be vec4s. */ 248 for (unsigned i = first_state_var; i < layout->NumParameters; i++) { 249 assert(layout->Parameters[i].Size == 4); 250 assert(layout->Parameters[i].ValueOffset == i * 4); 251 } 252 253 qsort(layout->Parameters + first_state_var, 254 layout->NumParameters - first_state_var, 255 sizeof(layout->Parameters[0]), compare_state_var); 256 257 /* Fix offsets. */ 258 for (unsigned i = first_state_var; i < layout->NumParameters; i++) { 259 layout->Parameters[i].ValueOffset = i * 4; 260 } 261 } 262 263 /* PASS 4: Fix up the index and file information for instructions whose 264 * parameters were added to the parameter list in PASS 3. 265 */ 266 for (inst = state->inst_head; inst != NULL; inst = inst->next) { 267 for (unsigned i = 0; i < 3; i++) { 268 const int idx = inst->SrcReg[i].Base.Index; 269 const struct gl_program_parameter *const p = 270 &state->prog->Parameters->Parameters[idx]; 271 272 if (inst->SrcReg[i].Base.RelAddr || 273 inst->SrcReg[i].Base.File <= PROGRAM_OUTPUT || 274 inst->SrcReg[i].Base.File >= PROGRAM_WRITE_ONLY || 275 p->Type != PROGRAM_STATE_VAR) 276 continue; 277 278 inst->Base.SrcReg[i] = inst->SrcReg[i].Base; 279 280 inst->Base.SrcReg[i].Index = 281 _mesa_add_state_reference(layout, p->StateIndexes); 282 283 inst->SrcReg[i].Base.File = p->Type; 284 inst->Base.SrcReg[i].File = p->Type; 285 } 286 } 287 288 assert(layout->NumParameters <= state->prog->Parameters->NumParameters); 289 _mesa_recompute_parameter_bounds(layout); 290 291 layout->StateFlags = state->prog->Parameters->StateFlags; 292 _mesa_free_parameter_list(state->prog->Parameters); 293 state->prog->Parameters = layout; 294 295 return GL_TRUE; 296} 297