126 static inline int isfail(const Context *ctx) |
126 static inline int isfail(const Context *ctx) |
127 { |
127 { |
128 return ctx->isfail; |
128 return ctx->isfail; |
129 } // isfail |
129 } // isfail |
130 |
130 |
|
131 static int vecsize_from_writemask(const uint8 m) |
|
132 { |
|
133 return (m & 1) + ((m >> 1) & 1) + ((m >> 2) & 1) + ((m >> 3) & 1); |
|
134 } // vecsize_from_writemask |
|
135 |
|
136 static void set_dstarg_writemask(DestArgInfo *dst, const uint8 mask) |
|
137 { |
|
138 dst->writemask = mask; |
|
139 dst->writemask0 = ((mask >> 0) & 1); |
|
140 dst->writemask1 = ((mask >> 1) & 1); |
|
141 dst->writemask2 = ((mask >> 2) & 1); |
|
142 dst->writemask3 = ((mask >> 3) & 1); |
|
143 } // set_dstarg_writemask |
131 |
144 |
132 // Shader model version magic... |
145 // Shader model version magic... |
133 |
146 |
134 static inline uint32 ver_ui32(const uint8 major, const uint8 minor) |
147 static inline uint32 ver_ui32(const uint8 major, const uint8 minor) |
135 { |
148 { |
551 // !!! FIXME: can dest registers do relative addressing? |
564 // !!! FIXME: can dest registers do relative addressing? |
552 |
565 |
553 int invalid_writemask = 0; |
566 int invalid_writemask = 0; |
554 if (nexttoken(ctx) != ((Token) '.')) |
567 if (nexttoken(ctx) != ((Token) '.')) |
555 { |
568 { |
556 info->writemask = ctx->default_writemask; |
569 set_dstarg_writemask(info, ctx->default_writemask); |
557 info->writemask0 = ((info->writemask >> 0) & 0x1); |
570 pushback(ctx); // no explicit writemask; do default mask. |
558 info->writemask1 = ((info->writemask >> 1) & 0x1); |
|
559 info->writemask2 = ((info->writemask >> 2) & 0x1); |
|
560 info->writemask3 = ((info->writemask >> 3) & 0x1); |
|
561 pushback(ctx); // no explicit writemask; do full mask. |
|
562 } // if |
571 } // if |
563 else if (nexttoken(ctx) != TOKEN_IDENTIFIER) |
572 else if (nexttoken(ctx) != TOKEN_IDENTIFIER) |
564 { |
573 { |
565 invalid_writemask = 1; |
574 invalid_writemask = 1; |
566 } // else if |
575 } // else if |
568 { |
577 { |
569 char tokenbytes[5] = { '\0', '\0', '\0', '\0', '\0' }; |
578 char tokenbytes[5] = { '\0', '\0', '\0', '\0', '\0' }; |
570 const unsigned int tokenlen = ctx->tokenlen; |
579 const unsigned int tokenlen = ctx->tokenlen; |
571 memcpy(tokenbytes, ctx->token, ((tokenlen < 4) ? tokenlen : 4)); |
580 memcpy(tokenbytes, ctx->token, ((tokenlen < 4) ? tokenlen : 4)); |
572 char *ptr = tokenbytes; |
581 char *ptr = tokenbytes; |
573 |
582 uint8 writemask = 0; |
574 if ((*ptr == 'r') || (*ptr == 'x')) { info->writemask0 = 1; ptr++; } |
583 if ((*ptr == 'r') || (*ptr == 'x')) { writemask |= (1<<0); ptr++; } |
575 if ((*ptr == 'g') || (*ptr == 'y')) { info->writemask1 = 1; ptr++; } |
584 if ((*ptr == 'g') || (*ptr == 'y')) { writemask |= (1<<1); ptr++; } |
576 if ((*ptr == 'b') || (*ptr == 'z')) { info->writemask2 = 1; ptr++; } |
585 if ((*ptr == 'b') || (*ptr == 'z')) { writemask |= (1<<2); ptr++; } |
577 if ((*ptr == 'a') || (*ptr == 'w')) { info->writemask3 = 1; ptr++; } |
586 if ((*ptr == 'a') || (*ptr == 'w')) { writemask |= (1<<3); ptr++; } |
578 |
587 |
579 if (*ptr != '\0') |
588 if (*ptr != '\0') |
580 invalid_writemask = 1; |
589 invalid_writemask = 1; |
581 |
|
582 info->writemask = ( ((info->writemask0 & 0x1) << 0) | |
|
583 ((info->writemask1 & 0x1) << 1) | |
|
584 ((info->writemask2 & 0x1) << 2) | |
|
585 ((info->writemask3 & 0x1) << 3) ); |
|
586 |
590 |
587 // Cg generates code with oDepth.z, and Microsoft's tools accept |
591 // Cg generates code with oDepth.z, and Microsoft's tools accept |
588 // oFog.x and probably others. For safety's sake, we'll allow |
592 // oFog.x and probably others. For safety's sake, we'll allow |
589 // any single channel to be specified and will just wipe out the |
593 // any single channel to be specified and will just wipe out the |
590 // writemask as if it wasn't specified at all. More than one |
594 // writemask as if it wasn't specified at all. More than one |
591 // channel will be a fail, though. |
595 // channel will be a fail, though. |
592 if (!invalid_writemask && scalar_register(ctx->shader_type, info->regtype, info->regnum)) |
596 if (!invalid_writemask && scalar_register(ctx->shader_type, info->regtype, info->regnum)) |
593 { |
597 { |
594 const int numchans = info->writemask0 + info->writemask1 + info->writemask2 + info->writemask3; |
598 const int numchans = vecsize_from_writemask(writemask); |
595 if (numchans != 1) |
599 if (numchans != 1) |
596 fail(ctx, "Non-scalar writemask specified for scalar register"); |
600 fail(ctx, "Non-scalar writemask specified for scalar register"); |
597 info->writemask = 0xF; |
601 writemask = 0xF; |
598 info->writemask0 = info->writemask1 = info->writemask2 = info->writemask3 = 1; |
|
599 } // if |
602 } // if |
|
603 |
|
604 set_dstarg_writemask(info, writemask); |
600 } // else |
605 } // else |
601 |
606 |
602 if (invalid_writemask) |
607 if (invalid_writemask) |
603 fail(ctx, "Invalid writemask"); |
608 fail(ctx, "Invalid writemask"); |
604 |
609 |