Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5564 serge 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 "main/glheader.h"
25
#include "main/context.h"
26
#include "main/hash.h"
27
#include "main/imports.h"
28
#include "main/macros.h"
29
#include "main/enums.h"
30
#include "main/mtypes.h"
31
#include "main/dispatch.h"
32
#include "main/atifragshader.h"
33
 
34
#define MESA_DEBUG_ATI_FS 0
35
 
36
static struct ati_fragment_shader DummyShader;
37
 
38
 
39
/**
40
 * Allocate and initialize a new ATI fragment shader object.
41
 */
42
struct ati_fragment_shader *
43
_mesa_new_ati_fragment_shader(struct gl_context *ctx, GLuint id)
44
{
45
   struct ati_fragment_shader *s = CALLOC_STRUCT(ati_fragment_shader);
46
   (void) ctx;
47
   if (s) {
48
      s->Id = id;
49
      s->RefCount = 1;
50
   }
51
   return s;
52
}
53
 
54
 
55
/**
56
 * Delete the given ati fragment shader
57
 */
58
void
59
_mesa_delete_ati_fragment_shader(struct gl_context *ctx, struct ati_fragment_shader *s)
60
{
61
   GLuint i;
62
   for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
63
      free(s->Instructions[i]);
64
      free(s->SetupInst[i]);
65
   }
66
   free(s);
67
}
68
 
69
 
70
 
71
static void
72
new_arith_inst(struct ati_fragment_shader *prog)
73
{
74
/* set "default" instruction as not all may get defined.
75
   there is no specified way to express a nop with ati fragment shaders we use
76
   GL_NONE as the op enum and just set some params to 0 - so nothing to do here */
77
   prog->numArithInstr[prog->cur_pass >> 1]++;
78
}
79
 
80
static void
81
new_tex_inst(struct ati_fragment_shader *prog)
82
{
83
}
84
 
85
static void match_pair_inst(struct ati_fragment_shader *curProg, GLuint optype)
86
{
87
   if (optype == curProg->last_optype) {
88
      curProg->last_optype = 1;
89
   }
90
}
91
 
92
#if MESA_DEBUG_ATI_FS
93
static char *
94
create_dst_mod_str(GLuint mod)
95
{
96
   static char ret_str[1024];
97
 
98
   memset(ret_str, 0, 1024);
99
   if (mod & GL_2X_BIT_ATI)
100
      strncat(ret_str, "|2X", 1024);
101
 
102
   if (mod & GL_4X_BIT_ATI)
103
      strncat(ret_str, "|4X", 1024);
104
 
105
   if (mod & GL_8X_BIT_ATI)
106
      strncat(ret_str, "|8X", 1024);
107
   if (mod & GL_HALF_BIT_ATI)
108
      strncat(ret_str, "|HA", 1024);
109
   if (mod & GL_QUARTER_BIT_ATI)
110
      strncat(ret_str, "|QU", 1024);
111
   if (mod & GL_EIGHTH_BIT_ATI)
112
      strncat(ret_str, "|EI", 1024);
113
 
114
   if (mod & GL_SATURATE_BIT_ATI)
115
      strncat(ret_str, "|SAT", 1024);
116
 
117
   if (strlen(ret_str) == 0)
118
      strncat(ret_str, "NONE", 1024);
119
   return ret_str;
120
}
121
 
122
static char *atifs_ops[] = {"ColorFragmentOp1ATI", "ColorFragmentOp2ATI", "ColorFragmentOp3ATI",
123
			    "AlphaFragmentOp1ATI", "AlphaFragmentOp2ATI", "AlphaFragmentOp3ATI" };
124
 
125
static void debug_op(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
126
		     GLuint dstMask, GLuint dstMod, GLuint arg1,
127
		     GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
128
		     GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
129
		     GLuint arg3Rep, GLuint arg3Mod)
