1 /**************************************************************************
3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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 TUNGSTEN GRAPHICS 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.
26 **************************************************************************/
29 * State validation for vertex/fragment shaders.
30 * Note that we have to delay most vertex/fragment shader translation
31 * until rendering time since the linkage between the vertex outputs and
32 * fragment inputs can vary depending on the pairing of shaders.
40 #include "main/imports.h"
41 #include "main/mtypes.h"
43 #include "pipe/p_context.h"
44 #include "pipe/p_shader_tokens.h"
46 #include "st_context.h"
49 #include "st_program.h"
50 #include "st_atom_shader.h"
51 #include "st_mesa_to_tgsi.h"
55 * This represents a vertex program, especially translated to match
56 * the inputs of a particular fragment shader.
58 struct translated_vertex_program
60 struct st_vertex_program
*master
;
62 /** The fragment shader "signature" this vertex shader is meant for: */
63 GLbitfield frag_inputs
;
65 /** Compared against master vertex program's serialNo: */
68 /** Maps VERT_RESULT_x to slot */
69 GLuint output_to_slot
[VERT_RESULT_MAX
];
71 /** The program in TGSI format */
72 struct tgsi_token tokens
[ST_MAX_SHADER_TOKENS
];
74 /** Pointer to the translated, cached vertex shader */
75 const struct cso_vertex_shader
*vs
;
77 struct translated_vertex_program
*next
; /**< next in linked list */
83 * Free data hanging off the st vert prog.
86 st_remove_vertex_program(struct st_context
*st
, struct st_vertex_program
*stvp
)
93 * Free data hanging off the st frag prog.
96 st_remove_fragment_program(struct st_context
*st
,
97 struct st_fragment_program
*stfp
)
99 struct translated_vertex_program
*xvp
, *next
;
101 for (xvp
= stfp
->vertex_programs
; xvp
; xvp
= next
) {
103 /* XXX free xvp->vs */
111 * Given a vertex program output attribute, return the corresponding
112 * fragment program input attribute.
113 * \return -1 for vertex outputs that have no corresponding fragment input
116 vp_out_to_fp_in(GLuint vertResult
)
118 if (vertResult
>= VERT_RESULT_TEX0
&&
119 vertResult
< VERT_RESULT_TEX0
+ MAX_TEXTURE_COORD_UNITS
)
120 return FRAG_ATTRIB_TEX0
+ (vertResult
- VERT_RESULT_TEX0
);
122 if (vertResult
>= VERT_RESULT_VAR0
&&
123 vertResult
< VERT_RESULT_VAR0
+ MAX_VARYING
)
124 return FRAG_ATTRIB_VAR0
+ (vertResult
- VERT_RESULT_VAR0
);
126 switch (vertResult
) {
127 case VERT_RESULT_HPOS
:
128 return FRAG_ATTRIB_WPOS
;
129 case VERT_RESULT_COL0
:
130 return FRAG_ATTRIB_COL0
;
131 case VERT_RESULT_COL1
:
132 return FRAG_ATTRIB_COL1
;
133 case VERT_RESULT_FOGC
:
134 return FRAG_ATTRIB_FOGC
;
136 /* Back-face colors, edge flags, etc */
143 * Find a translated vertex program that corresponds to stvp and
144 * has outputs matched to stfp's inputs.
145 * This performs vertex and fragment translation (to TGSI) when needed.
147 static struct translated_vertex_program
*
148 find_translated_vp(struct st_context
*st
,
149 struct st_vertex_program
*stvp
,
150 struct st_fragment_program
*stfp
)
152 static const GLuint UNUSED
= ~0;
153 struct translated_vertex_program
*xvp
;
154 const GLbitfield fragInputsRead
= stfp
->Base
.Base
.InputsRead
;
157 * Translate fragment program if needed.
160 GLuint inAttr
, numIn
= 0;
162 for (inAttr
= 0; inAttr
< FRAG_ATTRIB_MAX
; inAttr
++) {
163 if (fragInputsRead
& (1 << inAttr
)) {
164 stfp
->input_to_slot
[inAttr
] = numIn
;
168 stfp
->input_to_slot
[inAttr
] = UNUSED
;
172 stfp
->num_input_slots
= numIn
;
174 assert(stfp
->Base
.Base
.NumInstructions
> 1);
176 (void) st_translate_fragment_program(st
, stfp
,
179 ST_MAX_SHADER_TOKENS
);
184 /* See if we've got a translated vertex program whose outputs match
185 * the fragment program's inputs.
186 * XXX This could be a hash lookup, using InputsRead as the key.
188 for (xvp
= stfp
->vertex_programs
; xvp
; xvp
= xvp
->next
) {
189 if (xvp
->master
== stvp
&& xvp
->frag_inputs
== fragInputsRead
) {
194 /* No? Allocate translated vp object now */
196 xvp
= CALLOC_STRUCT(translated_vertex_program
);
197 xvp
->frag_inputs
= fragInputsRead
;
200 xvp
->next
= stfp
->vertex_programs
;
201 stfp
->vertex_programs
= xvp
;
204 /* See if we need to translate vertex program to TGSI form */
205 if (xvp
->serialNo
!= stvp
->serialNo
) {
206 GLuint outAttr
, dummySlot
;
207 const GLbitfield outputsWritten
= stvp
->Base
.Base
.OutputsWritten
;
208 GLuint numVpOuts
= 0;
210 /* Compute mapping of vertex program outputs to slots, which depends
211 * on the fragment program's input->slot mapping.
213 for (outAttr
= 0; outAttr
< VERT_RESULT_MAX
; outAttr
++) {
215 xvp
->output_to_slot
[outAttr
] = UNUSED
;
217 if (outAttr
== VERT_RESULT_HPOS
) {
218 /* always put xformed position into slot zero */
219 xvp
->output_to_slot
[VERT_RESULT_HPOS
] = 0;
222 else if (outputsWritten
& (1 << outAttr
)) {
223 /* see if the frag prog wants this vert output */
224 GLint fpInAttrib
= vp_out_to_fp_in(outAttr
);
225 if (fpInAttrib
>= 0) {
226 GLuint fpInSlot
= stfp
->input_to_slot
[fpInAttrib
];
227 GLuint vpOutSlot
= stfp
->fs
->state
.input_map
[fpInSlot
];
228 xvp
->output_to_slot
[outAttr
] = vpOutSlot
;
231 else if (outAttr
== VERT_RESULT_PSIZ
||
232 outAttr
== VERT_RESULT_BFC0
||
233 outAttr
== VERT_RESULT_BFC1
) {
234 /* backface colors go into last slots */
235 xvp
->output_to_slot
[outAttr
] = numVpOuts
++;
239 printf("output_to_slot[%d] = %d\n", outAttr,
240 xvp->output_to_slot[outAttr]);
244 /* Unneeded vertex program outputs will go to this slot.
245 * We could use this info to do dead code elimination in the
248 dummySlot
= stfp
->num_input_slots
;
250 /* Map vert program outputs that aren't used to the dummy slot */
251 for (outAttr
= 0; outAttr
< VERT_RESULT_MAX
; outAttr
++) {
252 if (outputsWritten
& (1 << outAttr
)) {
253 if (xvp
->output_to_slot
[outAttr
] == UNUSED
)
254 xvp
->output_to_slot
[outAttr
] = dummySlot
;
258 assert(stvp
->Base
.Base
.NumInstructions
> 1);
260 xvp
->vs
= st_translate_vertex_program(st
, stvp
,
263 ST_MAX_SHADER_TOKENS
);
265 stvp
->vs
= NULL
; /* don't want to use this */
267 /* translated VP is up to date now */
268 xvp
->serialNo
= stvp
->serialNo
;
276 update_linkage( struct st_context
*st
)
278 struct st_vertex_program
*stvp
;
279 struct st_fragment_program
*stfp
;
280 struct translated_vertex_program
*xvp
;
282 /* find active shader and params -- Should be covered by
283 * ST_NEW_VERTEX_PROGRAM
285 assert(st
->ctx
->VertexProgram
._Current
);
286 stvp
= st_vertex_program(st
->ctx
->VertexProgram
._Current
);
288 assert(st
->ctx
->FragmentProgram
._Current
);
289 stfp
= st_fragment_program(st
->ctx
->FragmentProgram
._Current
);
291 xvp
= find_translated_vp(st
, stvp
, stfp
);
294 st
->state
.vs
= xvp
->vs
;
295 st
->pipe
->bind_vs_state(st
->pipe
, st
->state
.vs
->data
);
298 st
->state
.fs
= stfp
->fs
;
299 st
->pipe
->bind_fs_state(st
->pipe
, st
->state
.fs
->data
);
301 st
->vertex_result_to_slot
= xvp
->output_to_slot
;
305 const struct st_tracked_state st_update_shader
= {
306 .name
= "st_update_shader",
309 .st
= ST_NEW_VERTEX_PROGRAM
| ST_NEW_FRAGMENT_PROGRAM
311 .update
= update_linkage