1 /* 2 * Copyright 2014 VMware, Inc. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26 27 /** 28 * This utility transforms the geometry shader to emulate point sprite by 29 * drawing a quad. It also adds an extra output for the original point position 30 * if the point position is to be written to a stream output buffer. 31 * Note: It assumes the driver will add a constant for the inverse viewport 32 * after the user defined constants. 33 */ 34 35 #include "util/u_debug.h" 36 #include "util/u_math.h" 37 #include "tgsi_info.h" 38 #include "tgsi_point_sprite.h" 39 #include "tgsi_transform.h" 40 #include "pipe/p_state.h" 41 42 #define INVALID_INDEX 9999 43 44 /* Set swizzle based on the immediates (0, 1, 0, -1) */ 45 static inline unsigned 46 set_swizzle(int x, int y, int z, int w) 47 { 48 static const unsigned map[3] = {TGSI_SWIZZLE_W, TGSI_SWIZZLE_X, 49 TGSI_SWIZZLE_Y}; 50 assert(x >= -1); 51 assert(x <= 1); 52 assert(y >= -1); 53 assert(y <= 1); 54 assert(z >= -1); 55 assert(z <= 1); 56 assert(w >= -1); 57 assert(w <= 1); 58 59 return map[x+1] | (map[y+1] << 2) | (map[z+1] << 4) | (map[w+1] << 6); 60 } 61 62 static inline unsigned 63 get_swizzle(unsigned swizzle, unsigned component) 64 { 65 assert(component < 4); 66 return (swizzle >> (component * 2)) & 0x3; 67 } 68 69 struct psprite_transform_context 70 { 71 struct tgsi_transform_context base; 72 unsigned num_tmp; 73 unsigned num_out; 74 unsigned num_orig_out; 75 unsigned num_const; 76 unsigned num_imm; 77 unsigned point_size_in; // point size input 78 unsigned point_size_out; // point size output 79 unsigned point_size_tmp; // point size temp 80 unsigned point_pos_in; // point pos input 81 unsigned point_pos_out; // point pos output 82 unsigned point_pos_sout; // original point pos for streamout 83 unsigned point_pos_tmp; // point pos temp 84 unsigned point_scale_tmp; // point scale temp 85 unsigned point_color_out; // point color output 86 unsigned point_color_tmp; // point color temp 87 unsigned point_imm; // point immediates 88 unsigned point_ivp; // point inverseViewport constant 89 unsigned point_dir_swz[4]; // point direction swizzle 90 unsigned point_coord_swz[4]; // point coord swizzle 91 unsigned point_coord_enable; // point coord enable mask 92 unsigned point_coord_decl; // point coord output declared mask 93 unsigned point_coord_out; // point coord output starting index 94 unsigned point_coord_aa; // aa point coord semantic index 95 unsigned point_coord_k; // aa point coord threshold distance 96 unsigned stream_out_point_pos:1; // set if to stream out original point pos 97 unsigned aa_point:1; // set if doing aa point 98 unsigned out_tmp_index[PIPE_MAX_SHADER_OUTPUTS]; 99 int max_generic; // max generic semantic index 100 }; 101 102 static inline struct psprite_transform_context * 103 psprite_transform_context(struct tgsi_transform_context *ctx) 104 { 105 return (struct psprite_transform_context *) ctx; 106 } 107 108 109 /** 110 * TGSI declaration transform callback. 111 */ 112 static void 113 psprite_decl(struct tgsi_transform_context *ctx, 114 struct tgsi_full_declaration *decl) 115 { 116 struct psprite_transform_context *ts = psprite_transform_context(ctx); 117 118 if (decl->Declaration.File == TGSI_FILE_INPUT) { 119 if (decl->Semantic.Name == TGSI_SEMANTIC_PSIZE) { 120 ts->point_size_in = decl->Range.First; 121 } 122 else if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) { 123 ts->point_pos_in = decl->Range.First; 124 } 125 } 126 else if (decl->Declaration.File == TGSI_FILE_OUTPUT) { 127 if (decl->Semantic.Name == TGSI_SEMANTIC_PSIZE) { 128 ts->point_size_out = decl->Range.First; 129 } 130 else if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) { 131 ts->point_pos_out = decl->Range.First; 132 } 133 else if (decl->Semantic.Name == TGSI_SEMANTIC_GENERIC && 134 decl->Semantic.Index < 32) { 135 ts->point_coord_decl |= 1 << decl->Semantic.Index; 136 ts->max_generic = MAX2(ts->max_generic, (int)decl->Semantic.Index); 137 } 138 ts->num_out = MAX2(ts->num_out, decl->Range.Last + 1); 139 } 140 else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { 141 ts->num_tmp = MAX2(ts->num_tmp, decl->Range.Last + 1); 142 } 143 else if (decl->Declaration.File == TGSI_FILE_CONSTANT) { 144 ts->num_const = MAX2(ts->num_const, decl->Range.Last + 1); 145 } 146 147 ctx->emit_declaration(ctx, decl); 148 } 149 150 /** 151 * TGSI immediate declaration transform callback. 152 */ 153 static void 154 psprite_immediate(struct tgsi_transform_context *ctx, 155 struct tgsi_full_immediate *imm) 156 { 157 struct psprite_transform_context *ts = psprite_transform_context(ctx); 158 159 ctx->emit_immediate(ctx, imm); 160 ts->num_imm++; 161 } 162 163 164 /** 165 * TGSI transform prolog callback. 166 */ 167 static void 168 psprite_prolog(struct tgsi_transform_context *ctx) 169 { 170 struct psprite_transform_context *ts = psprite_transform_context(ctx); 171 unsigned point_coord_enable, en; 172 int i; 173 174 /* Replace output registers with temporary registers */ 175 for (i = 0; i < ts->num_out; i++) { 176 ts->out_tmp_index[i] = ts->num_tmp++; 177 } 178 ts->num_orig_out = ts->num_out; 179 180 /* Declare a tmp register for point scale */ 181 ts->point_scale_tmp = ts->num_tmp++; 182 183 if (ts->point_size_out != INVALID_INDEX) 184 ts->point_size_tmp = ts->out_tmp_index[ts->point_size_out]; 185 else 186 ts->point_size_tmp = ts->num_tmp++; 187 188 assert(ts->point_pos_out != INVALID_INDEX); 189 ts->point_pos_tmp = ts->out_tmp_index[ts->point_pos_out]; 190 ts->out_tmp_index[ts->point_pos_out] = INVALID_INDEX; 191 192 /* Declare one more tmp register for point coord threshold distance 193 * if we are generating anti-aliased point. 194 */ 195 if (ts->aa_point) 196 ts->point_coord_k = ts->num_tmp++; 197 198 tgsi_transform_temps_decl(ctx, ts->point_size_tmp, ts->num_tmp-1); 199 200 /* Declare an extra output for the original point position for stream out */ 201 if (ts->stream_out_point_pos) { 202 ts->point_pos_sout = ts->num_out++; 203 tgsi_transform_output_decl(ctx, ts->point_pos_sout, 204 TGSI_SEMANTIC_GENERIC, 0, 0); 205 } 206 207 /* point coord outputs to be declared */ 208 point_coord_enable = ts->point_coord_enable & ~ts->point_coord_decl; 209 210 /* Declare outputs for those point coord that are enabled but are not 211 * already declared in this shader. 212 */ 213 ts->point_coord_out = ts->num_out; 214 if (point_coord_enable) { 215 for (i = 0, en = point_coord_enable; en; en>>=1, i++) { 216 if (en & 0x1) { 217 tgsi_transform_output_decl(ctx, ts->num_out++, 218 TGSI_SEMANTIC_GENERIC, i, 0); 219 ts->max_generic = MAX2(ts->max_generic, (int)i); 220 } 221 } 222 } 223 224 /* add an extra generic output for aa point texcoord */ 225 if (ts->aa_point) { 226 ts->point_coord_aa = ts->max_generic + 1; 227 assert((ts->point_coord_enable & (1 << ts->point_coord_aa)) == 0); 228 ts->point_coord_enable |= 1 << (ts->point_coord_aa); 229 tgsi_transform_output_decl(ctx, ts->num_out++, TGSI_SEMANTIC_GENERIC, 230 ts->point_coord_aa, 0); 231 } 232 233 /* Declare extra immediates */ 234 ts->point_imm = ts->num_imm; 235 tgsi_transform_immediate_decl(ctx, 0, 1, 0.5, -1); 236 237 /* Declare point constant - 238 * constant.xy -- inverseViewport 239 * constant.z -- current point size 240 * constant.w -- max point size 241 * The driver needs to add this constant to the constant buffer 242 */ 243 ts->point_ivp = ts->num_const++; 244 tgsi_transform_const_decl(ctx, ts->point_ivp, ts->point_ivp); 245 246 /* If this geometry shader does not specify point size, 247 * get the current point size from the point constant. 248 */ 249 if (ts->point_size_out == INVALID_INDEX) { 250 struct tgsi_full_instruction inst; 251 252 inst = tgsi_default_full_instruction(); 253 inst.Instruction.Opcode = TGSI_OPCODE_MOV; 254 inst.Instruction.NumDstRegs = 1; 255 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, 256 ts->point_size_tmp, TGSI_WRITEMASK_XYZW); 257 inst.Instruction.NumSrcRegs = 1; 258 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_CONSTANT, 259 ts->point_ivp, TGSI_SWIZZLE_Z, 260 TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z); 261 ctx->emit_instruction(ctx, &inst); 262 } 263 } 264 265 266 /** 267 * Add the point sprite emulation instructions at the emit vertex instruction 268 */ 269 static void 270 psprite_emit_vertex_inst(struct tgsi_transform_context *ctx, 271 struct tgsi_full_instruction *vert_inst) 272 { 273 struct psprite_transform_context *ts = psprite_transform_context(ctx); 274 struct tgsi_full_instruction inst; 275 unsigned point_coord_enable, en; 276 unsigned i, j, s; 277 278 /* new point coord outputs */ 279 point_coord_enable = ts->point_coord_enable & ~ts->point_coord_decl; 280 281 /* OUTPUT[pos_sout] = TEMP[pos] */ 282 if (ts->point_pos_sout != INVALID_INDEX) { 283 tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV, 284 TGSI_FILE_OUTPUT, ts->point_pos_sout, 285 TGSI_WRITEMASK_XYZW, 286 TGSI_FILE_TEMPORARY, ts->point_pos_tmp); 287 } 288 289 /** 290 * Set up the point scale vector 291 * scale = pointSize * pos.w * inverseViewport 292 */ 293 294 /* MUL point_scale.x, point_size.x, point_pos.w */ 295 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MUL, 296 TGSI_FILE_TEMPORARY, ts->point_scale_tmp, TGSI_WRITEMASK_X, 297 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 298 TGSI_FILE_TEMPORARY, ts->point_pos_tmp, TGSI_SWIZZLE_W, false); 299 300 /* MUL point_scale.xy, point_scale.xx, inverseViewport.xy */ 301 inst = tgsi_default_full_instruction(); 302 inst.Instruction.Opcode = TGSI_OPCODE_MUL; 303 inst.Instruction.NumDstRegs = 1; 304 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, 305 ts->point_scale_tmp, TGSI_WRITEMASK_XY); 306 inst.Instruction.NumSrcRegs = 2; 307 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, 308 ts->point_scale_tmp, TGSI_SWIZZLE_X, 309 TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, TGSI_SWIZZLE_X); 310 tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_CONSTANT, 311 ts->point_ivp, TGSI_SWIZZLE_X, 312 TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z); 313 ctx->emit_instruction(ctx, &inst); 314 315 /** 316 * Set up the point coord threshold distance 317 * k = 0.5 - 1 / pointsize 318 */ 319 if (ts->aa_point) { 320 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_DIV, 321 TGSI_FILE_TEMPORARY, ts->point_coord_k, 322 TGSI_WRITEMASK_X, 323 TGSI_FILE_IMMEDIATE, ts->point_imm, 324 TGSI_SWIZZLE_Y, 325 TGSI_FILE_TEMPORARY, ts->point_size_tmp, 326 TGSI_SWIZZLE_X, false); 327 328 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_ADD, 329 TGSI_FILE_TEMPORARY, ts->point_coord_k, 330 TGSI_WRITEMASK_X, 331 TGSI_FILE_IMMEDIATE, ts->point_imm, 332 TGSI_SWIZZLE_Z, 333 TGSI_FILE_TEMPORARY, ts->point_coord_k, 334 TGSI_SWIZZLE_X, true); 335 } 336 337 338 for (i = 0; i < 4; i++) { 339 unsigned point_dir_swz = ts->point_dir_swz[i]; 340 unsigned point_coord_swz = ts->point_coord_swz[i]; 341 342 /* All outputs need to be emitted for each vertex */ 343 for (j = 0; j < ts->num_orig_out; j++) { 344 if (ts->out_tmp_index[j] != INVALID_INDEX) { 345 tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV, 346 TGSI_FILE_OUTPUT, j, 347 TGSI_WRITEMASK_XYZW, 348 TGSI_FILE_TEMPORARY, ts->out_tmp_index[j]); 349 } 350 } 351 352 /* pos = point_scale * point_dir + point_pos */ 353 inst = tgsi_default_full_instruction(); 354 inst.Instruction.Opcode = TGSI_OPCODE_MAD; 355 inst.Instruction.NumDstRegs = 1; 356 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_OUTPUT, ts->point_pos_out, 357 TGSI_WRITEMASK_XYZW); 358 inst.Instruction.NumSrcRegs = 3; 359 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, ts->point_scale_tmp, 360 TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X, 361 TGSI_SWIZZLE_X); 362 tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_IMMEDIATE, ts->point_imm, 363 get_swizzle(point_dir_swz, 0), 364 get_swizzle(point_dir_swz, 1), 365 get_swizzle(point_dir_swz, 2), 366 get_swizzle(point_dir_swz, 3)); 367 tgsi_transform_src_reg(&inst.Src[2], TGSI_FILE_TEMPORARY, ts->point_pos_tmp, 368 TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, 369 TGSI_SWIZZLE_W); 370 ctx->emit_instruction(ctx, &inst); 371 372 /* point coord */ 373 for (j = 0, s = 0, en = point_coord_enable; en; en>>=1, s++) { 374 unsigned dstReg; 375 376 if (en & 0x1) { 377 dstReg = ts->point_coord_out + j; 378 379 inst = tgsi_default_full_instruction(); 380 inst.Instruction.Opcode = TGSI_OPCODE_MOV; 381 inst.Instruction.NumDstRegs = 1; 382 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_OUTPUT, 383 dstReg, TGSI_WRITEMASK_XYZW); 384 inst.Instruction.NumSrcRegs = 1; 385 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_IMMEDIATE, ts->point_imm, 386 get_swizzle(point_coord_swz, 0), 387 get_swizzle(point_coord_swz, 1), 388 get_swizzle(point_coord_swz, 2), 389 get_swizzle(point_coord_swz, 3)); 390 ctx->emit_instruction(ctx, &inst); 391 392 /* MOV point_coord.z point_coord_k.x */ 393 if (s == ts->point_coord_aa) { 394 tgsi_transform_op1_swz_inst(ctx, TGSI_OPCODE_MOV, 395 TGSI_FILE_OUTPUT, dstReg, TGSI_WRITEMASK_Z, 396 TGSI_FILE_TEMPORARY, ts->point_coord_k, 397 TGSI_SWIZZLE_X); 398 } 399 j++; /* the next point coord output offset */ 400 } 401 } 402 403 /* Emit the EMIT instruction for each vertex of the quad */ 404 ctx->emit_instruction(ctx, vert_inst); 405 } 406 407 /* Emit the ENDPRIM instruction for the quad */ 408 inst = tgsi_default_full_instruction(); 409 inst.Instruction.Opcode = TGSI_OPCODE_ENDPRIM; 410 inst.Instruction.NumDstRegs = 0; 411 inst.Instruction.NumSrcRegs = 1; 412 inst.Src[0] = vert_inst->Src[0]; 413 ctx->emit_instruction(ctx, &inst); 414 } 415 416 417 /** 418 * TGSI instruction transform callback. 419 */ 420 static void 421 psprite_inst(struct tgsi_transform_context *ctx, 422 struct tgsi_full_instruction *inst) 423 { 424 struct psprite_transform_context *ts = psprite_transform_context(ctx); 425 426 if (inst->Instruction.Opcode == TGSI_OPCODE_EMIT) { 427 psprite_emit_vertex_inst(ctx, inst); 428 } 429 else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT && 430 inst->Dst[0].Register.Index == ts->point_size_out) { 431 /** 432 * Replace point size output reg with tmp reg. 433 * The tmp reg will be later used as a src reg for computing 434 * the point scale factor. 435 */ 436 inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 437 inst->Dst[0].Register.Index = ts->point_size_tmp; 438 ctx->emit_instruction(ctx, inst); 439 440 /* Clamp the point size */ 441 /* MAX point_size_tmp.x, point_size_tmp.x, point_imm.y */ 442 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MAX, 443 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_WRITEMASK_X, 444 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 445 TGSI_FILE_IMMEDIATE, ts->point_imm, TGSI_SWIZZLE_Y, false); 446 447 /* MIN point_size_tmp.x, point_size_tmp.x, point_ivp.w */ 448 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MIN, 449 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_WRITEMASK_X, 450 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 451 TGSI_FILE_CONSTANT, ts->point_ivp, TGSI_SWIZZLE_W, false); 452 } 453 else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT && 454 inst->Dst[0].Register.Index == ts->point_pos_out) { 455 /** 456 * Replace point pos output reg with tmp reg. 457 */ 458 inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 459 inst->Dst[0].Register.Index = ts->point_pos_tmp; 460 ctx->emit_instruction(ctx, inst); 461 } 462 else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT) { 463 /** 464 * Replace output reg with tmp reg. 465 */ 466 inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 467 inst->Dst[0].Register.Index = ts->out_tmp_index[inst->Dst[0].Register.Index]; 468 ctx->emit_instruction(ctx, inst); 469 } 470 else { 471 ctx->emit_instruction(ctx, inst); 472 } 473 } 474 475 476 /** 477 * TGSI property instruction transform callback. 478 * Transforms a point into a 4-vertex triangle strip. 479 */ 480 static void 481 psprite_property(struct tgsi_transform_context *ctx, 482 struct tgsi_full_property *prop) 483 { 484 switch (prop->Property.PropertyName) { 485 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 486 prop->u[0].Data = PIPE_PRIM_TRIANGLE_STRIP; 487 break; 488 case TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES: 489 prop->u[0].Data *= 4; 490 break; 491 default: 492 break; 493 } 494 ctx->emit_property(ctx, prop); 495 } 496 497 /** 498 * TGSI utility to transform a geometry shader to support point sprite. 499 */ 500 struct tgsi_token * 501 tgsi_add_point_sprite(const struct tgsi_token *tokens_in, 502 const unsigned point_coord_enable, 503 const bool sprite_origin_lower_left, 504 const bool stream_out_point_pos, 505 int *aa_point_coord_index) 506 { 507 struct psprite_transform_context transform; 508 const uint num_new_tokens = 200; /* should be enough */ 509 const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens; 510 struct tgsi_token *new_tokens; 511 512 /* setup transformation context */ 513 memset(&transform, 0, sizeof(transform)); 514 transform.base.transform_declaration = psprite_decl; 515 transform.base.transform_instruction = psprite_inst; 516 transform.base.transform_property = psprite_property; 517 transform.base.transform_immediate = psprite_immediate; 518 transform.base.prolog = psprite_prolog; 519 520 transform.point_size_in = INVALID_INDEX; 521 transform.point_size_out = INVALID_INDEX; 522 transform.point_size_tmp = INVALID_INDEX; 523 transform.point_pos_in = INVALID_INDEX; 524 transform.point_pos_out = INVALID_INDEX; 525 transform.point_pos_sout = INVALID_INDEX; 526 transform.point_pos_tmp = INVALID_INDEX; 527 transform.point_scale_tmp = INVALID_INDEX; 528 transform.point_imm = INVALID_INDEX; 529 transform.point_coord_aa = INVALID_INDEX; 530 transform.point_coord_k = INVALID_INDEX; 531 532 transform.stream_out_point_pos = stream_out_point_pos; 533 transform.point_coord_enable = point_coord_enable; 534 transform.aa_point = aa_point_coord_index != NULL; 535 transform.max_generic = -1; 536 537 /* point sprite directions based on the immediates (0, 1, 0.5, -1) */ 538 /* (-1, -1, 0, 0) */ 539 transform.point_dir_swz[0] = set_swizzle(-1, -1, 0, 0); 540 /* (-1, 1, 0, 0) */ 541 transform.point_dir_swz[1] = set_swizzle(-1, 1, 0, 0); 542 /* (1, -1, 0, 0) */ 543 transform.point_dir_swz[2] = set_swizzle(1, -1, 0, 0); 544 /* (1, 1, 0, 0) */ 545 transform.point_dir_swz[3] = set_swizzle(1, 1, 0, 0); 546 547 /* point coord based on the immediates (0, 1, 0, -1) */ 548 if (sprite_origin_lower_left) { 549 /* (0, 0, 0, 1) */ 550 transform.point_coord_swz[0] = set_swizzle(0, 0, 0, 1); 551 /* (0, 1, 0, 1) */ 552 transform.point_coord_swz[1] = set_swizzle(0, 1, 0, 1); 553 /* (1, 0, 0, 1) */ 554 transform.point_coord_swz[2] = set_swizzle(1, 0, 0, 1); 555 /* (1, 1, 0, 1) */ 556 transform.point_coord_swz[3] = set_swizzle(1, 1, 0, 1); 557 } 558 else { 559 /* (0, 1, 0, 1) */ 560 transform.point_coord_swz[0] = set_swizzle(0, 1, 0, 1); 561 /* (0, 0, 0, 1) */ 562 transform.point_coord_swz[1] = set_swizzle(0, 0, 0, 1); 563 /* (1, 1, 0, 1) */ 564 transform.point_coord_swz[2] = set_swizzle(1, 1, 0, 1); 565 /* (1, 0, 0, 1) */ 566 transform.point_coord_swz[3] = set_swizzle(1, 0, 0, 1); 567 } 568 569 570 /* allocate new tokens buffer */ 571 new_tokens = tgsi_alloc_tokens(new_len); 572 if (!new_tokens) 573 return NULL; 574 575 /* transform the shader */ 576 tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base); 577 578 if (aa_point_coord_index) 579 *aa_point_coord_index = transform.point_coord_aa; 580 581 return new_tokens; 582 } 583