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