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