2 * Copyright 2013 VMware, Inc.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 * This utility transforms fragment shaders to facilitate two-sided lighting.
30 * Basically, if the FS has any color inputs (TGSI_SEMANTIC_COLOR) we'll:
31 * 1. create corresponding back-color inputs (TGSI_SEMANTIC_BCOLOR)
32 * 2. use the FACE register to choose between front/back colors and put the
33 * selected color in new temp regs.
34 * 3. replace reads of the original color inputs with the new temp regs.
36 * Then, the driver just needs to link the VS front/back output colors to
37 * the FS front/back input colors.
40 #include "util/u_debug.h"
41 #include "util/u_math.h"
42 #include "tgsi_info.h"
43 #include "tgsi_two_side.h"
44 #include "tgsi_transform.h"
47 #define INVALID_INDEX 9999
50 struct two_side_transform_context
52 struct tgsi_transform_context base
;
55 uint face_input
; /**< index of the FACE input */
56 uint front_color_input
[2]; /**< INPUT regs */
57 uint front_color_interp
[2];/**< TGSI_INTERPOLATE_x */
58 uint back_color_input
[2]; /**< INPUT regs */
59 uint new_colors
[2]; /**< TEMP regs */
63 static inline struct two_side_transform_context
*
64 two_side_transform_context(struct tgsi_transform_context
*ctx
)
66 return (struct two_side_transform_context
*) ctx
;
71 xform_decl(struct tgsi_transform_context
*ctx
,
72 struct tgsi_full_declaration
*decl
)
74 struct two_side_transform_context
*ts
= two_side_transform_context(ctx
);
76 if (decl
->Declaration
.File
== TGSI_FILE_INPUT
) {
77 if (decl
->Semantic
.Name
== TGSI_SEMANTIC_COLOR
) {
78 /* found a front color */
79 assert(decl
->Semantic
.Index
< 2);
80 ts
->front_color_input
[decl
->Semantic
.Index
] = decl
->Range
.First
;
81 ts
->front_color_interp
[decl
->Semantic
.Index
] = decl
->Interp
.Interpolate
;
83 else if (decl
->Semantic
.Name
== TGSI_SEMANTIC_FACE
) {
84 ts
->face_input
= decl
->Range
.First
;
86 ts
->num_inputs
= MAX2(ts
->num_inputs
, decl
->Range
.Last
+ 1);
88 else if (decl
->Declaration
.File
== TGSI_FILE_TEMPORARY
) {
89 ts
->num_temps
= MAX2(ts
->num_temps
, decl
->Range
.Last
+ 1);
92 ctx
->emit_declaration(ctx
, decl
);
97 emit_prolog(struct tgsi_transform_context
*ctx
)
99 struct two_side_transform_context
*ts
= two_side_transform_context(ctx
);
100 struct tgsi_full_declaration decl
;
101 struct tgsi_full_instruction inst
;
105 /* Declare 0, 1 or 2 new BCOLOR inputs */
106 for (i
= 0; i
< 2; i
++) {
107 if (ts
->front_color_input
[i
] != INVALID_INDEX
) {
108 decl
= tgsi_default_full_declaration();
109 decl
.Declaration
.File
= TGSI_FILE_INPUT
;
110 decl
.Declaration
.Interpolate
= 1;
111 decl
.Declaration
.Semantic
= 1;
112 decl
.Semantic
.Name
= TGSI_SEMANTIC_BCOLOR
;
113 decl
.Semantic
.Index
= i
;
114 decl
.Range
.First
= decl
.Range
.Last
= ts
->num_inputs
++;
115 decl
.Interp
.Interpolate
= ts
->front_color_interp
[i
];
116 ctx
->emit_declaration(ctx
, &decl
);
117 ts
->back_color_input
[i
] = decl
.Range
.First
;
122 if (num_colors
> 0) {
123 /* Declare 1 or 2 temp registers */
124 decl
= tgsi_default_full_declaration();
125 decl
.Declaration
.File
= TGSI_FILE_TEMPORARY
;
126 decl
.Range
.First
= ts
->num_temps
;
127 decl
.Range
.Last
= ts
->num_temps
+ num_colors
- 1;
128 ctx
->emit_declaration(ctx
, &decl
);
129 ts
->new_colors
[0] = ts
->num_temps
;
130 ts
->new_colors
[1] = ts
->num_temps
+ 1;
132 if (ts
->face_input
== INVALID_INDEX
) {
133 /* declare FACE INPUT register */
134 decl
= tgsi_default_full_declaration();
135 decl
.Declaration
.File
= TGSI_FILE_INPUT
;
136 decl
.Declaration
.Semantic
= 1;
137 decl
.Semantic
.Name
= TGSI_SEMANTIC_FACE
;
138 decl
.Semantic
.Index
= 0;
139 decl
.Range
.First
= decl
.Range
.Last
= ts
->num_inputs
++;
140 ctx
->emit_declaration(ctx
, &decl
);
141 ts
->face_input
= decl
.Range
.First
;
144 /* CMP temp[c0], face, bcolor[c0], fcolor[c0]
145 * temp[c0] = face < 0.0 ? bcolor[c0] : fcolor[c0]
147 for (i
= 0; i
< 2; i
++) {
148 if (ts
->front_color_input
[i
] != INVALID_INDEX
) {
149 inst
= tgsi_default_full_instruction();
150 inst
.Instruction
.Opcode
= TGSI_OPCODE_CMP
;
151 inst
.Instruction
.NumDstRegs
= 1;
152 inst
.Dst
[0].Register
.File
= TGSI_FILE_TEMPORARY
;
153 inst
.Dst
[0].Register
.Index
= ts
->new_colors
[i
];
154 inst
.Instruction
.NumSrcRegs
= 3;
155 inst
.Src
[0].Register
.File
= TGSI_FILE_INPUT
;
156 inst
.Src
[0].Register
.Index
= ts
->face_input
;
157 inst
.Src
[1].Register
.File
= TGSI_FILE_INPUT
;
158 inst
.Src
[1].Register
.Index
= ts
->back_color_input
[i
];
159 inst
.Src
[2].Register
.File
= TGSI_FILE_INPUT
;
160 inst
.Src
[2].Register
.Index
= ts
->front_color_input
[i
];
162 ctx
->emit_instruction(ctx
, &inst
);
170 xform_inst(struct tgsi_transform_context
*ctx
,
171 struct tgsi_full_instruction
*inst
)
173 struct two_side_transform_context
*ts
= two_side_transform_context(ctx
);
174 const struct tgsi_opcode_info
*info
=
175 tgsi_get_opcode_info(inst
->Instruction
.Opcode
);
178 /* Look for src regs which reference the input color and replace
179 * them with the temp color.
181 for (i
= 0; i
< info
->num_src
; i
++) {
182 if (inst
->Src
[i
].Register
.File
== TGSI_FILE_INPUT
) {
183 for (j
= 0; j
< 2; j
++) {
184 if (inst
->Src
[i
].Register
.Index
== ts
->front_color_input
[j
]) {
185 /* replace color input with temp reg */
186 inst
->Src
[i
].Register
.File
= TGSI_FILE_TEMPORARY
;
187 inst
->Src
[i
].Register
.Index
= ts
->new_colors
[j
];
194 ctx
->emit_instruction(ctx
, inst
);
199 tgsi_add_two_side(const struct tgsi_token
*tokens_in
)
201 struct two_side_transform_context transform
;
202 const uint num_new_tokens
= 100; /* should be enough */
203 const uint new_len
= tgsi_num_tokens(tokens_in
) + num_new_tokens
;
204 struct tgsi_token
*new_tokens
;
206 /* setup transformation context */
207 memset(&transform
, 0, sizeof(transform
));
208 transform
.base
.transform_declaration
= xform_decl
;
209 transform
.base
.transform_instruction
= xform_inst
;
210 transform
.base
.prolog
= emit_prolog
;
211 transform
.face_input
= INVALID_INDEX
;
212 transform
.front_color_input
[0] = INVALID_INDEX
;
213 transform
.front_color_input
[1] = INVALID_INDEX
;
214 transform
.front_color_interp
[0] = TGSI_INTERPOLATE_COLOR
;
215 transform
.front_color_interp
[1] = TGSI_INTERPOLATE_COLOR
;
216 transform
.back_color_input
[0] = INVALID_INDEX
;
217 transform
.back_color_input
[1] = INVALID_INDEX
;
219 /* allocate new tokens buffer */
220 new_tokens
= tgsi_alloc_tokens(new_len
);
224 /* transform the shader */
225 tgsi_transform_shader(tokens_in
, new_tokens
, new_len
, &transform
.base
);