130
{
131
  char *op_name;
132
 
133
  op_name = atifs_ops[(arg_count-1)+(optype?3:0)];
134
 
135
  fprintf(stderr, "%s(%s, %s", op_name, _mesa_lookup_enum_by_nr(op),
136
	      _mesa_lookup_enum_by_nr(dst));
137
  if (!optype)
138
    fprintf(stderr, ", %d", dstMask);
139
 
140
  fprintf(stderr, ", %s", create_dst_mod_str(dstMod));
141
 
142
  fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg1),
143
	      _mesa_lookup_enum_by_nr(arg1Rep), arg1Mod);
144
  if (arg_count>1)
145
    fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg2),
146
	      _mesa_lookup_enum_by_nr(arg2Rep), arg2Mod);
147
  if (arg_count>2)
148
    fprintf(stderr, ", %s, %s, %d", _mesa_lookup_enum_by_nr(arg3),
149
	      _mesa_lookup_enum_by_nr(arg3Rep), arg3Mod);
150
 
151
  fprintf(stderr,")\n");
152
 
153
}
154
#endif
155
 
156
static int check_arith_arg(struct ati_fragment_shader *curProg,
157
			GLuint optype, GLuint arg, GLuint argRep)
158
{
159
   GET_CURRENT_CONTEXT(ctx);
160
 
161
   if (((arg < GL_CON_0_ATI) || (arg > GL_CON_7_ATI)) &&
162
      ((arg < GL_REG_0_ATI) || (arg > GL_REG_5_ATI)) &&
163
      (arg != GL_ZERO) && (arg != GL_ONE) &&
164
      (arg != GL_PRIMARY_COLOR_ARB) && (arg != GL_SECONDARY_INTERPOLATOR_ATI)) {
165
      _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(arg)");
166
      return 0;
167
   }
168
   if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) ||
169
      ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) {
170
      _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
171
      return 0;
172
   }
173
   if ((arg == GL_SECONDARY_INTERPOLATOR_ATI) && (((optype == 0) && (argRep == GL_ALPHA)) ||
174
      ((optype == 1) && ((arg == GL_ALPHA) || (argRep == GL_NONE))))) {
175
      _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
176
      return 0;
177
   }
178
   if ((curProg->cur_pass == 1) &&
179
      ((arg == GL_PRIMARY_COLOR_ARB) || (arg == GL_SECONDARY_INTERPOLATOR_ATI))) {
180
      curProg->interpinp1 = GL_TRUE;
181
   }
182
   return 1;
183
}
184
 
185
GLuint GLAPIENTRY
186
_mesa_GenFragmentShadersATI(GLuint range)
187
{
188
   GLuint first;
189
   GLuint i;
190
   GET_CURRENT_CONTEXT(ctx);
191
 
192
   if (range == 0) {
193
      _mesa_error(ctx, GL_INVALID_VALUE, "glGenFragmentShadersATI(range)");
194
      return 0;
195
   }
196
 
197
   if (ctx->ATIFragmentShader.Compiling) {
198
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGenFragmentShadersATI(insideShader)");
199
      return 0;
200
   }
201
 
202
   first = _mesa_HashFindFreeKeyBlock(ctx->Shared->ATIShaders, range);
203
   for (i = 0; i < range; i++) {
204
      _mesa_HashInsert(ctx->Shared->ATIShaders, first + i, &DummyShader);
205
   }
206
 
207
   return first;
208
}
209
 
