1/**************************************************************************
2 *
3 * Copyright 2008 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28#ifndef TGSI_TRANSFORM_H
29#define TGSI_TRANSFORM_H
30
31
32#include "pipe/p_defines.h"
33#include "pipe/p_shader_tokens.h"
34#include "tgsi/tgsi_parse.h"
35#include "tgsi/tgsi_build.h"
36
37
38
39/**
40 * Subclass this to add caller-specific data
41 */
42struct tgsi_transform_context
43{
44/**** PUBLIC ***/
45
46   /**
47    * User-defined callbacks invoked per instruction.
48    */
49   void (*transform_instruction)(struct tgsi_transform_context *ctx,
50                                 struct tgsi_full_instruction *inst);
51
52   void (*transform_declaration)(struct tgsi_transform_context *ctx,
53                                 struct tgsi_full_declaration *decl);
54
55   void (*transform_immediate)(struct tgsi_transform_context *ctx,
56                               struct tgsi_full_immediate *imm);
57   void (*transform_property)(struct tgsi_transform_context *ctx,
58                              struct tgsi_full_property *prop);
59
60   /**
61    * Called after last declaration, before first instruction.  This is
62    * where the user might insert new declarations and/or instructions.
63    */
64   void (*prolog)(struct tgsi_transform_context *ctx);
65
66   /**
67    * Called at end of input program to allow caller to append extra
68    * instructions.
69    */
70   void (*epilog)(struct tgsi_transform_context *ctx);
71
72   enum pipe_shader_type processor;
73
74/*** PRIVATE ***/
75
76   /**
77    * These are setup by tgsi_transform_shader() and cannot be overridden.
78    * Meant to be called from in the above user callback functions.
79    */
80   void (*emit_instruction)(struct tgsi_transform_context *ctx,
81                            const struct tgsi_full_instruction *inst);
82   void (*emit_declaration)(struct tgsi_transform_context *ctx,
83                            const struct tgsi_full_declaration *decl);
84   void (*emit_immediate)(struct tgsi_transform_context *ctx,
85                          const struct tgsi_full_immediate *imm);
86   void (*emit_property)(struct tgsi_transform_context *ctx,
87                         const struct tgsi_full_property *prop);
88
89   struct tgsi_header *header;
90   uint max_tokens_out;
91   struct tgsi_token *tokens_out;
92   uint ti;
93   bool fail;
94};
95
96
97/**
98 * Helper for emitting temporary register declarations.
99 */
100static inline void
101tgsi_transform_temps_decl(struct tgsi_transform_context *ctx,
102                          unsigned firstIdx, unsigned lastIdx)
103{
104   struct tgsi_full_declaration decl;
105
106   decl = tgsi_default_full_declaration();
107   decl.Declaration.File = TGSI_FILE_TEMPORARY;
108   decl.Range.First = firstIdx;
109   decl.Range.Last = lastIdx;
110   ctx->emit_declaration(ctx, &decl);
111}
112
113static inline void
114tgsi_transform_temp_decl(struct tgsi_transform_context *ctx,
115                         unsigned index)
116{
117   tgsi_transform_temps_decl(ctx, index, index);
118}
119
120static inline void
121tgsi_transform_const_decl(struct tgsi_transform_context *ctx,
122                          unsigned firstIdx, unsigned lastIdx)
123{
124   struct tgsi_full_declaration decl;
125
126   decl = tgsi_default_full_declaration();
127   decl.Declaration.File = TGSI_FILE_CONSTANT;
128   decl.Range.First = firstIdx;
129   decl.Range.Last = lastIdx;
130   decl.Declaration.Dimension = 1;
131   /* Dim.Index2D is already 0 */
132   ctx->emit_declaration(ctx, &decl);
133}
134
135static inline void
136tgsi_transform_input_decl(struct tgsi_transform_context *ctx,
137                          unsigned index,
138                          unsigned sem_name, unsigned sem_index,
139                          unsigned interp)
140{
141   struct tgsi_full_declaration decl;
142
143   decl = tgsi_default_full_declaration();
144   decl.Declaration.File = TGSI_FILE_INPUT;
145   decl.Declaration.Interpolate = 1;
146   decl.Declaration.Semantic = 1;
147   decl.Semantic.Name = sem_name;
148   decl.Semantic.Index = sem_index;
149   decl.Range.First =
150   decl.Range.Last = index;
151   decl.Interp.Interpolate = interp;
152
153   ctx->emit_declaration(ctx, &decl);
154}
155
156static inline void
157tgsi_transform_output_decl(struct tgsi_transform_context *ctx,
158                          unsigned index,
159                          unsigned sem_name, unsigned sem_index,
160                          unsigned interp)
161{
162   struct tgsi_full_declaration decl;
163
164   decl = tgsi_default_full_declaration();
165   decl.Declaration.File = TGSI_FILE_OUTPUT;
166   decl.Declaration.Interpolate = 1;
167   decl.Declaration.Semantic = 1;
168   decl.Semantic.Name = sem_name;
169   decl.Semantic.Index = sem_index;
170   decl.Range.First =
171   decl.Range.Last = index;
172   decl.Interp.Interpolate = interp;
173
174   ctx->emit_declaration(ctx, &decl);
175}
176
177static inline void
178tgsi_transform_sampler_decl(struct tgsi_transform_context *ctx,
179                            unsigned index)
180{
181   struct tgsi_full_declaration decl;
182
183   decl = tgsi_default_full_declaration();
184   decl.Declaration.File = TGSI_FILE_SAMPLER;
185   decl.Range.First =
186   decl.Range.Last = index;
187   ctx->emit_declaration(ctx, &decl);
188}
189
190static inline void
191tgsi_transform_sampler_view_decl(struct tgsi_transform_context *ctx,
192                                 unsigned index,
193                                 unsigned target,
194                                 enum tgsi_return_type type)
195{
196   struct tgsi_full_declaration decl;
197
198   decl = tgsi_default_full_declaration();
199   decl.Declaration.File = TGSI_FILE_SAMPLER_VIEW;
200   decl.Declaration.UsageMask = TGSI_WRITEMASK_XYZW;
201   decl.Range.First =
202   decl.Range.Last = index;
203   decl.SamplerView.Resource = target;
204   decl.SamplerView.ReturnTypeX = type;
205   decl.SamplerView.ReturnTypeY = type;
206   decl.SamplerView.ReturnTypeZ = type;
207   decl.SamplerView.ReturnTypeW = type;
208
209   ctx->emit_declaration(ctx, &decl);
210}
211
212static inline void
213tgsi_transform_immediate_decl(struct tgsi_transform_context *ctx,
214                              float x, float y, float z, float w)
215{
216   struct tgsi_full_immediate immed;
217   unsigned size = 4;
218
219   immed = tgsi_default_full_immediate();
220   immed.Immediate.NrTokens = 1 + size; /* one for the token itself */
221   immed.u[0].Float = x;
222   immed.u[1].Float = y;
223   immed.u[2].Float = z;
224   immed.u[3].Float = w;
225
226   ctx->emit_immediate(ctx, &immed);
227}
228
229static inline void
230tgsi_transform_immediate_int_decl(struct tgsi_transform_context *ctx,
231                                  int x, int y, int z, int w)
232{
233   struct tgsi_full_immediate immed;
234   unsigned size = 4;
235
236   immed = tgsi_default_full_immediate();
237   immed.Immediate.DataType = TGSI_IMM_INT32;
238   immed.Immediate.NrTokens = 1 + size; /* one for the token itself */
239   immed.u[0].Int = x;
240   immed.u[1].Int = y;
241   immed.u[2].Int = z;
242   immed.u[3].Int = w;
243
244   ctx->emit_immediate(ctx, &immed);
245}
246
247static inline void
248tgsi_transform_dst_reg(struct tgsi_full_dst_register *reg,
249                       unsigned file, unsigned index, unsigned writemask)
250{
251   reg->Register.File = file;
252   reg->Register.Index = index;
253   reg->Register.WriteMask = writemask;
254}
255
256static inline void
257tgsi_transform_src_reg_xyzw(struct tgsi_full_src_register *reg,
258                            unsigned file, unsigned index)
259{
260   reg->Register.File = file;
261   reg->Register.Index = index;
262   if (file == TGSI_FILE_CONSTANT) {
263      reg->Register.Dimension = 1;
264      reg->Dimension.Index = 0;
265   }
266}
267
268static inline void
269tgsi_transform_src_reg(struct tgsi_full_src_register *reg,
270                       unsigned file, unsigned index,
271                       unsigned swizzleX, unsigned swizzleY,
272                       unsigned swizzleZ, unsigned swizzleW)
273{
274   reg->Register.File = file;
275   reg->Register.Index = index;
276   if (file == TGSI_FILE_CONSTANT) {
277      reg->Register.Dimension = 1;
278      reg->Dimension.Index = 0;
279   }
280   reg->Register.SwizzleX = swizzleX;
281   reg->Register.SwizzleY = swizzleY;
282   reg->Register.SwizzleZ = swizzleZ;
283   reg->Register.SwizzleW = swizzleW;
284}
285
286/**
287 * Helper for emitting 1-operand instructions.
288 */
289static inline void
290tgsi_transform_op1_inst(struct tgsi_transform_context *ctx,
291                        enum tgsi_opcode opcode,
292                        unsigned dst_file,
293                        unsigned dst_index,
294                        unsigned dst_writemask,
295                        unsigned src0_file,
296                        unsigned src0_index)
297{
298   struct tgsi_full_instruction inst;
299
300   inst = tgsi_default_full_instruction();
301   inst.Instruction.Opcode = opcode;
302   inst.Instruction.NumDstRegs = 1;
303   inst.Dst[0].Register.File = dst_file,
304   inst.Dst[0].Register.Index = dst_index;
305   inst.Dst[0].Register.WriteMask = dst_writemask;
306   inst.Instruction.NumSrcRegs = 1;
307   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
308
309   ctx->emit_instruction(ctx, &inst);
310}
311
312
313static inline void
314tgsi_transform_op2_inst(struct tgsi_transform_context *ctx,
315                        enum tgsi_opcode opcode,
316                        unsigned dst_file,
317                        unsigned dst_index,
318                        unsigned dst_writemask,
319                        unsigned src0_file,
320                        unsigned src0_index,
321                        unsigned src1_file,
322                        unsigned src1_index,
323                        bool src1_negate)
324{
325   struct tgsi_full_instruction inst;
326
327   inst = tgsi_default_full_instruction();
328   inst.Instruction.Opcode = opcode;
329   inst.Instruction.NumDstRegs = 1;
330   inst.Dst[0].Register.File = dst_file,
331   inst.Dst[0].Register.Index = dst_index;
332   inst.Dst[0].Register.WriteMask = dst_writemask;
333   inst.Instruction.NumSrcRegs = 2;
334   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
335   tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
336   inst.Src[1].Register.Negate = src1_negate;
337
338   ctx->emit_instruction(ctx, &inst);
339}
340
341
342static inline void
343tgsi_transform_op3_inst(struct tgsi_transform_context *ctx,
344                        enum tgsi_opcode opcode,
345                        unsigned dst_file,
346                        unsigned dst_index,
347                        unsigned dst_writemask,
348                        unsigned src0_file,
349                        unsigned src0_index,
350                        unsigned src1_file,
351                        unsigned src1_index,
352                        unsigned src2_file,
353                        unsigned src2_index)
354{
355   struct tgsi_full_instruction inst;
356
357   inst = tgsi_default_full_instruction();
358   inst.Instruction.Opcode = opcode;
359   inst.Instruction.NumDstRegs = 1;
360   inst.Dst[0].Register.File = dst_file,
361   inst.Dst[0].Register.Index = dst_index;
362   inst.Dst[0].Register.WriteMask = dst_writemask;
363   inst.Instruction.NumSrcRegs = 3;
364   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
365   tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
366   tgsi_transform_src_reg_xyzw(&inst.Src[2], src2_file, src2_index);
367
368   ctx->emit_instruction(ctx, &inst);
369}
370
371
372
373static inline void
374tgsi_transform_op1_swz_inst(struct tgsi_transform_context *ctx,
375                            enum tgsi_opcode opcode,
376                            unsigned dst_file,
377                            unsigned dst_index,
378                            unsigned dst_writemask,
379                            unsigned src0_file,
380                            unsigned src0_index,
381                            unsigned src0_swizzle)
382{
383   struct tgsi_full_instruction inst;
384
385   inst = tgsi_default_full_instruction();
386   inst.Instruction.Opcode = opcode;
387   inst.Instruction.NumDstRegs = 1;
388   inst.Dst[0].Register.File = dst_file,
389   inst.Dst[0].Register.Index = dst_index;
390   inst.Dst[0].Register.WriteMask = dst_writemask;
391   inst.Instruction.NumSrcRegs = 1;
392   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
393   switch (dst_writemask) {
394   case TGSI_WRITEMASK_X:
395      inst.Src[0].Register.SwizzleX = src0_swizzle;
396      break;
397   case TGSI_WRITEMASK_Y:
398      inst.Src[0].Register.SwizzleY = src0_swizzle;
399      break;
400   case TGSI_WRITEMASK_Z:
401      inst.Src[0].Register.SwizzleZ = src0_swizzle;
402      break;
403   case TGSI_WRITEMASK_W:
404      inst.Src[0].Register.SwizzleW = src0_swizzle;
405      break;
406   default:
407      ; /* nothing */
408   }
409
410   ctx->emit_instruction(ctx, &inst);
411}
412
413
414static inline void
415tgsi_transform_op2_swz_inst(struct tgsi_transform_context *ctx,
416                            enum tgsi_opcode opcode,
417                            unsigned dst_file,
418                            unsigned dst_index,
419                            unsigned dst_writemask,
420                            unsigned src0_file,
421                            unsigned src0_index,
422                            unsigned src0_swizzle,
423                            unsigned src1_file,
424                            unsigned src1_index,
425                            unsigned src1_swizzle,
426                            bool src1_negate)
427{
428   struct tgsi_full_instruction inst;
429
430   inst = tgsi_default_full_instruction();
431   inst.Instruction.Opcode = opcode;
432   inst.Instruction.NumDstRegs = 1;
433   inst.Dst[0].Register.File = dst_file,
434   inst.Dst[0].Register.Index = dst_index;
435   inst.Dst[0].Register.WriteMask = dst_writemask;
436   inst.Instruction.NumSrcRegs = 2;
437   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
438   tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
439   inst.Src[1].Register.Negate = src1_negate;
440   switch (dst_writemask) {
441   case TGSI_WRITEMASK_X:
442      inst.Src[0].Register.SwizzleX = src0_swizzle;
443      inst.Src[1].Register.SwizzleX = src1_swizzle;
444      break;
445   case TGSI_WRITEMASK_Y:
446      inst.Src[0].Register.SwizzleY = src0_swizzle;
447      inst.Src[1].Register.SwizzleY = src1_swizzle;
448      break;
449   case TGSI_WRITEMASK_Z:
450      inst.Src[0].Register.SwizzleZ = src0_swizzle;
451      inst.Src[1].Register.SwizzleZ = src1_swizzle;
452      break;
453   case TGSI_WRITEMASK_W:
454      inst.Src[0].Register.SwizzleW = src0_swizzle;
455      inst.Src[1].Register.SwizzleW = src1_swizzle;
456      break;
457   default:
458      ; /* nothing */
459   }
460
461   ctx->emit_instruction(ctx, &inst);
462}
463
464
465static inline void
466tgsi_transform_op3_swz_inst(struct tgsi_transform_context *ctx,
467                            enum tgsi_opcode opcode,
468                            unsigned dst_file,
469                            unsigned dst_index,
470                            unsigned dst_writemask,
471                            unsigned src0_file,
472                            unsigned src0_index,
473                            unsigned src0_swizzle,
474                            unsigned src0_negate,
475                            unsigned src1_file,
476                            unsigned src1_index,
477                            unsigned src1_swizzle,
478                            unsigned src2_file,
479                            unsigned src2_index,
480                            unsigned src2_swizzle)
481{
482   struct tgsi_full_instruction inst;
483
484   inst = tgsi_default_full_instruction();
485   inst.Instruction.Opcode = opcode;
486   inst.Instruction.NumDstRegs = 1;
487   inst.Dst[0].Register.File = dst_file,
488   inst.Dst[0].Register.Index = dst_index;
489   inst.Dst[0].Register.WriteMask = dst_writemask;
490   inst.Instruction.NumSrcRegs = 3;
491   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
492   inst.Src[0].Register.Negate = src0_negate;
493   tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
494   tgsi_transform_src_reg_xyzw(&inst.Src[2], src2_file, src2_index);
495   switch (dst_writemask) {
496   case TGSI_WRITEMASK_X:
497      inst.Src[0].Register.SwizzleX = src0_swizzle;
498      inst.Src[1].Register.SwizzleX = src1_swizzle;
499      inst.Src[2].Register.SwizzleX = src2_swizzle;
500      break;
501   case TGSI_WRITEMASK_Y:
502      inst.Src[0].Register.SwizzleY = src0_swizzle;
503      inst.Src[1].Register.SwizzleY = src1_swizzle;
504      inst.Src[2].Register.SwizzleY = src2_swizzle;
505      break;
506   case TGSI_WRITEMASK_Z:
507      inst.Src[0].Register.SwizzleZ = src0_swizzle;
508      inst.Src[1].Register.SwizzleZ = src1_swizzle;
509      inst.Src[2].Register.SwizzleZ = src2_swizzle;
510      break;
511   case TGSI_WRITEMASK_W:
512      inst.Src[0].Register.SwizzleW = src0_swizzle;
513      inst.Src[1].Register.SwizzleW = src1_swizzle;
514      inst.Src[2].Register.SwizzleW = src2_swizzle;
515      break;
516   default:
517      ; /* nothing */
518   }
519
520   ctx->emit_instruction(ctx, &inst);
521}
522
523
524static inline void
525tgsi_transform_kill_inst(struct tgsi_transform_context *ctx,
526                         unsigned src_file,
527                         unsigned src_index,
528                         unsigned src_swizzle,
529                         boolean negate)
530{
531   struct tgsi_full_instruction inst;
532
533   inst = tgsi_default_full_instruction();
534   inst.Instruction.Opcode = TGSI_OPCODE_KILL_IF;
535   inst.Instruction.NumDstRegs = 0;
536   inst.Instruction.NumSrcRegs = 1;
537   tgsi_transform_src_reg_xyzw(&inst.Src[0], src_file, src_index);
538   inst.Src[0].Register.SwizzleX =
539   inst.Src[0].Register.SwizzleY =
540   inst.Src[0].Register.SwizzleZ =
541   inst.Src[0].Register.SwizzleW = src_swizzle;
542   inst.Src[0].Register.Negate = negate;
543
544   ctx->emit_instruction(ctx, &inst);
545}
546
547
548static inline void
549tgsi_transform_tex_inst(struct tgsi_transform_context *ctx,
550                        unsigned dst_file,
551                        unsigned dst_index,
552                        unsigned src_file,
553                        unsigned src_index,
554                        unsigned tex_target,
555                        unsigned sampler_index)
556{
557   struct tgsi_full_instruction inst;
558
559   assert(tex_target < TGSI_TEXTURE_COUNT);
560
561   inst = tgsi_default_full_instruction();
562   inst.Instruction.Opcode = TGSI_OPCODE_TEX;
563   inst.Instruction.NumDstRegs = 1;
564   inst.Dst[0].Register.File = dst_file;
565   inst.Dst[0].Register.Index = dst_index;
566   inst.Instruction.NumSrcRegs = 2;
567   inst.Instruction.Texture = TRUE;
568   inst.Texture.Texture = tex_target;
569   tgsi_transform_src_reg_xyzw(&inst.Src[0], src_file, src_index);
570   tgsi_transform_src_reg_xyzw(&inst.Src[1], TGSI_FILE_SAMPLER, sampler_index);
571
572   ctx->emit_instruction(ctx, &inst);
573}
574
575
576extern struct tgsi_token *
577tgsi_transform_shader(const struct tgsi_token *tokens_in,
578                      uint initial_tokens_len,
579                      struct tgsi_transform_context *ctx);
580
581
582#endif /* TGSI_TRANSFORM_H */
583