Merge branch 'master' of git+ssh://znh@git.freedesktop.org/git/mesa/mesa
[mesa.git] / src / mesa / drivers / dri / nouveau / nouveau_shader_2.c
1 /*
2 * Copyright (C) 2006 Ben Skeggs.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 /*
29 * Authors:
30 * Ben Skeggs <darktama@iinet.net.au>
31 */
32
33 #include "glheader.h"
34 #include "macros.h"
35 #include "enums.h"
36
37 #include "program.h"
38
39 #include "nouveau_context.h"
40 #include "nouveau_shader.h"
41 #include "nouveau_msg.h"
42
43 struct pass2_rec {
44 /* Map nvsRegister temp ID onto hw temp ID */
45 unsigned int temps[NVS_MAX_TEMPS];
46 /* Track free hw registers */
47 unsigned int hw_temps[NVS_MAX_TEMPS];
48 };
49
50 static int
51 pass2_alloc_hw_temp(nvsPtr nvs)
52 {
53 struct pass2_rec *rec = nvs->pass_rec;
54 int i;
55
56 for (i=0; i<nvs->func->MaxTemp; i++) {
57 /* This is a *horrible* hack.. R0 is both temp0 and result.color
58 * in NV30/40 fragprogs, we can use R0 as a temp before result
59 * is written however..
60 */
61 if (nvs->mesa.vp.Base.Target == GL_FRAGMENT_PROGRAM_ARB && i==0)
62 continue;
63 if (rec->hw_temps[i] == 0) {
64 rec->hw_temps[i] = 1;
65 return i;
66 }
67 }
68
69 return -1;
70 }
71
72 static nvsRegister
73 pass2_mangle_reg(nvsPtr nvs, nvsInstruction *inst, nvsRegister reg)
74 {
75 struct pass2_rec *rec = nvs->pass_rec;
76
77 if (reg.file == NVS_FILE_TEMP) {
78 if (rec->temps[reg.index] == -1)
79 rec->temps[reg.index] = pass2_alloc_hw_temp(nvs);
80 reg.index = rec->temps[reg.index];
81 }
82
83 return reg;
84 }
85
86 static void
87 pass2_add_instruction(nvsPtr nvs, nvsInstruction *inst,
88 struct _op_xlat *op, int slot)
89 {
90 nvsSwzComp default_swz[4] = { NVS_SWZ_X, NVS_SWZ_Y,
91 NVS_SWZ_Z, NVS_SWZ_W };
92 nvsFunc *shader = nvs->func;
93 nvsRegister reg;
94 int i;
95
96 shader->SetOpcode(shader, op->NV, slot);
97 if (inst->saturate ) shader->SetSaturate(shader);
98 if (inst->cond_update ) shader->SetCCUpdate(shader);
99 if (inst->cond_test ) shader->SetCondition(shader, 1, inst->cond,
100 inst->cond_reg,
101 inst->cond_swizzle);
102 else shader->SetCondition(shader, 0, NVS_COND_TR,
103 0,
104 default_swz);
105 switch (inst->op) {
106 case NVS_OP_TEX:
107 case NVS_OP_TXB:
108 case NVS_OP_TXL:
109 case NVS_OP_TXP:
110 case NVS_OP_TXD:
111 shader->SetTexImageUnit(shader, inst->tex_unit);
112 break;
113 default:
114 break;
115 }
116
117 for (i = 0; i < 3; i++) {
118 if (op->srcpos[i] != -1) {
119 reg = pass2_mangle_reg(nvs, inst, inst->src[i]);
120
121 shader->SetSource(shader, &reg, op->srcpos[i]);
122
123 if (reg.file == NVS_FILE_CONST &&
124 shader->GetSourceConstVal) {
125 int idx_slot =
126 nvs->params[reg.index].hw_index_cnt++;
127 nvs->params[reg.index].hw_index = realloc(
128 nvs->params[reg.index].hw_index,
129 sizeof(int) * idx_slot+1);
130 nvs->params[reg.index].hw_index[idx_slot] =
131 nvs->program_current + 4;
132 }
133 }
134 }
135
136 reg = pass2_mangle_reg(nvs, inst, inst->dest);
137 shader->SetResult(shader, &reg, inst->mask, slot);
138
139 if (inst->dest_scale != NVS_SCALE_1X) {
140 shader->SetResultScale(shader, inst->dest_scale);
141 }
142 }
143
144 static int
145 pass2_assemble_instruction(nvsPtr nvs, nvsInstruction *inst, int last)
146 {
147 nvsFunc *shader = nvs->func;
148 struct _op_xlat *op;
149 unsigned int hw_inst[8];
150 int slot;
151 int instsz;
152 int i;
153
154 shader->inst = hw_inst;
155
156 /* Assemble this instruction */
157 if (!(op = shader->GetOPTXFromSOP(inst->op, &slot)))
158 return 0;
159 shader->InitInstruction(shader);
160 pass2_add_instruction(nvs, inst, op, slot);
161 if (last)
162 shader->SetLastInst(shader);
163
164 instsz = shader->GetOffsetNext(nvs->func);
165 if (nvs->program_size + instsz >= nvs->program_alloc_size) {
166 nvs->program_alloc_size *= 2;
167 nvs->program = realloc(nvs->program,
168 nvs->program_alloc_size *
169 sizeof(uint32_t));
170 }
171
172 for (i=0; i<instsz; i++)
173 nvs->program[nvs->program_current++] = hw_inst[i];
174 nvs->program_size = nvs->program_current;
175 return 1;
176 }
177
178 static GLboolean
179 pass2_translate(nvsPtr nvs, nvsFragmentHeader *f)
180 {
181 nvsFunc *shader = nvs->func;
182 GLboolean last;
183
184 while (f) {
185 last = (f == ((nvsSubroutine*)nvs->program_tree)->insn_tail);
186
187 switch (f->type) {
188 case NVS_INSTRUCTION:
189 if (!pass2_assemble_instruction(nvs,
190 (nvsInstruction *)f,
191 last))
192 return GL_FALSE;
193 break;
194 default:
195 WARN_ONCE("Unimplemented fragment type\n");
196 return GL_FALSE;
197 }
198
199 f = f->next;
200 }
201
202 return GL_TRUE;
203 }
204
205 /* Translate program into hardware format */
206 GLboolean
207 nouveau_shader_pass2(nvsPtr nvs)
208 {
209 struct pass2_rec *rec;
210 int i;
211
212 rec = calloc(1, sizeof(struct pass2_rec));
213 for (i=0; i<NVS_MAX_TEMPS; i++)
214 rec->temps[i] = -1;
215 nvs->pass_rec = rec;
216
217 /* Start off with allocating 4 uint32_t's for each inst, will be grown
218 * if necessary..
219 */
220 nvs->program_alloc_size = nvs->mesa.vp.Base.NumInstructions * 4;
221 nvs->program = calloc(nvs->program_alloc_size, sizeof(uint32_t));
222 nvs->program_size = 0;
223 nvs->program_current = 0;
224
225 if (!pass2_translate(nvs,
226 ((nvsSubroutine*)nvs->program_tree)->insn_head)) {
227 free(nvs->program);
228 nvs->program = NULL;
229 return GL_FALSE;
230 }
231
232 /* Shrink allocated memory to only what we need */
233 nvs->program = realloc(nvs->program,
234 nvs->program_size * sizeof(uint32_t));
235 nvs->program_alloc_size = nvs->program_size;
236
237 nvs->translated = 1;
238 nvs->on_hardware = 0;
239
240 if (NOUVEAU_DEBUG & DEBUG_SHADERS) {
241 fflush(stdout); fflush(stderr);
242 fprintf(stderr, "-----------MESA PROGRAM target=%s, id=0x%x\n",
243 _mesa_lookup_enum_by_nr(
244 nvs->mesa.vp.Base.Target),
245 nvs->mesa.vp.Base.Id);
246 fflush(stdout); fflush(stderr);
247 _mesa_print_program(&nvs->mesa.vp.Base);
248 fflush(stdout); fflush(stderr);
249 fprintf(stderr, "^^^^^^^^^^^^^^^^MESA PROGRAM\n");
250 fflush(stdout); fflush(stderr);
251 fprintf(stderr, "----------------NV PROGRAM\n");
252 fflush(stdout); fflush(stderr);
253 nvsDisasmHWShader(nvs);
254 fflush(stdout); fflush(stderr);
255 fprintf(stderr, "^^^^^^^^^^^^^^^^NV PROGRAM\n");
256 fflush(stdout); fflush(stderr);
257 }
258
259 return GL_TRUE;
260 }
261