210
void GLAPIENTRY
211
_mesa_BindFragmentShaderATI(GLuint id)
212
{
213
   GET_CURRENT_CONTEXT(ctx);
214
   struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
215
   struct ati_fragment_shader *newProg;
216
 
217
   if (ctx->ATIFragmentShader.Compiling) {
218
      _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFragmentShaderATI(insideShader)");
219
      return;
220
   }
221
 
222
   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
223
 
224
   if (curProg->Id == id) {
225
      return;
226
   }
227
 
228
   /* unbind current */
229
   if (curProg->Id != 0) {
230
      curProg->RefCount--;
231
      if (curProg->RefCount <= 0) {
232
	 _mesa_HashRemove(ctx->Shared->ATIShaders, id);
233
      }
234
   }
235
 
236
   /* find new shader */
237
   if (id == 0) {
238
      newProg = ctx->Shared->DefaultFragmentShader;
239
   }
240
   else {
241
      newProg = (struct ati_fragment_shader *)
242
         _mesa_HashLookup(ctx->Shared->ATIShaders, id);
243
      if (!newProg || newProg == &DummyShader) {
244
	 /* allocate a new program now */
245
	 newProg = _mesa_new_ati_fragment_shader(ctx, id);
246
	 if (!newProg) {
247
	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindFragmentShaderATI");
248
	    return;
249
	 }
250
	 _mesa_HashInsert(ctx->Shared->ATIShaders, id, newProg);
251
      }
252
 
253
   }
254
 
255
   /* do actual bind */
256
   ctx->ATIFragmentShader.Current = newProg;
257
 
258
   assert(ctx->ATIFragmentShader.Current);
259
   if (newProg)
260
      newProg->RefCount++;
261
 
262
   /*if (ctx->Driver.BindProgram)
263
      ctx->Driver.BindProgram(ctx, target, prog); */
264
}
265
 
266
void GLAPIENTRY
267
_mesa_DeleteFragmentShaderATI(GLuint id)
268
{
269
   GET_CURRENT_CONTEXT(ctx);
270
 
271
   if (ctx->ATIFragmentShader.Compiling) {
272
      _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteFragmentShaderATI(insideShader)");
273
      return;
274
   }
275
 
276
   if (id != 0) {
277
      struct ati_fragment_shader *prog = (struct ati_fragment_shader *)
278
	 _mesa_HashLookup(ctx->Shared->ATIShaders, id);
279
      if (prog == &DummyShader) {
280
	 _mesa_HashRemove(ctx->Shared->ATIShaders, id);
281
      }
282
      else if (prog) {
283
	 if (ctx->ATIFragmentShader.Current &&
284
	     ctx->ATIFragmentShader.Current->Id == id) {
285
	     FLUSH_VERTICES(ctx, _NEW_PROGRAM);
286
	    _mesa_BindFragmentShaderATI(0);
287
	 }
288
      }
289
 
290
      /* The ID is immediately available for re-use now */
291
      _mesa_HashRemove(ctx->Shared->ATIShaders, id);
292
      if (prog) {
293
	 prog->RefCount--;
294
	 if (prog->RefCount <= 0) {
295
	    assert(prog != &DummyShader);
296
	    free(prog);
297
	 }
298
      }
299
   }
300
}
301
 
302
 
303
void GLAPIENTRY
304
_mesa_BeginFragmentShaderATI(void)
305
{
306
   GLint i;
307
   GET_CURRENT_CONTEXT(ctx);
308
 
309
   if (ctx->ATIFragmentShader.Compiling) {
310
      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginFragmentShaderATI(insideShader)");
311
      return;
312
   }
313
 
314
   FLUSH_VERTICES(ctx, _NEW_PROGRAM);
315
 
316
   /* if the shader was already defined free instructions and get new ones
317
      (or, could use the same mem but would need to reinitialize) */
318
   /* no idea if it's allowed to redefine a shader */
319
   for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
320
         free(ctx->ATIFragmentShader.Current->Instructions[i]);
321
         free(ctx->ATIFragmentShader.Current->SetupInst[i]);
322
   }
323
 
324
   /* malloc the instructions here - not sure if the best place but its
325
      a start */
326
   for (i = 0; i < MAX_NUM_PASSES_ATI; i++) {
327
      ctx->ATIFragmentShader.Current->Instructions[i] =
328
	 calloc(sizeof(struct atifs_instruction),
329
                MAX_NUM_INSTRUCTIONS_PER_PASS_ATI);
330
      ctx->ATIFragmentShader.Current->SetupInst[i] =
331
	 calloc(sizeof(struct atifs_setupinst),
332
                MAX_NUM_FRAGMENT_REGISTERS_ATI);
333
   }
334
 
335
/* can't rely on calloc for initialization as it's possible to redefine a shader (?) */
336
   ctx->ATIFragmentShader.Current->LocalConstDef = 0;
337
   ctx->ATIFragmentShader.Current->numArithInstr[0] = 0;
