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) */ 45static inline unsigned 46set_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 62static inline unsigned 63get_swizzle(unsigned swizzle, unsigned component) 64{ 65 assert(component < 4); 66 return (swizzle >> (component * 2)) & 0x3; 67} 68 69struct 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 need_texcoord_semantic:1; // set if need texcoord semantic 99 unsigned out_tmp_index[PIPE_MAX_SHADER_OUTPUTS]; 100 int max_generic; // max generic semantic index 101}; 102 103static inline struct psprite_transform_context * 104psprite_transform_context(struct tgsi_transform_context *ctx) 105{ 106 return (struct psprite_transform_context *) ctx; 107} 108 109 110/** 111 * TGSI declaration transform callback. 112 */ 113static void 114psprite_decl(struct tgsi_transform_context *ctx, 115 struct tgsi_full_declaration *decl) 116{ 117 struct psprite_transform_context *ts = psprite_transform_context(ctx); 118 unsigned range_end = decl->Range.Last + 1; 119 120 if (decl->Declaration.File == TGSI_FILE_INPUT) { 121 if (decl->Semantic.Name == TGSI_SEMANTIC_PSIZE) { 122 ts->point_size_in = decl->Range.First; 123 } 124 else if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) { 125 ts->point_pos_in = decl->Range.First; 126 } 127 } 128 else if (decl->Declaration.File == TGSI_FILE_OUTPUT) { 129 if (decl->Semantic.Name == TGSI_SEMANTIC_PSIZE) { 130 ts->point_size_out = decl->Range.First; 131 } 132 else if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION) { 133 ts->point_pos_out = decl->Range.First; 134 } 135 else if (!ts->need_texcoord_semantic && 136 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC && 137 decl->Semantic.Index < 32) { 138 ts->point_coord_decl |= 1 << decl->Semantic.Index; 139 ts->max_generic = MAX2(ts->max_generic, (int)decl->Semantic.Index); 140 } 141 else if (ts->need_texcoord_semantic && 142 decl->Semantic.Name == TGSI_SEMANTIC_TEXCOORD) { 143 ts->point_coord_decl |= 1 << decl->Semantic.Index; 144 } 145 ts->num_out = MAX2(ts->num_out, range_end); 146 } 147 else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) { 148 ts->num_tmp = MAX2(ts->num_tmp, range_end); 149 } 150 else if (decl->Declaration.File == TGSI_FILE_CONSTANT) { 151 ts->num_const = MAX2(ts->num_const, range_end); 152 } 153 154 ctx->emit_declaration(ctx, decl); 155} 156 157/** 158 * TGSI immediate declaration transform callback. 159 */ 160static void 161psprite_immediate(struct tgsi_transform_context *ctx, 162 struct tgsi_full_immediate *imm) 163{ 164 struct psprite_transform_context *ts = psprite_transform_context(ctx); 165 166 ctx->emit_immediate(ctx, imm); 167 ts->num_imm++; 168} 169 170 171/** 172 * TGSI transform prolog callback. 173 */ 174static void 175psprite_prolog(struct tgsi_transform_context *ctx) 176{ 177 struct psprite_transform_context *ts = psprite_transform_context(ctx); 178 unsigned point_coord_enable, en; 179 unsigned i; 180 181 /* Replace output registers with temporary registers */ 182 for (i = 0; i < ts->num_out; i++) { 183 ts->out_tmp_index[i] = ts->num_tmp++; 184 } 185 ts->num_orig_out = ts->num_out; 186 187 /* Declare a tmp register for point scale */ 188 ts->point_scale_tmp = ts->num_tmp++; 189 190 if (ts->point_size_out != INVALID_INDEX) 191 ts->point_size_tmp = ts->out_tmp_index[ts->point_size_out]; 192 else 193 ts->point_size_tmp = ts->num_tmp++; 194 195 assert(ts->point_pos_out != INVALID_INDEX); 196 ts->point_pos_tmp = ts->out_tmp_index[ts->point_pos_out]; 197 ts->out_tmp_index[ts->point_pos_out] = INVALID_INDEX; 198 199 /* Declare one more tmp register for point coord threshold distance 200 * if we are generating anti-aliased point. 201 */ 202 if (ts->aa_point) 203 ts->point_coord_k = ts->num_tmp++; 204 205 tgsi_transform_temps_decl(ctx, ts->point_size_tmp, ts->num_tmp-1); 206 207 /* Declare an extra output for the original point position for stream out */ 208 if (ts->stream_out_point_pos) { 209 ts->point_pos_sout = ts->num_out++; 210 tgsi_transform_output_decl(ctx, ts->point_pos_sout, 211 TGSI_SEMANTIC_GENERIC, 0, 0); 212 } 213 214 /* point coord outputs to be declared */ 215 point_coord_enable = ts->point_coord_enable & ~ts->point_coord_decl; 216 217 /* Declare outputs for those point coord that are enabled but are not 218 * already declared in this shader. 219 */ 220 ts->point_coord_out = ts->num_out; 221 if (point_coord_enable) { 222 if (ts->need_texcoord_semantic) { 223 for (i = 0, en = point_coord_enable; en; en>>=1, i++) { 224 if (en & 0x1) { 225 tgsi_transform_output_decl(ctx, ts->num_out++, 226 TGSI_SEMANTIC_TEXCOORD, i, 0); 227 } 228 } 229 } else { 230 for (i = 0, en = point_coord_enable; en; en>>=1, i++) { 231 if (en & 0x1) { 232 tgsi_transform_output_decl(ctx, ts->num_out++, 233 TGSI_SEMANTIC_GENERIC, i, 0); 234 ts->max_generic = MAX2(ts->max_generic, (int)i); 235 } 236 } 237 } 238 } 239 240 /* add an extra generic output for aa point texcoord */ 241 if (ts->aa_point) { 242 if (ts->need_texcoord_semantic) { 243 ts->point_coord_aa = 0; 244 } else { 245 ts->point_coord_aa = ts->max_generic + 1; 246 assert((ts->point_coord_enable & (1 << ts->point_coord_aa)) == 0); 247 ts->point_coord_enable |= 1 << (ts->point_coord_aa); 248 tgsi_transform_output_decl(ctx, ts->num_out++, TGSI_SEMANTIC_GENERIC, 249 ts->point_coord_aa, 0); 250 } 251 } 252 253 /* Declare extra immediates */ 254 ts->point_imm = ts->num_imm; 255 tgsi_transform_immediate_decl(ctx, 0, 1, 0.5, -1); 256 257 /* Declare point constant - 258 * constant.xy -- inverseViewport 259 * constant.z -- current point size 260 * constant.w -- max point size 261 * The driver needs to add this constant to the constant buffer 262 */ 263 ts->point_ivp = ts->num_const++; 264 tgsi_transform_const_decl(ctx, ts->point_ivp, ts->point_ivp); 265 266 /* If this geometry shader does not specify point size, 267 * get the current point size from the point constant. 268 */ 269 if (ts->point_size_out == INVALID_INDEX) { 270 struct tgsi_full_instruction inst; 271 272 inst = tgsi_default_full_instruction(); 273 inst.Instruction.Opcode = TGSI_OPCODE_MOV; 274 inst.Instruction.NumDstRegs = 1; 275 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, 276 ts->point_size_tmp, TGSI_WRITEMASK_XYZW); 277 inst.Instruction.NumSrcRegs = 1; 278 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_CONSTANT, 279 ts->point_ivp, TGSI_SWIZZLE_Z, 280 TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z); 281 ctx->emit_instruction(ctx, &inst); 282 } 283} 284 285 286/** 287 * Add the point sprite emulation instructions at the emit vertex instruction 288 */ 289static void 290psprite_emit_vertex_inst(struct tgsi_transform_context *ctx, 291 struct tgsi_full_instruction *vert_inst) 292{ 293 struct psprite_transform_context *ts = psprite_transform_context(ctx); 294 struct tgsi_full_instruction inst; 295 unsigned point_coord_enable, en; 296 unsigned i, j, s; 297 298 /* new point coord outputs */ 299 point_coord_enable = ts->point_coord_enable & ~ts->point_coord_decl; 300 301 /* OUTPUT[pos_sout] = TEMP[pos] */ 302 if (ts->point_pos_sout != INVALID_INDEX) { 303 tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV, 304 TGSI_FILE_OUTPUT, ts->point_pos_sout, 305 TGSI_WRITEMASK_XYZW, 306 TGSI_FILE_TEMPORARY, ts->point_pos_tmp); 307 } 308 309 /** 310 * Set up the point scale vector 311 * scale = pointSize * pos.w * inverseViewport 312 */ 313 314 /* MUL point_scale.x, point_size.x, point_pos.w */ 315 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MUL, 316 TGSI_FILE_TEMPORARY, ts->point_scale_tmp, TGSI_WRITEMASK_X, 317 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 318 TGSI_FILE_TEMPORARY, ts->point_pos_tmp, TGSI_SWIZZLE_W, false); 319 320 /* MUL point_scale.xy, point_scale.xx, inverseViewport.xy */ 321 inst = tgsi_default_full_instruction(); 322 inst.Instruction.Opcode = TGSI_OPCODE_MUL; 323 inst.Instruction.NumDstRegs = 1; 324 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY, 325 ts->point_scale_tmp, TGSI_WRITEMASK_XY); 326 inst.Instruction.NumSrcRegs = 2; 327 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, 328 ts->point_scale_tmp, TGSI_SWIZZLE_X, 329 TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, TGSI_SWIZZLE_X); 330 tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_CONSTANT, 331 ts->point_ivp, TGSI_SWIZZLE_X, 332 TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_Z); 333 ctx->emit_instruction(ctx, &inst); 334 335 /** 336 * Set up the point coord threshold distance 337 * k = 0.5 - 1 / pointsize 338 */ 339 if (ts->aa_point) { 340 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_DIV, 341 TGSI_FILE_TEMPORARY, ts->point_coord_k, 342 TGSI_WRITEMASK_X, 343 TGSI_FILE_IMMEDIATE, ts->point_imm, 344 TGSI_SWIZZLE_Y, 345 TGSI_FILE_TEMPORARY, ts->point_size_tmp, 346 TGSI_SWIZZLE_X, false); 347 348 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_ADD, 349 TGSI_FILE_TEMPORARY, ts->point_coord_k, 350 TGSI_WRITEMASK_X, 351 TGSI_FILE_IMMEDIATE, ts->point_imm, 352 TGSI_SWIZZLE_Z, 353 TGSI_FILE_TEMPORARY, ts->point_coord_k, 354 TGSI_SWIZZLE_X, true); 355 } 356 357 358 for (i = 0; i < 4; i++) { 359 unsigned point_dir_swz = ts->point_dir_swz[i]; 360 unsigned point_coord_swz = ts->point_coord_swz[i]; 361 362 /* All outputs need to be emitted for each vertex */ 363 for (j = 0; j < ts->num_orig_out; j++) { 364 if (ts->out_tmp_index[j] != INVALID_INDEX) { 365 tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV, 366 TGSI_FILE_OUTPUT, j, 367 TGSI_WRITEMASK_XYZW, 368 TGSI_FILE_TEMPORARY, ts->out_tmp_index[j]); 369 } 370 } 371 372 /* pos = point_scale * point_dir + point_pos */ 373 inst = tgsi_default_full_instruction(); 374 inst.Instruction.Opcode = TGSI_OPCODE_MAD; 375 inst.Instruction.NumDstRegs = 1; 376 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_OUTPUT, ts->point_pos_out, 377 TGSI_WRITEMASK_XYZW); 378 inst.Instruction.NumSrcRegs = 3; 379 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY, ts->point_scale_tmp, 380 TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_X, 381 TGSI_SWIZZLE_X); 382 tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_IMMEDIATE, ts->point_imm, 383 get_swizzle(point_dir_swz, 0), 384 get_swizzle(point_dir_swz, 1), 385 get_swizzle(point_dir_swz, 2), 386 get_swizzle(point_dir_swz, 3)); 387 tgsi_transform_src_reg(&inst.Src[2], TGSI_FILE_TEMPORARY, ts->point_pos_tmp, 388 TGSI_SWIZZLE_X, TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, 389 TGSI_SWIZZLE_W); 390 ctx->emit_instruction(ctx, &inst); 391 392 /* point coord */ 393 for (j = 0, s = 0, en = point_coord_enable; en; en>>=1, s++) { 394 unsigned dstReg; 395 396 if (en & 0x1) { 397 dstReg = ts->point_coord_out + j; 398 399 inst = tgsi_default_full_instruction(); 400 inst.Instruction.Opcode = TGSI_OPCODE_MOV; 401 inst.Instruction.NumDstRegs = 1; 402 tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_OUTPUT, 403 dstReg, TGSI_WRITEMASK_XYZW); 404 inst.Instruction.NumSrcRegs = 1; 405 tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_IMMEDIATE, ts->point_imm, 406 get_swizzle(point_coord_swz, 0), 407 get_swizzle(point_coord_swz, 1), 408 get_swizzle(point_coord_swz, 2), 409 get_swizzle(point_coord_swz, 3)); 410 ctx->emit_instruction(ctx, &inst); 411 412 /* MOV point_coord.z point_coord_k.x */ 413 if (s == ts->point_coord_aa) { 414 tgsi_transform_op1_swz_inst(ctx, TGSI_OPCODE_MOV, 415 TGSI_FILE_OUTPUT, dstReg, TGSI_WRITEMASK_Z, 416 TGSI_FILE_TEMPORARY, ts->point_coord_k, 417 TGSI_SWIZZLE_X); 418 } 419 j++; /* the next point coord output offset */ 420 } 421 } 422 423 /* Emit the EMIT instruction for each vertex of the quad */ 424 ctx->emit_instruction(ctx, vert_inst); 425 } 426 427 /* Emit the ENDPRIM instruction for the quad */ 428 inst = tgsi_default_full_instruction(); 429 inst.Instruction.Opcode = TGSI_OPCODE_ENDPRIM; 430 inst.Instruction.NumDstRegs = 0; 431 inst.Instruction.NumSrcRegs = 1; 432 inst.Src[0] = vert_inst->Src[0]; 433 ctx->emit_instruction(ctx, &inst); 434} 435 436 437/** 438 * TGSI instruction transform callback. 439 */ 440static void 441psprite_inst(struct tgsi_transform_context *ctx, 442 struct tgsi_full_instruction *inst) 443{ 444 struct psprite_transform_context *ts = psprite_transform_context(ctx); 445 446 if (inst->Instruction.Opcode == TGSI_OPCODE_EMIT) { 447 psprite_emit_vertex_inst(ctx, inst); 448 } 449 else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT && 450 inst->Dst[0].Register.Index == (int)ts->point_size_out) { 451 /** 452 * Replace point size output reg with tmp reg. 453 * The tmp reg will be later used as a src reg for computing 454 * the point scale factor. 455 */ 456 inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 457 inst->Dst[0].Register.Index = ts->point_size_tmp; 458 ctx->emit_instruction(ctx, inst); 459 460 /* Clamp the point size */ 461 /* MAX point_size_tmp.x, point_size_tmp.x, point_imm.y */ 462 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MAX, 463 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_WRITEMASK_X, 464 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 465 TGSI_FILE_IMMEDIATE, ts->point_imm, TGSI_SWIZZLE_Y, false); 466 467 /* MIN point_size_tmp.x, point_size_tmp.x, point_ivp.w */ 468 tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MIN, 469 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_WRITEMASK_X, 470 TGSI_FILE_TEMPORARY, ts->point_size_tmp, TGSI_SWIZZLE_X, 471 TGSI_FILE_CONSTANT, ts->point_ivp, TGSI_SWIZZLE_W, false); 472 } 473 else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT && 474 inst->Dst[0].Register.Index == (int)ts->point_pos_out) { 475 /** 476 * Replace point pos output reg with tmp reg. 477 */ 478 inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 479 inst->Dst[0].Register.Index = ts->point_pos_tmp; 480 ctx->emit_instruction(ctx, inst); 481 } 482 else if (inst->Dst[0].Register.File == TGSI_FILE_OUTPUT) { 483 /** 484 * Replace output reg with tmp reg. 485 */ 486 inst->Dst[0].Register.File = TGSI_FILE_TEMPORARY; 487 inst->Dst[0].Register.Index = ts->out_tmp_index[inst->Dst[0].Register.Index]; 488 ctx->emit_instruction(ctx, inst); 489 } 490 else { 491 ctx->emit_instruction(ctx, inst); 492 } 493} 494 495 496/** 497 * TGSI property instruction transform callback. 498 * Transforms a point into a 4-vertex triangle strip. 499 */ 500static void 501psprite_property(struct tgsi_transform_context *ctx, 502 struct tgsi_full_property *prop) 503{ 504 switch (prop->Property.PropertyName) { 505 case TGSI_PROPERTY_GS_OUTPUT_PRIM: 506 prop->u[0].Data = PIPE_PRIM_TRIANGLE_STRIP; 507 break; 508 case TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES: 509 prop->u[0].Data *= 4; 510 break; 511 default: 512 break; 513 } 514 ctx->emit_property(ctx, prop); 515} 516 517/** 518 * TGSI utility to transform a geometry shader to support point sprite. 519 */ 520struct tgsi_token * 521tgsi_add_point_sprite(const struct tgsi_token *tokens_in, 522 const unsigned point_coord_enable, 523 const bool sprite_origin_lower_left, 524 const bool stream_out_point_pos, 525 const bool need_texcoord_semantic, 526 int *aa_point_coord_index) 527{ 528 struct psprite_transform_context transform; 529 const uint num_new_tokens = 200; /* should be enough */ 530 const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens; 531 struct tgsi_token *new_tokens; 532 533 /* setup transformation context */ 534 memset(&transform, 0, sizeof(transform)); 535 transform.base.transform_declaration = psprite_decl; 536 transform.base.transform_instruction = psprite_inst; 537 transform.base.transform_property = psprite_property; 538 transform.base.transform_immediate = psprite_immediate; 539 transform.base.prolog = psprite_prolog; 540 541 transform.point_size_in = INVALID_INDEX; 542 transform.point_size_out = INVALID_INDEX; 543 transform.point_size_tmp = INVALID_INDEX; 544 transform.point_pos_in = INVALID_INDEX; 545 transform.point_pos_out = INVALID_INDEX; 546 transform.point_pos_sout = INVALID_INDEX; 547 transform.point_pos_tmp = INVALID_INDEX; 548 transform.point_scale_tmp = INVALID_INDEX; 549 transform.point_imm = INVALID_INDEX; 550 transform.point_coord_aa = INVALID_INDEX; 551 transform.point_coord_k = INVALID_INDEX; 552 553 transform.stream_out_point_pos = stream_out_point_pos; 554 transform.point_coord_enable = point_coord_enable; 555 transform.aa_point = aa_point_coord_index != NULL; 556 transform.need_texcoord_semantic = need_texcoord_semantic; 557 transform.max_generic = -1; 558 559 /* point sprite directions based on the immediates (0, 1, 0.5, -1) */ 560 /* (-1, -1, 0, 0) */ 561 transform.point_dir_swz[0] = set_swizzle(-1, -1, 0, 0); 562 /* (-1, 1, 0, 0) */ 563 transform.point_dir_swz[1] = set_swizzle(-1, 1, 0, 0); 564 /* (1, -1, 0, 0) */ 565 transform.point_dir_swz[2] = set_swizzle(1, -1, 0, 0); 566 /* (1, 1, 0, 0) */ 567 transform.point_dir_swz[3] = set_swizzle(1, 1, 0, 0); 568 569 /* point coord based on the immediates (0, 1, 0, -1) */ 570 if (sprite_origin_lower_left) { 571 /* (0, 0, 0, 1) */ 572 transform.point_coord_swz[0] = set_swizzle(0, 0, 0, 1); 573 /* (0, 1, 0, 1) */ 574 transform.point_coord_swz[1] = set_swizzle(0, 1, 0, 1); 575 /* (1, 0, 0, 1) */ 576 transform.point_coord_swz[2] = set_swizzle(1, 0, 0, 1); 577 /* (1, 1, 0, 1) */ 578 transform.point_coord_swz[3] = set_swizzle(1, 1, 0, 1); 579 } 580 else { 581 /* (0, 1, 0, 1) */ 582 transform.point_coord_swz[0] = set_swizzle(0, 1, 0, 1); 583 /* (0, 0, 0, 1) */ 584 transform.point_coord_swz[1] = set_swizzle(0, 0, 0, 1); 585 /* (1, 1, 0, 1) */ 586 transform.point_coord_swz[2] = set_swizzle(1, 1, 0, 1); 587 /* (1, 0, 0, 1) */ 588 transform.point_coord_swz[3] = set_swizzle(1, 0, 0, 1); 589 } 590 591 592 new_tokens = tgsi_transform_shader(tokens_in, new_len, &transform.base); 593 594 if (aa_point_coord_index) 595 *aa_point_coord_index = transform.point_coord_aa; 596 597 return new_tokens; 598} 599