/
mojoshader.c
7798 lines (6596 loc) · 252 KB
1
/**
2
3
* MojoShader; generate shader programs from bytecode of compiled
* Direct3D shaders.
4
5
6
7
8
9
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
10
// !!! FIXME: this file really needs to be split up.
11
12
// !!! FIXME: I keep changing coding styles for symbols and typedefs.
13
14
#define __MOJOSHADER_INTERNAL__ 1
#include "mojoshader_internal.h"
15
16
17
18
// A simple linked list of strings, so we can build the final output without
// realloc()ing for each new line, and easily insert lines into the middle
// of the output without much trouble.
19
typedef struct OutputListNode
20
21
{
char *str;
22
23
24
25
26
27
28
struct OutputListNode *next;
} OutputListNode;
typedef struct OutputList
{
OutputListNode head;
OutputListNode *tail;
29
30
} OutputList;
31
32
33
34
35
36
typedef struct ConstantsList
{
MOJOSHADER_constant constant;
struct ConstantsList *next;
} ConstantsList;
37
38
39
40
41
typedef struct VariableList
{
MOJOSHADER_uniformType type;
int index;
int count;
42
ConstantsList *constant;
43
int used;
44
int emit_position; // used in some profiles.
45
46
struct VariableList *next;
} VariableList;
47
48
49
50
51
typedef struct RegisterList
{
RegisterType regtype;
int regnum;
52
53
54
MOJOSHADER_usage usage;
int index;
int writemask;
55
int misc;
56
const VariableList *array;
57
58
59
struct RegisterList *next;
} RegisterList;
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
typedef struct
{
const uint32 *token; // this is the unmolested token in the stream.
int regnum;
int swizzle; // xyzw (all four, not split out).
int swizzle_x;
int swizzle_y;
int swizzle_z;
int swizzle_w;
SourceMod src_mod;
RegisterType regtype;
int relative;
RegisterType relative_regtype;
int relative_regnum;
int relative_component;
const VariableList *relative_array;
} SourceArgInfo;
77
78
#define SCRATCH_BUFFER_SIZE 128
79
#define SCRATCH_BUFFERS 32
80
81
// !!! FIXME: the scratch buffers make Context pretty big.
82
83
// !!! FIXME: might be worth having one set of static scratch buffers that
// !!! FIXME: are mutex protected?
84
85
86
struct Profile; // predeclare.
87
// Context...this is state that changes as we parse through a shader...
88
typedef struct Context
89
{
90
91
int isfail;
int out_of_memory;
92
93
MOJOSHADER_malloc malloc;
MOJOSHADER_free free;
94
void *malloc_data;
95
const uint32 *orig_tokens;
96
97
const uint32 *tokens;
uint32 tokencount;
98
MOJOSHADER_parsePhase parse_phase;
99
100
const MOJOSHADER_swizzle *swizzles;
unsigned int swizzles_count;
101
OutputList *output;
102
OutputList preflight;
103
OutputList globals;
104
OutputList helpers;
105
OutputList subroutines;
106
OutputList mainline_intro;
107
OutputList mainline;
108
109
OutputList ignore;
OutputList *output_stack[2];
110
uint8 *output_bytes; // can be used instead of the OutputLists.
111
112
int indent_stack[2];
int output_stack_len;
113
int output_len; // total strlen; prevents walking the lists just to malloc.
114
int indent;
115
const char *shader_type_str;
116
117
const char *endline;
int endline_len;
118
char scratch[SCRATCH_BUFFERS][SCRATCH_BUFFER_SIZE];
119
120
int scratchidx; // current scratch buffer.
int profileid;
121
const struct Profile *profile;
122
MOJOSHADER_shaderType shader_type;
123
124
uint8 major_ver;
uint8 minor_ver;
125
DestArgInfo dest_arg;
126
SourceArgInfo source_args[5];
127
SourceArgInfo predicate_arg; // for predicated instructions.
128
uint32 dwords[4];
129
uint32 version_token;
130
int instruction_count;
131
uint32 instruction_controls;
132
133
uint32 previous_opcode;
int loops;
134
int reps;
135
int max_reps;
136
int cmps;
137
138
int scratch_registers;
int max_scratch_registers;
139
140
141
int branch_labels_stack_index;
int branch_labels_stack[32];
int assigned_branch_labels;
142
int assigned_vertex_attributes;
143
int last_address_reg_component;
144
145
RegisterList used_registers;
RegisterList defined_registers;
146
147
int error_count;
ErrorList *errors;
148
149
int constant_count;
ConstantsList *constants;
150
int uniform_count;
151
152
153
int uniform_float4_count;
int uniform_int4_count;
int uniform_bool_count;
154
RegisterList uniforms;
155
156
int attribute_count;
RegisterList attributes;
157
158
int sampler_count;
RegisterList samplers;
159
VariableList *variables; // variables to register mapping.
160
161
int centroid_allowed;
int have_ctab;
162
int have_relative_input_registers;
163
164
165
166
167
168
169
int determined_constants_arrays;
int predicated;
int support_nv2;
int support_nv3;
int support_nv4;
int support_glsl120;
int glsl_generated_lit_opcode;
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
} Context;
// Profile entry points...
// one emit function for each opcode in each profile.
typedef void (*emit_function)(Context *ctx);
// one emit function for starting output in each profile.
typedef void (*emit_start)(Context *ctx, const char *profilestr);
// one emit function for ending output in each profile.
typedef void (*emit_end)(Context *ctx);
// one emit function for phase opcode output in each profile.
typedef void (*emit_phase)(Context *ctx);
// one emit function for finalizing output in each profile.
typedef void (*emit_finalize)(Context *ctx);
// one emit function for global definitions in each profile.
typedef void (*emit_global)(Context *ctx, RegisterType regtype, int regnum);
// one emit function for relative uniform arrays in each profile.
typedef void (*emit_array)(Context *ctx, VariableList *var);
// one emit function for relative constants arrays in each profile.
typedef void (*emit_const_array)(Context *ctx,
const struct ConstantsList *constslist,
int base, int size);
// one emit function for uniforms in each profile.
typedef void (*emit_uniform)(Context *ctx, RegisterType regtype, int regnum,
const VariableList *var);
// one emit function for samplers in each profile.
typedef void (*emit_sampler)(Context *ctx, int stage, TextureType ttype);
// one emit function for attributes in each profile.
typedef void (*emit_attribute)(Context *ctx, RegisterType regtype, int regnum,
MOJOSHADER_usage usage, int index, int wmask,
int flags);
// one args function for each possible sequence of opcode arguments.
typedef int (*args_function)(Context *ctx);
// one state function for each opcode where we have state machine updates.
typedef void (*state_function)(Context *ctx);
// one function for varnames in each profile.
typedef const char *(*varname_function)(Context *c, RegisterType t, int num);
// one function for const var array in each profile.
typedef const char *(*const_array_varname_function)(Context *c, int base, int size);
typedef struct Profile
{
const char *name;
emit_start start_emitter;
emit_end end_emitter;
emit_phase phase_emitter;
emit_global global_emitter;
emit_array array_emitter;
emit_const_array const_array_emitter;
emit_uniform uniform_emitter;
emit_sampler sampler_emitter;
emit_attribute attribute_emitter;
emit_finalize finalize_emitter;
varname_function get_varname;
const_array_varname_function get_const_array_varname;
} Profile;
240
241
242
// Convenience functions for allocators...
243
#if !MOJOSHADER_FORCE_ALLOCATOR
244
245
void *MOJOSHADER_internal_malloc(int bytes, void *d) { return malloc(bytes); }
void MOJOSHADER_internal_free(void *ptr, void *d) { free(ptr); }
246
#endif
247
248
249
250
251
MOJOSHADER_error MOJOSHADER_out_of_mem_error = { "Out of memory", NULL, -1 };
MOJOSHADER_parseData MOJOSHADER_out_of_mem_data = {
1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0,
MOJOSHADER_TYPE_UNKNOWN, 0, 0, 0, 0
252
253
};
254
static inline void out_of_memory(Context *ctx)
255
{
256
ctx->isfail = ctx->out_of_memory = 1;
257
258
} // out_of_memory
259
static inline void *Malloc(Context *ctx, const size_t len)
260
{
261
void *retval = ctx->malloc((int) len, ctx->malloc_data);
262
263
264
if (retval == NULL)
out_of_memory(ctx);
return retval;
265
266
} // Malloc
267
268
269
static inline char *StrDup(Context *ctx, const char *str)
{
char *retval = (char *) Malloc(ctx, strlen(str) + 1);
270
if (retval != NULL)
271
272
273
strcpy(retval, str);
return retval;
} // StrDup
274
275
static inline void Free(Context *ctx, void *ptr)
276
{
277
if (ptr != NULL) // check for NULL in case of dumb free() impl.
278
ctx->free(ptr, ctx->malloc_data);
279
280
281
} // Free
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
// jump between output sections in the context...
static inline void push_output(Context *ctx, OutputList *section)
{
assert(ctx->output_stack_len < STATICARRAYLEN(ctx->output_stack));
ctx->output_stack[ctx->output_stack_len] = ctx->output;
ctx->indent_stack[ctx->output_stack_len] = ctx->indent;
ctx->output_stack_len++;
ctx->output = section;
ctx->indent = 0;
} // push_output
static inline void pop_output(Context *ctx)
{
assert(ctx->output_stack_len > 0);
ctx->output_stack_len--;
ctx->output = ctx->output_stack[ctx->output_stack_len];
ctx->indent = ctx->indent_stack[ctx->output_stack_len];
} // pop_output
// Shader model version magic...
306
307
static inline uint32 ver_ui32(const uint8 major, const uint8 minor)
{
308
return ( (((uint32) major) << 16) | (((minor) == 0xFF) ? 1 : (minor)) );
309
310
} // version_ui32
311
static inline int shader_version_supported(const uint8 maj, const uint8 min)
312
313
314
315
{
return (ver_ui32(maj,min) <= ver_ui32(MAX_SHADER_MAJOR, MAX_SHADER_MINOR));
} // shader_version_supported
316
317
static inline int shader_version_atleast(const Context *ctx, const uint8 maj,
const uint8 min)
318
319
320
321
{
return (ver_ui32(ctx->major_ver, ctx->minor_ver) >= ver_ui32(maj, min));
} // shader_version_atleast
322
323
324
325
326
327
static inline int shader_version_exactly(const Context *ctx, const uint8 maj,
const uint8 min)
{
return ((ctx->major_ver == maj) && (ctx->minor_ver == min));
} // shader_version_exactly
328
329
330
331
332
333
334
335
336
337
static inline int shader_is_pixel(const Context *ctx)
{
return (ctx->shader_type == MOJOSHADER_TYPE_PIXEL);
} // shader_is_pixel
static inline int shader_is_vertex(const Context *ctx)
{
return (ctx->shader_type == MOJOSHADER_TYPE_VERTEX);
} // shader_is_vertex
338
339
340
static inline int isfail(const Context *ctx)
{
341
return ctx->isfail;
342
343
} // isfail
344
345
static inline char *get_scratch_buffer(Context *ctx)
346
{
347
assert(ctx->scratchidx < SCRATCH_BUFFERS);
348
ctx->scratchidx = (ctx->scratchidx + 1) % SCRATCH_BUFFERS;
349
return ctx->scratch[ctx->scratchidx];
350
351
} // get_scratch_buffer
352
353
354
static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
static void failf(Context *ctx, const char *fmt, ...)
355
{
356
357
ctx->isfail = 1;
if (ctx->out_of_memory)
358
return;
359
360
361
int error_position = 0;
switch (ctx->parse_phase)
362
{
363
364
365
366
367
368
369
370
371
372
373
case MOJOSHADER_PARSEPHASE_NOTSTARTED:
error_position = -2;
break;
case MOJOSHADER_PARSEPHASE_WORKING:
error_position = (ctx->tokens - ctx->orig_tokens) * sizeof (uint32);
break;
case MOJOSHADER_PARSEPHASE_DONE:
error_position = -1;
break;
default:
assert(0 && "Unexpected value");
374
return;
375
376
377
378
} // switch
ErrorList *error = (ErrorList *) Malloc(ctx, sizeof (ErrorList));
if (error == NULL)
379
return;
380
381
382
383
384
385
char *scratch = get_scratch_buffer(ctx);
va_list ap;
va_start(ap, fmt);
const int len = vsnprintf(scratch, SCRATCH_BUFFER_SIZE, fmt, ap);
va_end(ap);
386
387
388
389
390
391
392
393
394
395
char *failstr = (char *) Malloc(ctx, len + 1);
if (failstr == NULL)
Free(ctx, error);
else
{
// see comments about scratch buffer overflow in output_line().
if (len < SCRATCH_BUFFER_SIZE)
strcpy(failstr, scratch); // copy it over.
else
396
{
397
398
399
400
401
402
403
404
va_start(ap, fmt);
vsnprintf(failstr, len + 1, fmt, ap); // rebuild it.
va_end(ap);
} // else
error->error.error = failstr;
error->error.filename = NULL; // no filename at this level.
error->error.error_position = error_position;
405
error->next = NULL;
406
407
ErrorList *prev = NULL;
408
409
ErrorList *item = ctx->errors;
while (item != NULL)
410
{
411
prev = item;
412
item = item->next;
413
414
} // while
415
if (prev == NULL)
416
ctx->errors = error;
417
418
else
prev->next = error;
419
420
421
ctx->error_count++;
} // else
422
423
424
} // failf
425
static inline void fail(Context *ctx, const char *reason)
426
{
427
failf(ctx, "%s", reason);
428
429
430
} // fail
431
432
static void output_line(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
static void output_line(Context *ctx, const char *fmt, ...)
433
{
434
435
OutputListNode *item = NULL;
436
437
if (isfail(ctx) || ctx->out_of_memory)
return; // we failed previously, don't go on...
438
439
char *scratch = get_scratch_buffer(ctx);
440
441
const int indent = ctx->indent;
442
443
if (indent > 0)
memset(scratch, '\t', indent);
444
445
446
va_list ap;
va_start(ap, fmt);
447
const int len = vsnprintf(scratch+indent, SCRATCH_BUFFER_SIZE-indent, fmt, ap) + indent;
448
449
va_end(ap);
450
item = (OutputListNode *) Malloc(ctx, sizeof (OutputListNode));
451
if (item == NULL)
452
return;
453
454
item->str = (char *) Malloc(ctx, len + 1);
455
if (item->str == NULL)
456
{
457
Free(ctx, item);
458
return;
459
460
} // if
461
462
463
// If we overflowed our scratch buffer, that's okay. We were going to
// allocate anyhow...the scratch buffer just lets us avoid a second
// run of vsnprintf().
464
if (len < SCRATCH_BUFFER_SIZE)
465
466
467
strcpy(item->str, scratch); // copy it over.
else
{
468
469
if (indent > 0)
memset(item->str, '\t', indent);
470
va_start(ap, fmt);
471
vsnprintf(item->str+indent, len + 1, fmt, ap); // rebuild it.
472
473
va_end(ap);
} // else
474
475
item->next = NULL;
476
477
478
ctx->output->tail->next = item;
ctx->output->tail = item;
479
ctx->output_len += len + ctx->endline_len;
480
481
482
} // output_line
483
// this is just to stop gcc whining.
484
static inline void output_blank_line(Context *ctx)
485
{
486
output_line(ctx, "%s", "");
487
488
489
} // output_blank_line
490
// !!! FIXME: this is sort of nasty.
491
492
static void floatstr(Context *ctx, char *buf, size_t bufsize, float f,
int leavedecimal)
493
494
{
const size_t len = snprintf(buf, bufsize, "%f", f);
495
if ((len+2) >= bufsize)
496
497
498
499
500
501
fail(ctx, "BUG: internal buffer is too small");
else
{
char *end = buf + len;
char *ptr = strchr(buf, '.');
if (ptr == NULL)
502
503
504
{
if (leavedecimal)
strcat(buf, ".0");
505
return; // done.
506
} // if
507
508
509
510
511
512
513
514
515
while (--end != ptr)
{
if (*end != '0')
{
end++;
break;
} // if
} // while
516
517
if ((leavedecimal) && (end == ptr))
end += 2;
518
519
520
521
*end = '\0'; // chop extra '0' or all decimal places off.
} // else
} // floatstr
522
523
524
// Deal with register lists... !!! FIXME: I sort of hate this.
525
static void free_reglist(MOJOSHADER_free f, void *d, RegisterList *item)
526
527
528
529
{
while (item != NULL)
{
RegisterList *next = item->next;
530
f(item, d);
531
532
533
534
535
536
537
538
539
item = next;
} // while
} // free_reglist
static inline uint32 reg_to_ui32(const RegisterType regtype, const int regnum)
{
return ( ((uint32) regtype) | (((uint32) regnum) << 16) );
} // reg_to_uint32
540
541
542
static RegisterList *reglist_insert(Context *ctx, RegisterList *prev,
const RegisterType regtype,
const int regnum)
543
544
545
546
547
548
549
{
const uint32 newval = reg_to_ui32(regtype, regnum);
RegisterList *item = prev->next;
while (item != NULL)
{
const uint32 val = reg_to_ui32(item->regtype, item->regnum);
if (newval == val)
550
return item; // already set, so we're done.
551
552
553
554
555
556
557
558
559
560
561
else if (newval < val) // insert it here.
break;
else // if (newval > val)
{
// keep going, we're not to the insertion point yet.
prev = item;
item = item->next;
} // else
} // while
// we need to insert an entry after (prev).
562
item = (RegisterList *) Malloc(ctx, sizeof (RegisterList));
563
if (item != NULL)
564
565
566
{
item->regtype = regtype;
item->regnum = regnum;
567
item->usage = MOJOSHADER_USAGE_UNKNOWN;
568
569
item->index = 0;
item->writemask = 0;
570
item->misc = 0;
571
item->array = NULL;
572
573
item->next = prev->next;
prev->next = item;
574
} // if
575
576
return item;
577
578
} // reglist_insert
579
580
static RegisterList *reglist_find(const RegisterList *prev,
const RegisterType rtype, const int regnum)
581
{
582
583
const uint32 newval = reg_to_ui32(rtype, regnum);
RegisterList *item = prev->next;
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
while (item != NULL)
{
const uint32 val = reg_to_ui32(item->regtype, item->regnum);
if (newval == val)
return item; // here it is.
else if (newval < val) // should have been here if it existed.
return NULL;
else // if (newval > val)
{
// keep going, we're not to the insertion point yet.
prev = item;
item = item->next;
} // else
} // while
return NULL; // wasn't in the list.
600
601
602
603
604
605
606
} // reglist_find
static inline const RegisterList *reglist_exists(RegisterList *prev,
const RegisterType regtype,
const int regnum)
{
return (reglist_find(prev, regtype, regnum));
607
608
609
610
611
612
613
614
615
616
617
618
} // reglist_exists
static inline void set_used_register(Context *ctx, const RegisterType regtype,
const int regnum)
{
reglist_insert(ctx, &ctx->used_registers, regtype, regnum);
} // set_used_register
static inline int get_used_register(Context *ctx, const RegisterType regtype,
const int regnum)
{
return (reglist_exists(&ctx->used_registers, regtype, regnum) != NULL);
619
} // get_used_register
620
621
622
623
624
625
626
627
628
629
630
631
632
static inline void set_defined_register(Context *ctx, const RegisterType rtype,
const int regnum)
{
reglist_insert(ctx, &ctx->defined_registers, rtype, regnum);
} // set_defined_register
static inline int get_defined_register(Context *ctx, const RegisterType rtype,
const int regnum)
{
return (reglist_exists(&ctx->defined_registers, rtype, regnum) != NULL);
} // get_defined_register
633
634
static void add_attribute_register(Context *ctx, const RegisterType rtype,
const int regnum, const MOJOSHADER_usage usage,
635
const int index, const int writemask, int flags)
636
637
638
639
640
{
RegisterList *item = reglist_insert(ctx, &ctx->attributes, rtype, regnum);
item->usage = usage;
item->index = index;
item->writemask = writemask;
641
item->misc = flags;
642
643
} // add_attribute_register
644
645
646
static inline void add_sampler(Context *ctx, const RegisterType rtype,
const int regnum, const TextureType ttype)
{
647
// !!! FIXME: make sure it doesn't exist?
648
649
650
651
RegisterList *item = reglist_insert(ctx, &ctx->samplers, rtype, regnum);
item->index = (int) ttype;
} // add_sampler
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
static inline int writemask_xyzw(const int writemask)
{
return (writemask == 0xF); // 0xF == 1111. No explicit mask (full!).
} // writemask_xyzw
static inline int writemask_xyz(const int writemask)
{
return (writemask == 0x7); // 0x7 == 0111. (that is: xyz)
} // writemask_xyz
static inline int writemask_xy(const int writemask)
{
return (writemask == 0x3); // 0x3 == 0011. (that is: xy)
} // writemask_xy
static inline int writemask_x(const int writemask)
{
return (writemask == 0x1); // 0x1 == 0001. (that is: x)
} // writemask_x
static inline int writemask_y(const int writemask)
{
return (writemask == 0x2); // 0x1 == 0010. (that is: y)
} // writemask_y
683
684
685
686
687
688
689
690
static inline int replicate_swizzle(const int swizzle)
{
return ( (((swizzle >> 0) & 0x3) == ((swizzle >> 2) & 0x3)) &&
(((swizzle >> 2) & 0x3) == ((swizzle >> 4) & 0x3)) &&
(((swizzle >> 4) & 0x3) == ((swizzle >> 6) & 0x3)) );
} // replicate_swizzle
691
692
static inline int no_swizzle(const int swizzle)
{
693
return (swizzle == 0xE4); // 0xE4 == 11100100 ... 0 1 2 3. No swizzle.
694
695
696
} // no_swizzle
697
698
699
700
701
static inline int vecsize_from_writemask(const int m)
{
return (m & 1) + ((m >> 1) & 1) + ((m >> 2) & 1) + ((m >> 3) & 1);
} // vecsize_from_writemask
702
703
704
705
706
707
708
709
static int allocate_scratch_register(Context *ctx)
{
const int retval = ctx->scratch_registers++;
if (retval >= ctx->max_scratch_registers)
ctx->max_scratch_registers = retval + 1;
return retval;
} // allocate_scratch_register
710
static int allocate_branch_label(Context *ctx)
711
{
712
713
return ctx->assigned_branch_labels++;
} // allocate_branch_label
714
715
716
717
// D3D stuff that's used in more than just the d3d profile...
718
719
720
static const char swizzle_channels[] = { 'x', 'y', 'z', 'w' };
721
722
723
724
725
static const char *usagestrs[] = {
"_position", "_blendweight", "_blendindices", "_normal", "_psize",
"_texcoord", "_tangent", "_binormal", "_tessfactor", "_positiont",
"_color", "_fog", "_depth", "_sample"
};
726
727
static const char *get_D3D_register_string(Context *ctx,
728
RegisterType regtype,
729
730
int regnum, char *regnum_str,
size_t regnum_size)
731
{
732
const char *retval = NULL;
733
int has_number = 1;
734
735
switch (regtype)
736
{
737
case REG_TYPE_TEMP:
738
retval = "r";
739
740
break;
741
case REG_TYPE_INPUT:
742
retval = "v";
743
744
break;
745
case REG_TYPE_CONST:
746
747
748
retval = "c";
break;
749
case REG_TYPE_ADDRESS: // (or REG_TYPE_TEXTURE, same value.)
750
retval = shader_is_vertex(ctx) ? "a" : "t";
751
752
break;
753
case REG_TYPE_RASTOUT:
754
switch ((RastOutType) regnum)
755
{
756
757
758
case RASTOUT_TYPE_POSITION: retval = "oPos"; break;
case RASTOUT_TYPE_FOG: retval = "oFog"; break;
case RASTOUT_TYPE_POINT_SIZE: retval = "oPts"; break;
759
} // switch
760
has_number = 0;
761
762
break;
763
case REG_TYPE_ATTROUT:
764
retval = "oD";
765
766
break;
767
case REG_TYPE_OUTPUT: // (or REG_TYPE_TEXCRDOUT, same value.)
768
if (shader_is_vertex(ctx) && shader_version_atleast(ctx, 3, 0))
769
retval = "o";
770
else
771
retval = "oT";
772
773
break;
774
case REG_TYPE_CONSTINT:
775
retval = "i";
776
777
break;
778
case REG_TYPE_COLOROUT:
779
retval = "oC";
780
781
break;
782
case REG_TYPE_DEPTHOUT:
783
retval = "oDepth";
784
has_number = 0;
785
786
break;
787
case REG_TYPE_SAMPLER:
788
retval = "s";
789
790
break;
791
case REG_TYPE_CONSTBOOL:
792
retval = "b";
793
794
break;
795
case REG_TYPE_LOOP:
796
retval = "aL";
797
has_number = 0;
798
799
break;
800
case REG_TYPE_MISCTYPE:
801
switch ((const MiscTypeType) regnum)
802
{
803
804
case MISCTYPE_TYPE_POSITION: retval = "vPos"; break;
case MISCTYPE_TYPE_FACE: retval = "vFace"; break;
805
} // switch
806
has_number = 0;
807
808
break;
809
case REG_TYPE_LABEL:
810
retval = "l";
811
812
break;
813
case REG_TYPE_PREDICATE:
814
retval = "p";
815
break;
816
817
818
819
820
821
822
//case REG_TYPE_TEMPFLOAT16: // !!! FIXME: don't know this asm string
default:
fail(ctx, "unknown register type");
retval = "???";
has_number = 0;
break;
823
824
} // switch
825
826
827
828
829
if (has_number)
snprintf(regnum_str, regnum_size, "%u", (uint) regnum);
else
regnum_str[0] = '\0';
830
831
832
833
return retval;
} // get_D3D_register_string
834
835
836
837
838
839
840
841
842
#define AT_LEAST_ONE_PROFILE 0
#if !SUPPORT_PROFILE_D3D
#define PROFILE_EMITTER_D3D(op)
#else
#undef AT_LEAST_ONE_PROFILE
#define AT_LEAST_ONE_PROFILE 1
#define PROFILE_EMITTER_D3D(op) emit_D3D_##op,
843
static const char *make_D3D_srcarg_string_in_buf(Context *ctx,
844
845
const SourceArgInfo *arg,
char *buf, size_t buflen)
846
847
848
{
const char *premod_str = "";
const char *postmod_str = "";
849
switch (arg->src_mod)
850
851
852
853
854
855
856
857
858
859
860
{
case SRCMOD_NEGATE:
premod_str = "-";
break;
case SRCMOD_BIASNEGATE:
premod_str = "-";
// fall through.
case SRCMOD_BIAS:
postmod_str = "_bias";
break;
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
case SRCMOD_SIGNNEGATE:
premod_str = "-";
// fall through.
case SRCMOD_SIGN:
postmod_str = "_bx2";
break;
case SRCMOD_COMPLEMENT:
premod_str = "1-";
break;
case SRCMOD_X2NEGATE:
premod_str = "-";
// fall through.
case SRCMOD_X2:
postmod_str = "_x2";
break;
case SRCMOD_DZ:
postmod_str = "_dz";
break;
case SRCMOD_DW:
postmod_str = "_dw";
break;
case SRCMOD_ABSNEGATE:
premod_str = "-";
// fall through.
case SRCMOD_ABS:
postmod_str = "_abs";
break;
case SRCMOD_NOT:
premod_str = "!";
break;
898
899
900
901
case SRCMOD_NONE:
case SRCMOD_TOTAL:
break; // stop compiler whining.
902
903
904
905
} // switch
char regnum_str[16];
906
907
908
const char *regtype_str = get_D3D_register_string(ctx, arg->regtype,
arg->regnum, regnum_str,
sizeof (regnum_str));
909
910
911
912
if (regtype_str == NULL)
{
fail(ctx, "Unknown source register type.");
913
return "";
914
915
} // if
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
const char *rel_lbracket = "";
const char *rel_rbracket = "";
char rel_swizzle[4] = { '\0' };
char rel_regnum_str[16] = { '\0' };
const char *rel_regtype_str = "";
if (arg->relative)
{
rel_swizzle[0] = '.';
rel_swizzle[1] = swizzle_channels[arg->relative_component];
rel_swizzle[2] = '\0';
rel_lbracket = "[";
rel_rbracket = "]";
rel_regtype_str = get_D3D_register_string(ctx, arg->relative_regtype,
arg->relative_regnum,
rel_regnum_str,
sizeof (rel_regnum_str));
if (regtype_str == NULL)
{
fail(ctx, "Unknown relative source register type.");
return "";
} // if
} // if
940
941
char swizzle_str[6];
int i = 0;
942
const int scalar = scalar_register(ctx->shader_type, arg->regtype, arg->regnum);
943
if (!scalar && !no_swizzle(arg->swizzle))
944
945
{
swizzle_str[i++] = '.';
946
947
948
949
swizzle_str[i++] = swizzle_channels[arg->swizzle_x];
swizzle_str[i++] = swizzle_channels[arg->swizzle_y];
swizzle_str[i++] = swizzle_channels[arg->swizzle_z];
swizzle_str[i++] = swizzle_channels[arg->swizzle_w];
950
951
952
953
// .xyzz is the same as .xyz, .z is the same as .zzzz, etc.
while (swizzle_str[i-1] == swizzle_str[i-2])
i--;
954
955
956
957
} // if
swizzle_str[i] = '\0';
assert(i < sizeof (swizzle_str));
958
// !!! FIXME: c12[a0.x] actually needs to be c[a0.x + 12]
959
960
961
962
snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s",
premod_str, regtype_str, regnum_str, postmod_str,
rel_lbracket, rel_regtype_str, rel_regnum_str, rel_swizzle,
rel_rbracket, swizzle_str);
963
// !!! FIXME: make sure the scratch buffer was large enough.
964
return buf;
965
} // make_D3D_srcarg_string_in_buf
966
967
968
static const char *make_D3D_destarg_string(Context *ctx)
969
{
970
const DestArgInfo *arg = &ctx->dest_arg;
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
const char *result_shift_str = "";
switch (arg->result_shift)
{
case 0x1: result_shift_str = "_x2"; break;
case 0x2: result_shift_str = "_x4"; break;
case 0x3: result_shift_str = "_x8"; break;
case 0xD: result_shift_str = "_d8"; break;
case 0xE: result_shift_str = "_d4"; break;
case 0xF: result_shift_str = "_d2"; break;
} // switch
const char *sat_str = (arg->result_mod & MOD_SATURATE) ? "_sat" : "";
const char *pp_str = (arg->result_mod & MOD_PP) ? "_pp" : "";
const char *cent_str = (arg->result_mod & MOD_CENTROID) ? "_centroid" : "";
char regnum_str[16];
const char *regtype_str = get_D3D_register_string(ctx, arg->regtype,
arg->regnum, regnum_str,
sizeof (regnum_str));
if (regtype_str == NULL)
{
fail(ctx, "Unknown destination register type.");
return "";
} // if
char writemask_str[6];
int i = 0;
999
const int scalar = scalar_register(ctx->shader_type, arg->regtype, arg->regnum);
1000
if (!scalar && !writemask_xyzw(arg->writemask))