338
   ctx->ATIFragmentShader.Current->numArithInstr[1] = 0;
339
   ctx->ATIFragmentShader.Current->regsAssigned[0] = 0;
340
   ctx->ATIFragmentShader.Current->regsAssigned[1] = 0;
341
   ctx->ATIFragmentShader.Current->NumPasses = 0;
342
   ctx->ATIFragmentShader.Current->cur_pass = 0;
343
   ctx->ATIFragmentShader.Current->last_optype = 0;
344
   ctx->ATIFragmentShader.Current->interpinp1 = GL_FALSE;
345
   ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
346
   ctx->ATIFragmentShader.Current->swizzlerq = 0;
347
   ctx->ATIFragmentShader.Compiling = 1;
348
}
349
 
350
void GLAPIENTRY
351
_mesa_EndFragmentShaderATI(void)
352
{
353
   GET_CURRENT_CONTEXT(ctx);
354
   struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
355
#if MESA_DEBUG_ATI_FS
356
   GLint i, j;
357
#endif
358
 
359
   if (!ctx->ATIFragmentShader.Compiling) {
360
      _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(outsideShader)");
361
      return;
362
   }
363
   if (curProg->interpinp1 && (ctx->ATIFragmentShader.Current->cur_pass > 1)) {
364
      _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(interpinfirstpass)");
365
   /* according to spec, DON'T return here */
366
   }
367
 
368
   match_pair_inst(curProg, 0);
369
   ctx->ATIFragmentShader.Compiling = 0;
370
   ctx->ATIFragmentShader.Current->isValid = GL_TRUE;
371
   if ((ctx->ATIFragmentShader.Current->cur_pass == 0) ||
372
      (ctx->ATIFragmentShader.Current->cur_pass == 2)) {
373
      _mesa_error(ctx, GL_INVALID_OPERATION, "glEndFragmentShaderATI(noarithinst)");
374
   }
375
   if (ctx->ATIFragmentShader.Current->cur_pass > 1)
376
      ctx->ATIFragmentShader.Current->NumPasses = 2;
377
   else
378
      ctx->ATIFragmentShader.Current->NumPasses = 1;
379
 
380
   ctx->ATIFragmentShader.Current->cur_pass = 0;
381
 
382
#if MESA_DEBUG_ATI_FS
383
   for (j = 0; j < MAX_NUM_PASSES_ATI; j++) {
384
      for (i = 0; i < MAX_NUM_FRAGMENT_REGISTERS_ATI; i++) {
385
	 GLuint op = curProg->SetupInst[j][i].Opcode;
386
	 const char *op_enum = op > 5 ? _mesa_lookup_enum_by_nr(op) : "0";
387
	 GLuint src = curProg->SetupInst[j][i].src;
388
	 GLuint swizzle = curProg->SetupInst[j][i].swizzle;
389
	 fprintf(stderr, "%2d %04X %s %d %04X\n", i, op, op_enum, src,
390
	      swizzle);
391
      }
392
      for (i = 0; i < curProg->numArithInstr[j]; i++) {
393
	 GLuint op0 = curProg->Instructions[j][i].Opcode[0];
394
	 GLuint op1 = curProg->Instructions[j][i].Opcode[1];
395
	 const char *op0_enum = op0 > 5 ? _mesa_lookup_enum_by_nr(op0) : "0";
396
	 const char *op1_enum = op1 > 5 ? _mesa_lookup_enum_by_nr(op1) : "0";
397
	 GLuint count0 = curProg->Instructions[j][i].ArgCount[0];
398
	 GLuint count1 = curProg->Instructions[j][i].ArgCount[1];
399
	 fprintf(stderr, "%2d %04X %s %d %04X %s %d\n", i, op0, op0_enum, count0,
400
	      op1, op1_enum, count1);
401
      }
402
   }
403
#endif
404
 
405
   if (!ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_SHADER_ATI, NULL)) {
406
      ctx->ATIFragmentShader.Current->isValid = GL_FALSE;
407
      /* XXX is this the right error? */
408
      _mesa_error(ctx, GL_INVALID_OPERATION,
409
                  "glEndFragmentShaderATI(driver rejected shader)");
410
   }
