• 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 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 
103 static inline struct psprite_transform_context *
psprite_transform_context(struct tgsi_transform_context * ctx)104 psprite_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  */
113 static void
psprite_decl(struct tgsi_transform_context * ctx,struct tgsi_full_declaration * decl)114 psprite_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  */
160 static void
psprite_immediate(struct tgsi_transform_context * ctx,struct tgsi_full_immediate * imm)161 psprite_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  */
174 static void
psprite_prolog(struct tgsi_transform_context * ctx)175 psprite_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  */
289 static void
psprite_emit_vertex_inst(struct tgsi_transform_context * ctx,struct tgsi_full_instruction * vert_inst)290 psprite_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  */
440 static void
psprite_inst(struct tgsi_transform_context * ctx,struct tgsi_full_instruction * inst)441 psprite_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  */
500 static void
psprite_property(struct tgsi_transform_context * ctx,struct tgsi_full_property * prop)501 psprite_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  */
520 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,const bool need_texcoord_semantic,int * aa_point_coord_index)521 tgsi_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