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