411
}
412
 
413
void GLAPIENTRY
414
_mesa_PassTexCoordATI(GLuint dst, GLuint coord, GLenum swizzle)
415
{
416
   GET_CURRENT_CONTEXT(ctx);
417
   struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
418
   struct atifs_setupinst *curI;
419
 
420
   if (!ctx->ATIFragmentShader.Compiling) {
421
      _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(outsideShader)");
422
      return;
423
   }
424
 
425
   if (curProg->cur_pass == 1) {
426
      match_pair_inst(curProg, 0);
427
      curProg->cur_pass = 2;
428
   }
429
   if ((curProg->cur_pass > 2) ||
430
      ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
431
      _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoord(pass)");
432
      return;
433
   }
434
   if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) ||
435
      ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) {
436
      _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(dst)");
437
      return;
438
   }
439
   if (((coord < GL_REG_0_ATI) || (coord > GL_REG_5_ATI)) &&
440
       ((coord < GL_TEXTURE0_ARB) || (coord > GL_TEXTURE7_ARB) ||
441
       ((coord - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) {
442
      _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(coord)");
443
      return;
444
   }
445
   if ((curProg->cur_pass == 0) && (coord >= GL_REG_0_ATI)) {
446
      _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(coord)");
447
      return;
448
   }
449
   if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) {
450
      _mesa_error(ctx, GL_INVALID_ENUM, "glPassTexCoordATI(swizzle)");
451
      return;
452
   }
453
   if ((swizzle & 1) && (coord >= GL_REG_0_ATI)) {
454
      _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)");
455
      return;
456
   }
457
   if (coord <= GL_TEXTURE7_ARB) {
458
      GLuint tmp = coord - GL_TEXTURE0_ARB;
459
      if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) &&
460
	   (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) {
461
	 _mesa_error(ctx, GL_INVALID_OPERATION, "glPassTexCoordATI(swizzle)");
462
	 return;
463
      } else {
464
	 curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2));
465
      }
466
   }
467
 
468
   curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
469
   new_tex_inst(curProg);
470
 
471
   /* add the instructions */
472
   curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
473
 
474
   curI->Opcode = ATI_FRAGMENT_SHADER_PASS_OP;
475
   curI->src = coord;
476
   curI->swizzle = swizzle;
477
 
478
#if MESA_DEBUG_ATI_FS
479
   _mesa_debug(ctx, "%s(%s, %s, %s)\n", __func__,
480
	       _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(coord),
481
	       _mesa_lookup_enum_by_nr(swizzle));
482
#endif
483
}
484
 
485
void GLAPIENTRY
486
_mesa_SampleMapATI(GLuint dst, GLuint interp, GLenum swizzle)
487
{
488
   GET_CURRENT_CONTEXT(ctx);
489
   struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
490
   struct atifs_setupinst *curI;
491
 
492
   if (!ctx->ATIFragmentShader.Compiling) {
493
      _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(outsideShader)");
494
      return;
495
   }
496
 
497
   if (curProg->cur_pass == 1) {
498
      match_pair_inst(curProg, 0);
499
      curProg->cur_pass = 2;
500
   }
501
   if ((curProg->cur_pass > 2) ||
502
      ((1 << (dst - GL_REG_0_ATI)) & curProg->regsAssigned[curProg->cur_pass >> 1])) {
503
      _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(pass)");
504
      return;
505
   }
506
   if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI) ||
507
      ((dst - GL_REG_0_ATI) >= ctx->Const.MaxTextureUnits)) {
508
      _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(dst)");
509
      return;
510
   }
511
   if (((interp < GL_REG_0_ATI) || (interp > GL_REG_5_ATI)) &&
512
       ((interp < GL_TEXTURE0_ARB) || (interp > GL_TEXTURE7_ARB) ||
513
       ((interp - GL_TEXTURE0_ARB) >= ctx->Const.MaxTextureUnits))) {
514
   /* is this texture5 or texture7? spec is a bit unclear there */
515
      _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(interp)");
516
      return;
517
   }
