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_immediate_int_decl(struct tgsi_transform_context *ctx,
228                                  int x, int y, int z, int w)
229{
230   struct tgsi_full_immediate immed;
231   unsigned size = 4;
232
233   immed = tgsi_default_full_immediate();
234   immed.Immediate.DataType = TGSI_IMM_INT32;
235   immed.Immediate.NrTokens = 1 + size; /* one for the token itself */
236   immed.u[0].Int = x;
237   immed.u[1].Int = y;
238   immed.u[2].Int = z;
239   immed.u[3].Int = w;
240
241   ctx->emit_immediate(ctx, &immed);
242}
243
244static inline void
245tgsi_transform_dst_reg(struct tgsi_full_dst_register *reg,
246                       unsigned file, unsigned index, unsigned writemask)
247{
248   reg->Register.File = file;
249   reg->Register.Index = index;
250   reg->Register.WriteMask = writemask;
251}
252
253static inline void
254tgsi_transform_src_reg_xyzw(struct tgsi_full_src_register *reg,
255                            unsigned file, unsigned index)
256{
257   reg->Register.File = file;
258   reg->Register.Index = index;
259   if (file == TGSI_FILE_CONSTANT) {
260      reg->Register.Dimension = 1;
261      reg->Dimension.Index = 0;
262   }
263}
264
265static inline void
266tgsi_transform_src_reg(struct tgsi_full_src_register *reg,
267                       unsigned file, unsigned index,
268                       unsigned swizzleX, unsigned swizzleY,
269                       unsigned swizzleZ, unsigned swizzleW)
270{
271   reg->Register.File = file;
272   reg->Register.Index = index;
273   if (file == TGSI_FILE_CONSTANT) {
274      reg->Register.Dimension = 1;
275      reg->Dimension.Index = 0;
276   }
277   reg->Register.SwizzleX = swizzleX;
278   reg->Register.SwizzleY = swizzleY;
279   reg->Register.SwizzleZ = swizzleZ;
280   reg->Register.SwizzleW = swizzleW;
281}
282
283/**
284 * Helper for emitting 1-operand instructions.
285 */
286static inline void
287tgsi_transform_op1_inst(struct tgsi_transform_context *ctx,
288                        enum tgsi_opcode opcode,
289                        unsigned dst_file,
290                        unsigned dst_index,
291                        unsigned dst_writemask,
292                        unsigned src0_file,
293                        unsigned src0_index)
294{
295   struct tgsi_full_instruction inst;
296
297   inst = tgsi_default_full_instruction();
298   inst.Instruction.Opcode = opcode;
299   inst.Instruction.NumDstRegs = 1;
300   inst.Dst[0].Register.File = dst_file,
301   inst.Dst[0].Register.Index = dst_index;
302   inst.Dst[0].Register.WriteMask = dst_writemask;
303   inst.Instruction.NumSrcRegs = 1;
304   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
305
306   ctx->emit_instruction(ctx, &inst);
307}
308
309
310static inline void
311tgsi_transform_op2_inst(struct tgsi_transform_context *ctx,
312                        enum tgsi_opcode opcode,
313                        unsigned dst_file,
314                        unsigned dst_index,
315                        unsigned dst_writemask,
316                        unsigned src0_file,
317                        unsigned src0_index,
318                        unsigned src1_file,
319                        unsigned src1_index,
320                        bool src1_negate)
321{
322   struct tgsi_full_instruction inst;
323
324   inst = tgsi_default_full_instruction();
325   inst.Instruction.Opcode = opcode;
326   inst.Instruction.NumDstRegs = 1;
327   inst.Dst[0].Register.File = dst_file,
328   inst.Dst[0].Register.Index = dst_index;
329   inst.Dst[0].Register.WriteMask = dst_writemask;
330   inst.Instruction.NumSrcRegs = 2;
331   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
332   tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
333   inst.Src[1].Register.Negate = src1_negate;
334
335   ctx->emit_instruction(ctx, &inst);
336}
337
338
339static inline void
340tgsi_transform_op3_inst(struct tgsi_transform_context *ctx,
341                        enum tgsi_opcode opcode,
342                        unsigned dst_file,
343                        unsigned dst_index,
344                        unsigned dst_writemask,
345                        unsigned src0_file,
346                        unsigned src0_index,
347                        unsigned src1_file,
348                        unsigned src1_index,
349                        unsigned src2_file,
350                        unsigned src2_index)
351{
352   struct tgsi_full_instruction inst;
353
354   inst = tgsi_default_full_instruction();
355   inst.Instruction.Opcode = opcode;
356   inst.Instruction.NumDstRegs = 1;
357   inst.Dst[0].Register.File = dst_file,
358   inst.Dst[0].Register.Index = dst_index;
359   inst.Dst[0].Register.WriteMask = dst_writemask;
360   inst.Instruction.NumSrcRegs = 3;
361   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
362   tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
363   tgsi_transform_src_reg_xyzw(&inst.Src[2], src2_file, src2_index);
364
365   ctx->emit_instruction(ctx, &inst);
366}
367
368
369
370static inline void
371tgsi_transform_op1_swz_inst(struct tgsi_transform_context *ctx,
372                            enum tgsi_opcode opcode,
373                            unsigned dst_file,
374                            unsigned dst_index,
375                            unsigned dst_writemask,
376                            unsigned src0_file,
377                            unsigned src0_index,
378                            unsigned src0_swizzle)
379{
380   struct tgsi_full_instruction inst;
381
382   inst = tgsi_default_full_instruction();
383   inst.Instruction.Opcode = opcode;
384   inst.Instruction.NumDstRegs = 1;
385   inst.Dst[0].Register.File = dst_file,
386   inst.Dst[0].Register.Index = dst_index;
387   inst.Dst[0].Register.WriteMask = dst_writemask;
388   inst.Instruction.NumSrcRegs = 1;
389   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
390   switch (dst_writemask) {
391   case TGSI_WRITEMASK_X:
392      inst.Src[0].Register.SwizzleX = src0_swizzle;
393      break;
394   case TGSI_WRITEMASK_Y:
395      inst.Src[0].Register.SwizzleY = src0_swizzle;
396      break;
397   case TGSI_WRITEMASK_Z:
398      inst.Src[0].Register.SwizzleZ = src0_swizzle;
399      break;
400   case TGSI_WRITEMASK_W:
401      inst.Src[0].Register.SwizzleW = src0_swizzle;
402      break;
403   default:
404      ; /* nothing */
405   }
406
407   ctx->emit_instruction(ctx, &inst);
408}
409
410
411static inline void
412tgsi_transform_op2_swz_inst(struct tgsi_transform_context *ctx,
413                            enum tgsi_opcode opcode,
414                            unsigned dst_file,
415                            unsigned dst_index,
416                            unsigned dst_writemask,
417                            unsigned src0_file,
418                            unsigned src0_index,
419                            unsigned src0_swizzle,
420                            unsigned src1_file,
421                            unsigned src1_index,
422                            unsigned src1_swizzle,
423                            bool src1_negate)
424{
425   struct tgsi_full_instruction inst;
426
427   inst = tgsi_default_full_instruction();
428   inst.Instruction.Opcode = opcode;
429   inst.Instruction.NumDstRegs = 1;
430   inst.Dst[0].Register.File = dst_file,
431   inst.Dst[0].Register.Index = dst_index;
432   inst.Dst[0].Register.WriteMask = dst_writemask;
433   inst.Instruction.NumSrcRegs = 2;
434   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
435   tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
436   inst.Src[1].Register.Negate = src1_negate;
437   switch (dst_writemask) {
438   case TGSI_WRITEMASK_X:
439      inst.Src[0].Register.SwizzleX = src0_swizzle;
440      inst.Src[1].Register.SwizzleX = src1_swizzle;
441      break;
442   case TGSI_WRITEMASK_Y:
443      inst.Src[0].Register.SwizzleY = src0_swizzle;
444      inst.Src[1].Register.SwizzleY = src1_swizzle;
445      break;
446   case TGSI_WRITEMASK_Z:
447      inst.Src[0].Register.SwizzleZ = src0_swizzle;
448      inst.Src[1].Register.SwizzleZ = src1_swizzle;
449      break;
450   case TGSI_WRITEMASK_W:
451      inst.Src[0].Register.SwizzleW = src0_swizzle;
452      inst.Src[1].Register.SwizzleW = src1_swizzle;
453      break;
454   default:
455      ; /* nothing */
456   }
457
458   ctx->emit_instruction(ctx, &inst);
459}
460
461
462static inline void
463tgsi_transform_op3_swz_inst(struct tgsi_transform_context *ctx,
464                            enum tgsi_opcode opcode,
465                            unsigned dst_file,
466                            unsigned dst_index,
467                            unsigned dst_writemask,
468                            unsigned src0_file,
469                            unsigned src0_index,
470                            unsigned src0_swizzle,
471                            unsigned src0_negate,
472                            unsigned src1_file,
473                            unsigned src1_index,
474                            unsigned src1_swizzle,
475                            unsigned src2_file,
476                            unsigned src2_index,
477                            unsigned src2_swizzle)
478{
479   struct tgsi_full_instruction inst;
480
481   inst = tgsi_default_full_instruction();
482   inst.Instruction.Opcode = opcode;
483   inst.Instruction.NumDstRegs = 1;
484   inst.Dst[0].Register.File = dst_file,
485   inst.Dst[0].Register.Index = dst_index;
486   inst.Dst[0].Register.WriteMask = dst_writemask;
487   inst.Instruction.NumSrcRegs = 3;
488   tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
489   inst.Src[0].Register.Negate = src0_negate;
490   tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
491   tgsi_transform_src_reg_xyzw(&inst.Src[2], src2_file, src2_index);
492   switch (dst_writemask) {
493   case TGSI_WRITEMASK_X:
494      inst.Src[0].Register.SwizzleX = src0_swizzle;
495      inst.Src[1].Register.SwizzleX = src1_swizzle;
496      inst.Src[2].Register.SwizzleX = src2_swizzle;
497      break;
498   case TGSI_WRITEMASK_Y:
499      inst.Src[0].Register.SwizzleY = src0_swizzle;
500      inst.Src[1].Register.SwizzleY = src1_swizzle;
501      inst.Src[2].Register.SwizzleY = src2_swizzle;
502      break;
503   case TGSI_WRITEMASK_Z:
504      inst.Src[0].Register.SwizzleZ = src0_swizzle;
505      inst.Src[1].Register.SwizzleZ = src1_swizzle;
506      inst.Src[2].Register.SwizzleZ = src2_swizzle;
507      break;
508   case TGSI_WRITEMASK_W:
509      inst.Src[0].Register.SwizzleW = src0_swizzle;
510      inst.Src[1].Register.SwizzleW = src1_swizzle;
511      inst.Src[2].Register.SwizzleW = src2_swizzle;
512      break;
513   default:
514      ; /* nothing */
515   }
516
517   ctx->emit_instruction(ctx, &inst);
518}
519
520
521static inline void
522tgsi_transform_kill_inst(struct tgsi_transform_context *ctx,
523                         unsigned src_file,
524                         unsigned src_index,
525                         unsigned src_swizzle,
526                         boolean negate)
527{
528   struct tgsi_full_instruction inst;
529
530   inst = tgsi_default_full_instruction();
531   inst.Instruction.Opcode = TGSI_OPCODE_KILL_IF;
532   inst.Instruction.NumDstRegs = 0;
533   inst.Instruction.NumSrcRegs = 1;
534   tgsi_transform_src_reg_xyzw(&inst.Src[0], src_file, src_index);
535   inst.Src[0].Register.SwizzleX =
536   inst.Src[0].Register.SwizzleY =
537   inst.Src[0].Register.SwizzleZ =
538   inst.Src[0].Register.SwizzleW = src_swizzle;
539   inst.Src[0].Register.Negate = negate;
540
541   ctx->emit_instruction(ctx, &inst);
542}
543
544
545static inline void
546tgsi_transform_tex_inst(struct tgsi_transform_context *ctx,
547                        unsigned dst_file,
548                        unsigned dst_index,
549                        unsigned src_file,
550                        unsigned src_index,
551                        unsigned tex_target,
552                        unsigned sampler_index)
553{
554   struct tgsi_full_instruction inst;
555
556   assert(tex_target < TGSI_TEXTURE_COUNT);
557
558   inst = tgsi_default_full_instruction();
559   inst.Instruction.Opcode = TGSI_OPCODE_TEX;
560   inst.Instruction.NumDstRegs = 1;
561   inst.Dst[0].Register.File = dst_file;
562   inst.Dst[0].Register.Index = dst_index;
563   inst.Instruction.NumSrcRegs = 2;
564   inst.Instruction.Texture = TRUE;
565   inst.Texture.Texture = tex_target;
566   tgsi_transform_src_reg_xyzw(&inst.Src[0], src_file, src_index);
567   tgsi_transform_src_reg_xyzw(&inst.Src[1], TGSI_FILE_SAMPLER, sampler_index);
568
569   ctx->emit_instruction(ctx, &inst);
570}
571
572
573extern int
574tgsi_transform_shader(const struct tgsi_token *tokens_in,
575                      struct tgsi_token *tokens_out,
576                      uint max_tokens_out,
577                      struct tgsi_transform_context *ctx);
578
579
580#endif /* TGSI_TRANSFORM_H */
581