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