518
   if ((curProg->cur_pass == 0) && (interp >= GL_REG_0_ATI)) {
519
      _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(interp)");
520
      return;
521
   }
522
   if (!(swizzle >= GL_SWIZZLE_STR_ATI) && (swizzle <= GL_SWIZZLE_STQ_DQ_ATI)) {
523
      _mesa_error(ctx, GL_INVALID_ENUM, "glSampleMapATI(swizzle)");
524
      return;
525
   }
526
   if ((swizzle & 1) && (interp >= GL_REG_0_ATI)) {
527
      _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)");
528
      return;
529
   }
530
   if (interp <= GL_TEXTURE7_ARB) {
531
      GLuint tmp = interp - GL_TEXTURE0_ARB;
532
      if ((((curProg->swizzlerq >> (tmp * 2)) & 3) != 0) &&
533
	   (((swizzle & 1) + 1) != ((curProg->swizzlerq >> (tmp * 2)) & 3))) {
534
	 _mesa_error(ctx, GL_INVALID_OPERATION, "glSampleMapATI(swizzle)");
535
	 return;
536
      } else {
537
	 curProg->swizzlerq |= (((swizzle & 1) + 1) << (tmp * 2));
538
      }
539
   }
540
 
541
   curProg->regsAssigned[curProg->cur_pass >> 1] |= 1 << (dst - GL_REG_0_ATI);
542
   new_tex_inst(curProg);
543
 
544
   /* add the instructions */
545
   curI = &curProg->SetupInst[curProg->cur_pass >> 1][dst - GL_REG_0_ATI];
546
 
547
   curI->Opcode = ATI_FRAGMENT_SHADER_SAMPLE_OP;
548
   curI->src = interp;
549
   curI->swizzle = swizzle;
550
 
551
#if MESA_DEBUG_ATI_FS
552
   _mesa_debug(ctx, "%s(%s, %s, %s)\n", __func__,
553
	       _mesa_lookup_enum_by_nr(dst), _mesa_lookup_enum_by_nr(interp),
554
	       _mesa_lookup_enum_by_nr(swizzle));
555
#endif
556
}
557
 
558
static void
559
_mesa_FragmentOpXATI(GLint optype, GLuint arg_count, GLenum op, GLuint dst,
560
		     GLuint dstMask, GLuint dstMod, GLuint arg1,
561
		     GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
562
		     GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
563
		     GLuint arg3Rep, GLuint arg3Mod)
564
{
565
   GET_CURRENT_CONTEXT(ctx);
566
   struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
567
   GLint ci;
568
   struct atifs_instruction *curI;
569
   GLuint modtemp = dstMod & ~GL_SATURATE_BIT_ATI;
570
 
571
   if (!ctx->ATIFragmentShader.Compiling) {
572
      _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(outsideShader)");
573
      return;
574
   }
575
 
576
   if (curProg->cur_pass==0)
577
      curProg->cur_pass=1;
578
 
579
   else if (curProg->cur_pass==2)
580
      curProg->cur_pass=3;
581
 
582
   /* decide whether this is a new instruction or not ... all color instructions are new,
583
      and alpha instructions might also be new if there was no preceding color inst */
584
   if ((optype == 0) || (curProg->last_optype == optype)) {
585
      if (curProg->numArithInstr[curProg->cur_pass >> 1] > 7) {
586
	 _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(instrCount)");
587
	 return;
588
      }
589
      /* easier to do that here slight side effect invalid instr will still be inserted as nops */
590
      match_pair_inst(curProg, optype);
591
      new_arith_inst(curProg);
592
   }
593
   curProg->last_optype = optype;
594
   ci = curProg->numArithInstr[curProg->cur_pass >> 1] - 1;
595
 
596
   /* add the instructions */
597
   curI = &curProg->Instructions[curProg->cur_pass >> 1][ci];
598
 
599
   /* error checking */
600
   if ((dst < GL_REG_0_ATI) || (dst > GL_REG_5_ATI)) {
601
      _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dst)");
602
      return;
603
   }
