1848b8605Smrg/*
2848b8605Smrg * Copyright © 2009 Intel Corporation
3848b8605Smrg *
4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5848b8605Smrg * copy of this software and associated documentation files (the "Software"),
6848b8605Smrg * to deal in the Software without restriction, including without limitation
7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
9848b8605Smrg * Software is furnished to do so, subject to the following conditions:
10848b8605Smrg *
11848b8605Smrg * The above copyright notice and this permission notice (including the next
12848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the
13848b8605Smrg * Software.
14848b8605Smrg *
15848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16848b8605Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19848b8605Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20848b8605Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21848b8605Smrg * DEALINGS IN THE SOFTWARE.
22848b8605Smrg */
23848b8605Smrg
24848b8605Smrg/**
25848b8605Smrg * \file prog_parameter_layout.c
26848b8605Smrg * \brief Helper functions to layout storage for program parameters
27848b8605Smrg *
28848b8605Smrg * \author Ian Romanick <ian.d.romanick@intel.com>
29848b8605Smrg */
30848b8605Smrg
31b8e80941Smrg#include "main/imports.h"
32848b8605Smrg#include "main/mtypes.h"
33848b8605Smrg#include "prog_parameter.h"
34848b8605Smrg#include "prog_parameter_layout.h"
35848b8605Smrg#include "prog_instruction.h"
36848b8605Smrg#include "program_parser.h"
37848b8605Smrg
38848b8605Smrgunsigned
39848b8605Smrg_mesa_combine_swizzles(unsigned base, unsigned applied)
40848b8605Smrg{
41848b8605Smrg   unsigned swiz = 0;
42848b8605Smrg   unsigned i;
43848b8605Smrg
44848b8605Smrg   for (i = 0; i < 4; i++) {
45848b8605Smrg      const unsigned s = GET_SWZ(applied, i);
46848b8605Smrg
47848b8605Smrg      swiz |= ((s <= SWIZZLE_W) ? GET_SWZ(base, s) : s) << (i * 3);
48848b8605Smrg   }
49848b8605Smrg
50848b8605Smrg   return swiz;
51848b8605Smrg}
52848b8605Smrg
53848b8605Smrg
54848b8605Smrg/**
55848b8605Smrg * Copy indirect access array from one parameter list to another
56848b8605Smrg *
57848b8605Smrg * \param src   Parameter array copied from
58848b8605Smrg * \param dst   Parameter array copied to
59848b8605Smrg * \param first Index of first element in \c src to copy
60848b8605Smrg * \param count Number of elements to copy
61848b8605Smrg *
62848b8605Smrg * \return
63848b8605Smrg * The location in \c dst of the first element copied from \c src on
64848b8605Smrg * success.  -1 on failure.
65848b8605Smrg *
66848b8605Smrg * \warning
67848b8605Smrg * This function assumes that there is already enough space available in
68848b8605Smrg * \c dst to hold all of the elements that will be copied over.
69848b8605Smrg */
70848b8605Smrgstatic int
71848b8605Smrgcopy_indirect_accessed_array(struct gl_program_parameter_list *src,
72848b8605Smrg			     struct gl_program_parameter_list *dst,
73848b8605Smrg			     unsigned first, unsigned count)
74848b8605Smrg{
75848b8605Smrg   const int base = dst->NumParameters;
76848b8605Smrg   unsigned i, j;
77848b8605Smrg
78848b8605Smrg   for (i = first; i < (first + count); i++) {
79848b8605Smrg      struct gl_program_parameter *curr = & src->Parameters[i];
80848b8605Smrg
81848b8605Smrg      if (curr->Type == PROGRAM_CONSTANT) {
82848b8605Smrg	 j = dst->NumParameters;
83848b8605Smrg      } else {
84848b8605Smrg	 for (j = 0; j < dst->NumParameters; j++) {
85848b8605Smrg	    if (memcmp(dst->Parameters[j].StateIndexes, curr->StateIndexes,
86848b8605Smrg		       sizeof(curr->StateIndexes)) == 0) {
87848b8605Smrg	       return -1;
88848b8605Smrg	    }
89848b8605Smrg	 }
90848b8605Smrg      }
91848b8605Smrg
92848b8605Smrg      assert(j == dst->NumParameters);
93848b8605Smrg
94848b8605Smrg      /* copy src parameter [i] to dest parameter [j] */
95b8e80941Smrg      memcpy(&dst->Parameters[j], curr,
96848b8605Smrg	     sizeof(dst->Parameters[j]));
97b8e80941Smrg
98b8e80941Smrg      dst->ParameterValueOffset[j] = dst->NumParameterValues;
99b8e80941Smrg
100b8e80941Smrg      gl_constant_value *pv_dst =
101b8e80941Smrg         dst->ParameterValues + dst->ParameterValueOffset[j];
102b8e80941Smrg      gl_constant_value *pv_src =
103b8e80941Smrg         src->ParameterValues + src->ParameterValueOffset[i];
104b8e80941Smrg
105b8e80941Smrg      memcpy(pv_dst, pv_src, MIN2(src->Parameters[i].Size, 4) *
106b8e80941Smrg             sizeof(GLfloat));
107b8e80941Smrg      dst->NumParameterValues += MIN2(dst->Parameters[j].Size, 4);
108b8e80941Smrg
109848b8605Smrg
110848b8605Smrg      /* Pointer to the string name was copied.  Null-out src param name
111848b8605Smrg       * to prevent double free later.
112848b8605Smrg       */
113848b8605Smrg      curr->Name = NULL;
114848b8605Smrg
115848b8605Smrg      dst->NumParameters++;
116848b8605Smrg   }
117848b8605Smrg
118848b8605Smrg   return base;
119848b8605Smrg}
120848b8605Smrg
121848b8605Smrg
122848b8605Smrg/**
123848b8605Smrg * XXX description???
124848b8605Smrg * \return GL_TRUE for success, GL_FALSE for failure
125848b8605Smrg */
126848b8605SmrgGLboolean
127848b8605Smrg_mesa_layout_parameters(struct asm_parser_state *state)
128848b8605Smrg{
129848b8605Smrg   struct gl_program_parameter_list *layout;
130848b8605Smrg   struct asm_instruction *inst;
131848b8605Smrg   unsigned i;
132848b8605Smrg
133848b8605Smrg   layout =
134848b8605Smrg      _mesa_new_parameter_list_sized(state->prog->Parameters->NumParameters);
135848b8605Smrg
136848b8605Smrg   /* PASS 1:  Move any parameters that are accessed indirectly from the
137848b8605Smrg    * original parameter list to the new parameter list.
138848b8605Smrg    */
139848b8605Smrg   for (inst = state->inst_head; inst != NULL; inst = inst->next) {
140848b8605Smrg      for (i = 0; i < 3; i++) {
141848b8605Smrg	 if (inst->SrcReg[i].Base.RelAddr) {
142848b8605Smrg	    /* Only attempt to add the to the new parameter list once.
143848b8605Smrg	     */
144848b8605Smrg	    if (!inst->SrcReg[i].Symbol->pass1_done) {
145848b8605Smrg	       const int new_begin =
146848b8605Smrg		  copy_indirect_accessed_array(state->prog->Parameters, layout,
147848b8605Smrg		      inst->SrcReg[i].Symbol->param_binding_begin,
148848b8605Smrg		      inst->SrcReg[i].Symbol->param_binding_length);
149848b8605Smrg
150848b8605Smrg	       if (new_begin < 0) {
151848b8605Smrg		  _mesa_free_parameter_list(layout);
152848b8605Smrg		  return GL_FALSE;
153848b8605Smrg	       }
154848b8605Smrg
155848b8605Smrg	       inst->SrcReg[i].Symbol->param_binding_begin = new_begin;
156848b8605Smrg	       inst->SrcReg[i].Symbol->pass1_done = 1;
157848b8605Smrg	    }
158848b8605Smrg
159848b8605Smrg	    /* Previously the Index was just the offset from the parameter
160848b8605Smrg	     * array.  Now that the base of the parameter array is known, the
161848b8605Smrg	     * index can be updated to its actual value.
162848b8605Smrg	     */
163848b8605Smrg	    inst->Base.SrcReg[i] = inst->SrcReg[i].Base;
164848b8605Smrg	    inst->Base.SrcReg[i].Index +=
165848b8605Smrg	       inst->SrcReg[i].Symbol->param_binding_begin;
166848b8605Smrg	 }
167848b8605Smrg      }
168848b8605Smrg   }
169848b8605Smrg
170848b8605Smrg   /* PASS 2:  Move any parameters that are not accessed indirectly from the
171848b8605Smrg    * original parameter list to the new parameter list.
172848b8605Smrg    */
173848b8605Smrg   for (inst = state->inst_head; inst != NULL; inst = inst->next) {
174848b8605Smrg      for (i = 0; i < 3; i++) {
175848b8605Smrg	 const struct gl_program_parameter *p;
176848b8605Smrg	 const int idx = inst->SrcReg[i].Base.Index;
177848b8605Smrg	 unsigned swizzle = SWIZZLE_NOOP;
178848b8605Smrg
179848b8605Smrg	 /* All relative addressed operands were processed on the first
180848b8605Smrg	  * pass.  Just skip them here.
181848b8605Smrg	  */
182848b8605Smrg	 if (inst->SrcReg[i].Base.RelAddr) {
183848b8605Smrg	    continue;
184848b8605Smrg	 }
185848b8605Smrg
186848b8605Smrg	 if ((inst->SrcReg[i].Base.File <= PROGRAM_OUTPUT)
187848b8605Smrg	     || (inst->SrcReg[i].Base.File >= PROGRAM_WRITE_ONLY)) {
188848b8605Smrg	    continue;
189848b8605Smrg	 }
190848b8605Smrg
191848b8605Smrg	 inst->Base.SrcReg[i] = inst->SrcReg[i].Base;
192848b8605Smrg	 p = & state->prog->Parameters->Parameters[idx];
193848b8605Smrg
194848b8605Smrg	 switch (p->Type) {
195848b8605Smrg	 case PROGRAM_CONSTANT: {
196b8e80941Smrg            unsigned pvo = state->prog->Parameters->ParameterValueOffset[idx];
197b8e80941Smrg            const gl_constant_value *const v =
198b8e80941Smrg               state->prog->Parameters->ParameterValues + pvo;
199848b8605Smrg
200848b8605Smrg	    inst->Base.SrcReg[i].Index =
201848b8605Smrg	       _mesa_add_unnamed_constant(layout, v, p->Size, & swizzle);
202848b8605Smrg
203848b8605Smrg	    inst->Base.SrcReg[i].Swizzle =
204848b8605Smrg	       _mesa_combine_swizzles(swizzle, inst->Base.SrcReg[i].Swizzle);
205848b8605Smrg	    break;
206848b8605Smrg	 }
207848b8605Smrg
208848b8605Smrg	 case PROGRAM_STATE_VAR:
209848b8605Smrg	    inst->Base.SrcReg[i].Index =
210848b8605Smrg	       _mesa_add_state_reference(layout, p->StateIndexes);
211848b8605Smrg	    break;
212848b8605Smrg
213848b8605Smrg	 default:
214848b8605Smrg	    break;
215848b8605Smrg	 }
216848b8605Smrg
217848b8605Smrg	 inst->SrcReg[i].Base.File = p->Type;
218848b8605Smrg	 inst->Base.SrcReg[i].File = p->Type;
219848b8605Smrg      }
220848b8605Smrg   }
221848b8605Smrg
222848b8605Smrg   layout->StateFlags = state->prog->Parameters->StateFlags;
223848b8605Smrg   _mesa_free_parameter_list(state->prog->Parameters);
224848b8605Smrg   state->prog->Parameters = layout;
225848b8605Smrg
226848b8605Smrg   return GL_TRUE;
227848b8605Smrg}
228