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