604
   if ((modtemp != GL_NONE) && (modtemp != GL_2X_BIT_ATI) &&
605
      (modtemp != GL_4X_BIT_ATI) && (modtemp != GL_8X_BIT_ATI) &&
606
      (modtemp != GL_HALF_BIT_ATI) && !(modtemp != GL_QUARTER_BIT_ATI) &&
607
      (modtemp != GL_EIGHTH_BIT_ATI)) {
608
      _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(dstMod)%x", modtemp);
609
      return;
610
   }
611
   /* op checking? Actually looks like that's missing in the spec but we'll do it anyway */
612
   if (((op < GL_ADD_ATI) || (op > GL_DOT2_ADD_ATI)) && !(op == GL_MOV_ATI)) {
613
      _mesa_error(ctx, GL_INVALID_ENUM, "C/AFragmentOpATI(op)");
614
      return;
615
   }
616
   if (optype == 1) {
617
      if (((op == GL_DOT2_ADD_ATI) && (curI->Opcode[0] != GL_DOT2_ADD_ATI)) ||
618
	 ((op == GL_DOT3_ATI) && (curI->Opcode[0] != GL_DOT3_ATI)) ||
619
	 ((op == GL_DOT4_ATI) && (curI->Opcode[0] != GL_DOT4_ATI)) ||
620
	 ((op != GL_DOT4_ATI) && (curI->Opcode[0] == GL_DOT4_ATI))) {
621
	 _mesa_error(ctx, GL_INVALID_OPERATION, "AFragmentOpATI(op)");
622
	 return;
623
      }
624
   }
625
   if ((op == GL_DOT4_ATI) &&
626
      (((arg1 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg1Rep == GL_ALPHA) || (arg1Rep == GL_NONE))) ||
627
      (((arg2 == GL_SECONDARY_INTERPOLATOR_ATI) && ((arg2Rep == GL_ALPHA) || (arg2Rep == GL_NONE)))))) {
628
      _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(sec_interp)");
629
   }
630
 
631
   if (!check_arith_arg(curProg, optype, arg1, arg1Rep)) {
632
      return;
633
   }
634
   if (arg2) {
635
      if (!check_arith_arg(curProg, optype, arg2, arg2Rep)) {
636
	 return;
637
      }
638
   }
639
   if (arg3) {
640
      if (!check_arith_arg(curProg, optype, arg3, arg3Rep)) {
641
	 return;
642
      }
643
      if ((arg1 >= GL_CON_0_ATI) && (arg1 <= GL_CON_7_ATI) &&
644
	  (arg2 >= GL_CON_0_ATI) && (arg2 <= GL_CON_7_ATI) &&
645
	  (arg3 >= GL_CON_0_ATI) && (arg3 <= GL_CON_7_ATI) &&
646
	  (arg1 != arg2) && (arg1 != arg3) && (arg2 != arg3)) {
647
	 _mesa_error(ctx, GL_INVALID_OPERATION, "C/AFragmentOpATI(3Consts)");
648
	 return;
649
      }
650
   }
651
 
652
   /* all ok - not all fully validated though (e.g. argNMod - spec doesn't say anything) */
653
 
654
   curI->Opcode[optype] = op;
655
   curI->SrcReg[optype][0].Index = arg1;
656
   curI->SrcReg[optype][0].argRep = arg1Rep;
657
   curI->SrcReg[optype][0].argMod = arg1Mod;
658
   curI->ArgCount[optype] = arg_count;
659
 
660
   if (arg2) {
661
      curI->SrcReg[optype][1].Index = arg2;
662
      curI->SrcReg[optype][1].argRep = arg2Rep;
663
      curI->SrcReg[optype][1].argMod = arg2Mod;
664
   }
665
 
666
   if (arg3) {
667
      curI->SrcReg[optype][2].Index = arg3;
668
      curI->SrcReg[optype][2].argRep = arg3Rep;
669
      curI->SrcReg[optype][2].argMod = arg3Mod;
670
   }
671
 
672
   curI->DstReg[optype].Index = dst;
673
   curI->DstReg[optype].dstMod = dstMod;
674
   curI->DstReg[optype].dstMask = dstMask;
