Handy TIntermTraverser class wrapper
[mesa.git] / src / mesa / shader / atifragshader.c
1 /**
2 * \file atifragshader.c
3 * \author David Airlie
4 * Copyright (C) 2004 David Airlie All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * DAVID AIRLIE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "glheader.h"
25 #include "context.h"
26 #include "hash.h"
27 #include "imports.h"
28 #include "macros.h"
29 #include "enums.h"
30 #include "mtypes.h"
31 #include "atifragshader.h"
32
33 #define MESA_DEBUG_ATI_FS 0
34
35 extern struct program _mesa_DummyProgram;
36
37 static void
38 new_inst(struct ati_fragment_shader *prog)
39 {
40 prog->Base.NumInstructions++;
41 }
42
43 #if MESA_DEBUG_ATI_FS
44 static char *
45 create_dst_mod_str(GLuint mod)
46 {
47 static char ret_str[1024];
48
49 _mesa_memset(ret_str, 0, 1024);
50 if (mod & GL_2X_BIT_ATI)
51 _mesa_strncat(ret_str, "|2X", 1024);
52
53 if (mod & GL_4X_BIT_ATI)
54 _mesa_strncat(ret_str, "|4X", 1024);
55
56 if (mod & GL_8X_BIT_ATI)
57 _mesa_strncat(ret_str, "|8X", 1024);
58 if (mod & GL_HALF_BIT_ATI)
59 _mesa_strncat(ret_str, "|HA", 1024);
60 if (mod & GL_QUARTER_BIT_ATI)
61 _mesa_strncat(ret_str, "|QU", 1024);
62 if (mod & GL_EIGHTH_BIT_ATI)
63 _mesa_strncat(ret_str, "|EI", 1024);
64
65 if (mod & GL_SATURATE_BIT_ATI)
66 _mesa_strncat(ret_str, "|SAT", 1024);
67
68 if (_mesa_strlen(ret_str) == 0)
69 _mesa_strncat(ret_str, "NONE", 1024);
70 return ret_str;
71 }
72
73 static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI",
74 "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" };
75
76 static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
77 GLuint dstMask, GLuint dstMod, GLuint arg1,
78 GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
79 GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
80 GLuint arg3Rep, GLuint arg3Mod)
81 {
82 char *op_name;
83
84 op_name = atifs_ops[(arg_count-1)+(optype?3:0)];
85
86 fprintf(stderr, "%s(%s, %s", op_name, _mesa_lookup_enum_by_nr(op),
87 _mesa_lookup_enum_by_nr(dst));
88 if (!optype)
89 fprintf(stderr, ", %d", dstMask);
90
91 fprintf(stderr, ", %s", create_dst_mod_str(dstMod));
92
93 fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1),
94 _mesa_lookup_enum_by_nr(arg1Rep), arg1Mod);
95 if (arg_count>1)
96 fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2),
97 _mesa_lookup_enum_by_nr(arg2Rep), arg2Mod);
98 if (arg_count>2)
99 fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3),
100 _mesa_lookup_enum_by_nr(arg3Rep), arg3Mod);
101
102 fprintf(stderr,")\n");
103
104 }
105 #endif
106
107 GLuint GLAPIENTRY
108 _mesa_GenFragmentShadersATI(GLuint range)
109 {
110 GLuint first;
111 GLuint i;
112 GET_CURRENT_CONTEXT(ctx);
113
114 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, range);
115 for (i = 0; i < range; i++) {
116 _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
117 }
118
119 return first;
120 }
121
122 void GLAPIENTRY
123 _mesa_BindFragmentShaderATI(GLuint id)
124 {
125 struct program *prog;
126 GET_CURRENT_CONTEXT(ctx);
127 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
128
129 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
130
131 if (curProg->Base.Id == id) {
132 return;
133 }
134
135 if (curProg->Base.Id != 0) {
136 curProg->Base.RefCount--;
137 if (curProg->Base.RefCount <= 0) {
138 _mesa_HashRemove(ctx->Shared->Programs, id);
139 }
140 }
141
142 /* Go bind */
143 if (id == 0) {
144 prog = ctx->Shared->DefaultFragmentShader;
145 }
146 else {
147 prog = (struct program *) _mesa_HashLookup(ctx->Shared->Programs, id);
148 if (!prog || prog == &_mesa_DummyProgram) {
149 /* allocate a new program now */
150 prog = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_SHADER_ATI, id);
151 if (!prog) {
152 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFragmentShaderATI");
153 return;
154 }
155 _mesa_HashInsert(ctx->Shared->Programs, id, prog);
156 }
157
158 }
159
160 /* do actual bind */
161 ctx->ATIFragmentShader.Current = (struct ati_fragment_shader *) prog;
162
163 ASSERT(ctx->ATIFragmentShader.Current);
164 if (prog)
165 prog->RefCount++;
166
167 /*if (ctx->Driver.BindProgram)
168 ctx->Driver.BindProgram(ctx, target, prog); */
169 }
170
171 void GLAPIENTRY
172 _mesa_DeleteFragmentShaderATI(GLuint id)
173 {
174 GET_CURRENT_CONTEXT(ctx);
175
176 if (id != 0) {
177 struct program *prog = (struct program *)
178 _mesa_HashLookup(ctx->Shared->Programs, id);
179 if (prog == &_mesa_DummyProgram) {
180 _mesa_HashRemove(ctx->Shared->Programs, id);
181 }
182 else if (prog) {
183 if (ctx->ATIFragmentShader.Current &&
184 ctx->ATIFragmentShader.Current->Base.Id == id) {
185 _mesa_BindFragmentShaderATI(0);
186 }
187 }
188 #if 0
189 if (!prog->DeletePending) {
190 prog->DeletePending = GL_TRUE;
191 prog->RefCount--;
192 }
193 if (prog->RefCount <= 0) {
194 _mesa_HashRemove(ctx->Shared->Programs, id);
195 ctx->Driver.DeleteProgram(ctx, prog);
196 }
197 #else
198 /* The ID is immediately available for re-use now */
199 _mesa_HashRemove(ctx->Shared->Programs, id);
200 prog->RefCount--;
201 if (prog->RefCount <= 0) {
202 ctx->Driver.DeleteProgram(ctx, prog);
203 }
204 #endif
205 }
206 }
207
208 void GLAPIENTRY
209 _mesa_BeginFragmentShaderATI(void)
210 {
211 GET_CURRENT_CONTEXT(ctx);
212
213 /* malloc the instructions here - not sure if the best place but its
214 a start */
215 ctx->ATIFragmentShader.Current->Instructions =
216 (struct atifs_instruction *)
217 _mesa_calloc(sizeof(struct atifs_instruction) * MAX_NUM_PASSES_ATI *
218 MAX_NUM_INSTRUCTIONS_PER_PASS_ATI * 2);
219
220 ctx->ATIFragmentShader.Current->cur_pass = 0;
221 ctx->ATIFragmentShader.Compiling = 1;
222 }
223
224 void GLAPIENTRY
225 _mesa_EndFragmentShaderATI(void)
226 {
227 GET_CURRENT_CONTEXT(ctx);
228 #if MESA_DEBUG_ATI_FS
229 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
230 GLint i;
231 #endif
232
233 ctx->ATIFragmentShader.Compiling = 0;
234
235 #if MESA_DEBUG_ATI_FS
236 for (i = 0; i < curProg->Base.NumInstructions; i++) {
237 GLuint op0 = curProg->Instructions[i].Opcode[0];
238 GLuint op1 = curProg->Instructions[i].Opcode[1];
239 const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0";
240 const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0";
241 GLuint count0 = curProg->Instructions[i].ArgCount[0];
242 GLuint count1 = curProg->Instructions[i].ArgCount[1];
243
244 fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0,
245 op1, op1_enum, count1);
246 }
247 #endif
248 }
249
250 void GLAPIENTRY
251 _mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
252 {
253 GET_CURRENT_CONTEXT(ctx);
254 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
255 GLint ci;
256 struct atifs_instruction *curI;
257
258 new_inst(curProg);
259 ci = curProg->Base.NumInstructions - 1;
260 /* some validation
261 if ((swizzle != GL_SWIZZLE_STR_ATI) ||
262 (swizzle != GL_SWIZZLE_STQ_ATI) ||
263 (swizzle != GL_SWIZZLE_STR_DR_ATI) ||
264 (swizzle != GL_SWIZZLE_STQ_DQ_ATI))
265 */
266
267 /* add the instructions */
268 curI = &curProg->Instructions[ci];
269
270 curI->Opcode[0] = ATI_FRAGMENT_SHADER_PASS_OP;
271 curI->DstReg[0].Index = dst;
272 curI->SrcReg[0][0].Index = coord;
273 curI->DstReg[0].Swizzle = swizzle;
274
275 #if MESA_DEBUG_ATI_FS
276 _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
277 _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord),
278 _mesa_lookup_enum_by_nr(swizzle));
279 #endif
280 }
281
282 void GLAPIENTRY
283 _mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
284 {
285 GET_CURRENT_CONTEXT(ctx);
286 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
287 GLint ci;
288 struct atifs_instruction *curI;
289
290 new_inst(curProg);
291
292 ci = curProg->Base.NumInstructions - 1;
293 /* add the instructions */
294 curI = &curProg->Instructions[ci];
295
296 curI->Opcode[0] = ATI_FRAGMENT_SHADER_SAMPLE_OP;
297 curI->DstReg[0].Index = dst;
298 curI->DstReg[0].Swizzle = swizzle;
299
300 curI->SrcReg[0][0].Index = interp;
301
302 #if MESA_DEBUG_ATI_FS
303 _mesa_debug(ctx, "%s(%s, %s, %s)\n", __FUNCTION__,
304 _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp),
305 _mesa_lookup_enum_by_nr(swizzle));
306 #endif
307 }
308
309 static void
310 _mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
311 GLuint dstMask, GLuint dstMod, GLuint arg1,
312 GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
313 GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
314 GLuint arg3Rep, GLuint arg3Mod)
315 {
316 GET_CURRENT_CONTEXT(ctx);
317 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
318 GLint ci;
319 struct atifs_instruction *curI;
320
321 /* decide whether this is a new instruction or not ... all color instructions are new */
322 if (optype == 0)
323 new_inst(curProg);
324
325 ci = curProg->Base.NumInstructions - 1;
326
327 /* add the instructions */
328 curI = &curProg->Instructions[ci];
329
330 curI->Opcode[optype] = op;
331
332 curI->SrcReg[optype][0].Index = arg1;
333 curI->SrcReg[optype][0].argRep = arg1Rep;
334 curI->SrcReg[optype][0].argMod = arg1Mod;
335 curI->ArgCount[optype] = arg_count;
336
337 if (arg2) {
338 curI->SrcReg[optype][1].Index = arg2;
339 curI->SrcReg[optype][1].argRep = arg2Rep;
340 curI->SrcReg[optype][1].argMod = arg2Mod;
341 }
342
343 if (arg3) {
344 curI->SrcReg[optype][2].Index = arg3;
345 curI->SrcReg[optype][2].argRep = arg3Rep;
346 curI->SrcReg[optype][2].argMod = arg3Mod;
347 }
348
349 curI->DstReg[optype].Index = dst;
350 curI->DstReg[optype].dstMod = dstMod;
351 curI->DstReg[optype].dstMask = dstMask;
352
353 #if MESA_DEBUG_ATI_FS
354 debug_op(optype, arg_count, op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod);
355 #endif
356
357 }
358
359 void GLAPIENTRY
360 _mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask,
361 GLuint dstMod, GLuint arg1, GLuint arg1Rep,
362 GLuint arg1Mod)
363 {
364 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 1, op, dst, dstMask,
365 dstMod, arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
366 }
367
368 void GLAPIENTRY
369 _mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask,
370 GLuint dstMod, GLuint arg1, GLuint arg1Rep,
371 GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
372 GLuint arg2Mod)
373 {
374 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 2, op, dst, dstMask,
375 dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
376 arg2Mod, 0, 0, 0);
377 }
378
379 void GLAPIENTRY
380 _mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask,
381 GLuint dstMod, GLuint arg1, GLuint arg1Rep,
382 GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
383 GLuint arg2Mod, GLuint arg3, GLuint arg3Rep,
384 GLuint arg3Mod)
385 {
386 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 3, op, dst, dstMask,
387 dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
388 arg2Mod, arg3, arg3Rep, arg3Mod);
389 }
390
391 void GLAPIENTRY
392 _mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
393 GLuint arg1Rep, GLuint arg1Mod)
394 {
395 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 1, op, dst, 0, dstMod,
396 arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
397 }
398
399 void GLAPIENTRY
400 _mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
401 GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
402 GLuint arg2Rep, GLuint arg2Mod)
403 {
404 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 2, op, dst, 0, dstMod,
405 arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, 0, 0,
406 0);
407 }
408
409 void GLAPIENTRY
410 _mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
411 GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
412 GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
413 GLuint arg3Rep, GLuint arg3Mod)
414 {
415 _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 3, op, dst, 0, dstMod,
416 arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3,
417 arg3Rep, arg3Mod);
418 }
419
420 void GLAPIENTRY
421 _mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value)
422 {
423 GET_CURRENT_CONTEXT(ctx);
424 GLuint dstindex = dst - GL_CON_0_ATI;
425 struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
426
427 COPY_4V(curProg->Constants[dstindex], value);
428 }