• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
set_swizzle(int x,int y,int z,int w)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
get_swizzle(unsigned swizzle,unsigned component)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 *
psprite_transform_context(struct tgsi_transform_context * ctx)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
psprite_decl(struct tgsi_transform_context * ctx,struct tgsi_full_declaration * decl)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
psprite_immediate(struct tgsi_transform_context * ctx,struct tgsi_full_immediate * imm)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
psprite_prolog(struct tgsi_transform_context * ctx)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
psprite_emit_vertex_inst(struct tgsi_transform_context * ctx,struct tgsi_full_instruction * vert_inst)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
psprite_inst(struct tgsi_transform_context * ctx,struct tgsi_full_instruction * inst)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
psprite_property(struct tgsi_transform_context * ctx,struct tgsi_full_property * prop)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 *
tgsi_add_point_sprite(const struct tgsi_token * tokens_in,const unsigned point_coord_enable,const bool sprite_origin_lower_left,const bool stream_out_point_pos,int * aa_point_coord_index)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