675
 
676
#if MESA_DEBUG_ATI_FS
677
   debug_op(optype, arg_count, op, dst, dstMask, dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3, arg3Rep, arg3Mod);
678
#endif
679
 
680
}
681
 
682
void GLAPIENTRY
683
_mesa_ColorFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMask,
684
			  GLuint dstMod, GLuint arg1, GLuint arg1Rep,
685
			  GLuint arg1Mod)
686
{
687
   _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 1, op, dst, dstMask,
688
			dstMod, arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
689
}
690
 
691
void GLAPIENTRY
692
_mesa_ColorFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMask,
693
			  GLuint dstMod, GLuint arg1, GLuint arg1Rep,
694
			  GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
695
			  GLuint arg2Mod)
696
{
697
   _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 2, op, dst, dstMask,
698
			dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
699
			arg2Mod, 0, 0, 0);
700
}
701
 
702
void GLAPIENTRY
703
_mesa_ColorFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMask,
704
			  GLuint dstMod, GLuint arg1, GLuint arg1Rep,
705
			  GLuint arg1Mod, GLuint arg2, GLuint arg2Rep,
706
			  GLuint arg2Mod, GLuint arg3, GLuint arg3Rep,
707
			  GLuint arg3Mod)
708
{
709
   _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_COLOR_OP, 3, op, dst, dstMask,
710
			dstMod, arg1, arg1Rep, arg1Mod, arg2, arg2Rep,
711
			arg2Mod, arg3, arg3Rep, arg3Mod);
712
}
713
 
714
void GLAPIENTRY
715
_mesa_AlphaFragmentOp1ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
716
			  GLuint arg1Rep, GLuint arg1Mod)
717
{
718
   _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 1, op, dst, 0, dstMod,
719
			arg1, arg1Rep, arg1Mod, 0, 0, 0, 0, 0, 0);
720
}
721
 
722
void GLAPIENTRY
723
_mesa_AlphaFragmentOp2ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
724
			  GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
725
			  GLuint arg2Rep, GLuint arg2Mod)
726
{
727
   _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 2, op, dst, 0, dstMod,
728
			arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, 0, 0,
729
			0);
730
}
731
 
732
void GLAPIENTRY
733
_mesa_AlphaFragmentOp3ATI(GLenum op, GLuint dst, GLuint dstMod, GLuint arg1,
734
			  GLuint arg1Rep, GLuint arg1Mod, GLuint arg2,
735
			  GLuint arg2Rep, GLuint arg2Mod, GLuint arg3,
736
			  GLuint arg3Rep, GLuint arg3Mod)
737
{
738
   _mesa_FragmentOpXATI(ATI_FRAGMENT_SHADER_ALPHA_OP, 3, op, dst, 0, dstMod,
739
			arg1, arg1Rep, arg1Mod, arg2, arg2Rep, arg2Mod, arg3,
740
			arg3Rep, arg3Mod);
741
}
742
 
743
void GLAPIENTRY
744
_mesa_SetFragmentShaderConstantATI(GLuint dst, const GLfloat * value)
745
{
746
   GLuint dstindex;
747
   GET_CURRENT_CONTEXT(ctx);
748
 
749
   if ((dst < GL_CON_0_ATI) || (dst > GL_CON_7_ATI)) {
750
      /* spec says nothing about what should happen here but we can't just segfault...*/
751
      _mesa_error(ctx, GL_INVALID_ENUM, "glSetFragmentShaderConstantATI(dst)");
752
      return;
753
   }
754
 
755
   dstindex = dst - GL_CON_0_ATI;
756
   if (ctx->ATIFragmentShader.Compiling) {
757
      struct ati_fragment_shader *curProg = ctx->ATIFragmentShader.Current;
758
      COPY_4V(curProg->Constants[dstindex], value);
759
      curProg->LocalConstDef |= 1 << dstindex;
760
   }
761
   else {
762
      FLUSH_VERTICES(ctx, _NEW_PROGRAM);
763
      COPY_4V(ctx->ATIFragmentShader.GlobalConstants[dstindex], value);
764
   }
765
}