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 */
42 struct 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 unsigned max_tokens_out;
91 struct tgsi_token *tokens_out;
92 unsigned ti;
93 bool fail;
94 };
95
96
97 /**
98 * Helper for emitting temporary register declarations.
99 */
100 static inline void
tgsi_transform_temps_decl(struct tgsi_transform_context * ctx,unsigned firstIdx,unsigned lastIdx)101 tgsi_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
113 static inline void
tgsi_transform_temp_decl(struct tgsi_transform_context * ctx,unsigned index)114 tgsi_transform_temp_decl(struct tgsi_transform_context *ctx,
115 unsigned index)
116 {
117 tgsi_transform_temps_decl(ctx, index, index);
118 }
119
120 static inline void
tgsi_transform_const_decl(struct tgsi_transform_context * ctx,unsigned firstIdx,unsigned lastIdx)121 tgsi_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
135 static inline void
tgsi_transform_input_decl(struct tgsi_transform_context * ctx,unsigned index,unsigned sem_name,unsigned sem_index,unsigned interp)136 tgsi_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
156 static inline void
tgsi_transform_output_decl(struct tgsi_transform_context * ctx,unsigned index,unsigned sem_name,unsigned sem_index,unsigned interp)157 tgsi_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
177 static inline void
tgsi_transform_sampler_decl(struct tgsi_transform_context * ctx,unsigned index)178 tgsi_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
190 static inline void
tgsi_transform_sampler_view_decl(struct tgsi_transform_context * ctx,unsigned index,unsigned target,enum tgsi_return_type type)191 tgsi_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
212 static inline void
tgsi_transform_immediate_decl(struct tgsi_transform_context * ctx,float x,float y,float z,float w)213 tgsi_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
229 static inline void
tgsi_transform_immediate_int_decl(struct tgsi_transform_context * ctx,int x,int y,int z,int w)230 tgsi_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
247 static inline void
tgsi_transform_dst_reg(struct tgsi_full_dst_register * reg,unsigned file,unsigned index,unsigned writemask)248 tgsi_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
256 static inline void
tgsi_transform_src_reg_xyzw(struct tgsi_full_src_register * reg,unsigned file,unsigned index)257 tgsi_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
268 static inline void
tgsi_transform_src_reg(struct tgsi_full_src_register * reg,unsigned file,unsigned index,unsigned swizzleX,unsigned swizzleY,unsigned swizzleZ,unsigned swizzleW)269 tgsi_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 */
289 static inline void
tgsi_transform_op1_inst(struct tgsi_transform_context * ctx,enum tgsi_opcode opcode,unsigned dst_file,unsigned dst_index,unsigned dst_writemask,unsigned src0_file,unsigned src0_index)290 tgsi_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
313 static inline void
tgsi_transform_op2_inst(struct tgsi_transform_context * ctx,enum tgsi_opcode opcode,unsigned dst_file,unsigned dst_index,unsigned dst_writemask,unsigned src0_file,unsigned src0_index,unsigned src1_file,unsigned src1_index,bool src1_negate)314 tgsi_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
342 static inline void
tgsi_transform_op1_swz_inst(struct tgsi_transform_context * ctx,enum tgsi_opcode opcode,unsigned dst_file,unsigned dst_index,unsigned dst_writemask,unsigned src0_file,unsigned src0_index,unsigned src0_swizzle)343 tgsi_transform_op1_swz_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 src0_swizzle)
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 = 1;
361 tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
362 switch (dst_writemask) {
363 case TGSI_WRITEMASK_X:
364 inst.Src[0].Register.SwizzleX = src0_swizzle;
365 break;
366 case TGSI_WRITEMASK_Y:
367 inst.Src[0].Register.SwizzleY = src0_swizzle;
368 break;
369 case TGSI_WRITEMASK_Z:
370 inst.Src[0].Register.SwizzleZ = src0_swizzle;
371 break;
372 case TGSI_WRITEMASK_W:
373 inst.Src[0].Register.SwizzleW = src0_swizzle;
374 break;
375 default:
376 ; /* nothing */
377 }
378
379 ctx->emit_instruction(ctx, &inst);
380 }
381
382
383 static inline void
tgsi_transform_op2_swz_inst(struct tgsi_transform_context * ctx,enum tgsi_opcode opcode,unsigned dst_file,unsigned dst_index,unsigned dst_writemask,unsigned src0_file,unsigned src0_index,unsigned src0_swizzle,unsigned src1_file,unsigned src1_index,unsigned src1_swizzle,bool src1_negate)384 tgsi_transform_op2_swz_inst(struct tgsi_transform_context *ctx,
385 enum tgsi_opcode opcode,
386 unsigned dst_file,
387 unsigned dst_index,
388 unsigned dst_writemask,
389 unsigned src0_file,
390 unsigned src0_index,
391 unsigned src0_swizzle,
392 unsigned src1_file,
393 unsigned src1_index,
394 unsigned src1_swizzle,
395 bool src1_negate)
396 {
397 struct tgsi_full_instruction inst;
398
399 inst = tgsi_default_full_instruction();
400 inst.Instruction.Opcode = opcode;
401 inst.Instruction.NumDstRegs = 1;
402 inst.Dst[0].Register.File = dst_file,
403 inst.Dst[0].Register.Index = dst_index;
404 inst.Dst[0].Register.WriteMask = dst_writemask;
405 inst.Instruction.NumSrcRegs = 2;
406 tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
407 tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
408 inst.Src[1].Register.Negate = src1_negate;
409 switch (dst_writemask) {
410 case TGSI_WRITEMASK_X:
411 inst.Src[0].Register.SwizzleX = src0_swizzle;
412 inst.Src[1].Register.SwizzleX = src1_swizzle;
413 break;
414 case TGSI_WRITEMASK_Y:
415 inst.Src[0].Register.SwizzleY = src0_swizzle;
416 inst.Src[1].Register.SwizzleY = src1_swizzle;
417 break;
418 case TGSI_WRITEMASK_Z:
419 inst.Src[0].Register.SwizzleZ = src0_swizzle;
420 inst.Src[1].Register.SwizzleZ = src1_swizzle;
421 break;
422 case TGSI_WRITEMASK_W:
423 inst.Src[0].Register.SwizzleW = src0_swizzle;
424 inst.Src[1].Register.SwizzleW = src1_swizzle;
425 break;
426 default:
427 ; /* nothing */
428 }
429
430 ctx->emit_instruction(ctx, &inst);
431 }
432
433
434 static inline void
tgsi_transform_op3_swz_inst(struct tgsi_transform_context * ctx,enum tgsi_opcode opcode,unsigned dst_file,unsigned dst_index,unsigned dst_writemask,unsigned src0_file,unsigned src0_index,unsigned src0_swizzle,unsigned src0_negate,unsigned src1_file,unsigned src1_index,unsigned src1_swizzle,unsigned src2_file,unsigned src2_index,unsigned src2_swizzle)435 tgsi_transform_op3_swz_inst(struct tgsi_transform_context *ctx,
436 enum tgsi_opcode opcode,
437 unsigned dst_file,
438 unsigned dst_index,
439 unsigned dst_writemask,
440 unsigned src0_file,
441 unsigned src0_index,
442 unsigned src0_swizzle,
443 unsigned src0_negate,
444 unsigned src1_file,
445 unsigned src1_index,
446 unsigned src1_swizzle,
447 unsigned src2_file,
448 unsigned src2_index,
449 unsigned src2_swizzle)
450 {
451 struct tgsi_full_instruction inst;
452
453 inst = tgsi_default_full_instruction();
454 inst.Instruction.Opcode = opcode;
455 inst.Instruction.NumDstRegs = 1;
456 inst.Dst[0].Register.File = dst_file,
457 inst.Dst[0].Register.Index = dst_index;
458 inst.Dst[0].Register.WriteMask = dst_writemask;
459 inst.Instruction.NumSrcRegs = 3;
460 tgsi_transform_src_reg_xyzw(&inst.Src[0], src0_file, src0_index);
461 inst.Src[0].Register.Negate = src0_negate;
462 tgsi_transform_src_reg_xyzw(&inst.Src[1], src1_file, src1_index);
463 tgsi_transform_src_reg_xyzw(&inst.Src[2], src2_file, src2_index);
464 switch (dst_writemask) {
465 case TGSI_WRITEMASK_X:
466 inst.Src[0].Register.SwizzleX = src0_swizzle;
467 inst.Src[1].Register.SwizzleX = src1_swizzle;
468 inst.Src[2].Register.SwizzleX = src2_swizzle;
469 break;
470 case TGSI_WRITEMASK_Y:
471 inst.Src[0].Register.SwizzleY = src0_swizzle;
472 inst.Src[1].Register.SwizzleY = src1_swizzle;
473 inst.Src[2].Register.SwizzleY = src2_swizzle;
474 break;
475 case TGSI_WRITEMASK_Z:
476 inst.Src[0].Register.SwizzleZ = src0_swizzle;
477 inst.Src[1].Register.SwizzleZ = src1_swizzle;
478 inst.Src[2].Register.SwizzleZ = src2_swizzle;
479 break;
480 case TGSI_WRITEMASK_W:
481 inst.Src[0].Register.SwizzleW = src0_swizzle;
482 inst.Src[1].Register.SwizzleW = src1_swizzle;
483 inst.Src[2].Register.SwizzleW = src2_swizzle;
484 break;
485 default:
486 ; /* nothing */
487 }
488
489 ctx->emit_instruction(ctx, &inst);
490 }
491
492
493 static inline void
tgsi_transform_kill_inst(struct tgsi_transform_context * ctx,unsigned src_file,unsigned src_index,unsigned src_swizzle,bool negate)494 tgsi_transform_kill_inst(struct tgsi_transform_context *ctx,
495 unsigned src_file,
496 unsigned src_index,
497 unsigned src_swizzle,
498 bool negate)
499 {
500 struct tgsi_full_instruction inst;
501
502 inst = tgsi_default_full_instruction();
503 inst.Instruction.Opcode = TGSI_OPCODE_KILL_IF;
504 inst.Instruction.NumDstRegs = 0;
505 inst.Instruction.NumSrcRegs = 1;
506 tgsi_transform_src_reg_xyzw(&inst.Src[0], src_file, src_index);
507 inst.Src[0].Register.SwizzleX =
508 inst.Src[0].Register.SwizzleY =
509 inst.Src[0].Register.SwizzleZ =
510 inst.Src[0].Register.SwizzleW = src_swizzle;
511 inst.Src[0].Register.Negate = negate;
512
513 ctx->emit_instruction(ctx, &inst);
514 }
515
516
517 static inline void
tgsi_transform_tex_inst(struct tgsi_transform_context * ctx,unsigned dst_file,unsigned dst_index,unsigned src_file,unsigned src_index,unsigned tex_target,unsigned sampler_index)518 tgsi_transform_tex_inst(struct tgsi_transform_context *ctx,
519 unsigned dst_file,
520 unsigned dst_index,
521 unsigned src_file,
522 unsigned src_index,
523 unsigned tex_target,
524 unsigned sampler_index)
525 {
526 struct tgsi_full_instruction inst;
527
528 assert(tex_target < TGSI_TEXTURE_COUNT);
529
530 inst = tgsi_default_full_instruction();
531 inst.Instruction.Opcode = TGSI_OPCODE_TEX;
532 inst.Instruction.NumDstRegs = 1;
533 inst.Dst[0].Register.File = dst_file;
534 inst.Dst[0].Register.Index = dst_index;
535 inst.Instruction.NumSrcRegs = 2;
536 inst.Instruction.Texture = true;
537 inst.Texture.Texture = tex_target;
538 tgsi_transform_src_reg_xyzw(&inst.Src[0], src_file, src_index);
539 tgsi_transform_src_reg_xyzw(&inst.Src[1], TGSI_FILE_SAMPLER, sampler_index);
540
541 ctx->emit_instruction(ctx, &inst);
542 }
543
544
545 extern struct tgsi_token *
546 tgsi_transform_shader(const struct tgsi_token *tokens_in,
547 unsigned initial_tokens_len,
548 struct tgsi_transform_context *ctx);
549
550
551 #endif /* TGSI_TRANSFORM_H */
552