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