st_atom_shader.c revision cedf6892e7cc29aab404b142012eec0b0603a414
1/************************************************************************** 2 * 3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * All Rights Reserved. 5 * 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: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 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. 25 * 26 **************************************************************************/ 27 28/** 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. 33 * 34 * Authors: 35 * Brian Paul 36 */ 37 38 39 40#include "main/imports.h" 41#include "main/mtypes.h" 42 43#include "pipe/p_context.h" 44#include "pipe/p_shader_tokens.h" 45 46#include "st_context.h" 47#include "st_cache.h" 48#include "st_atom.h" 49#include "st_program.h" 50#include "st_atom_shader.h" 51#include "st_mesa_to_tgsi.h" 52 53 54/** 55 * This represents a vertex program, especially translated to match 56 * the inputs of a particular fragment shader. 57 */ 58struct translated_vertex_program 59{ 60 struct st_vertex_program *master; 61 62 /** The fragment shader "signature" this vertex shader is meant for: */ 63 GLbitfield frag_inputs; 64 65 /** Compared against master vertex program's serialNo: */ 66 GLuint serialNo; 67 68 /** Maps VERT_RESULT_x to slot */ 69 GLuint output_to_slot[VERT_RESULT_MAX]; 70 71 /** The program in TGSI format */ 72 struct tgsi_token tokens[ST_MAX_SHADER_TOKENS]; 73 74 /** Pointer to the translated, cached vertex shader */ 75 const struct cso_vertex_shader *vs; 76 77 struct translated_vertex_program *next; /**< next in linked list */ 78}; 79 80 81 82/** 83 * Free data hanging off the st vert prog. 84 */ 85void 86st_remove_vertex_program(struct st_context *st, struct st_vertex_program *stvp) 87{ 88 /* no-op, for now? */ 89} 90 91 92/** 93 * Free data hanging off the st frag prog. 94 */ 95void 96st_remove_fragment_program(struct st_context *st, 97 struct st_fragment_program *stfp) 98{ 99 struct translated_vertex_program *xvp, *next; 100 101 for (xvp = stfp->vertex_programs; xvp; xvp = next) { 102 next = xvp->next; 103 /* XXX free xvp->vs */ 104 free(xvp); 105 } 106} 107 108 109 110/** 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 114 */ 115static GLint 116vp_out_to_fp_in(GLuint vertResult) 117{ 118 if (vertResult >= VERT_RESULT_TEX0 && 119 vertResult < VERT_RESULT_TEX0 + MAX_TEXTURE_COORD_UNITS) 120 return FRAG_ATTRIB_TEX0 + (vertResult - VERT_RESULT_TEX0); 121 122 if (vertResult >= VERT_RESULT_VAR0 && 123 vertResult < VERT_RESULT_VAR0 + MAX_VARYING) 124 return FRAG_ATTRIB_VAR0 + (vertResult - VERT_RESULT_VAR0); 125 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; 135 default: 136 /* Back-face colors, edge flags, etc */ 137 return -1; 138 } 139} 140 141 142/** 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. 146 */ 147static struct translated_vertex_program * 148find_translated_vp(struct st_context *st, 149 struct st_vertex_program *stvp, 150 struct st_fragment_program *stfp) 151{ 152 static const GLuint UNUSED = ~0; 153 struct translated_vertex_program *xvp; 154 const GLbitfield fragInputsRead = stfp->Base.Base.InputsRead; 155 156 /* 157 * Translate fragment program if needed. 158 */ 159 if (!stfp->fs) { 160 GLuint inAttr, numIn = 0; 161 162 for (inAttr = 0; inAttr < FRAG_ATTRIB_MAX; inAttr++) { 163 if (fragInputsRead & (1 << inAttr)) { 164 stfp->input_to_slot[inAttr] = numIn; 165 numIn++; 166 } 167 else { 168 stfp->input_to_slot[inAttr] = UNUSED; 169 } 170 } 171 172 stfp->num_input_slots = numIn; 173 174 assert(stfp->Base.Base.NumInstructions > 1); 175 176 (void) st_translate_fragment_program(st, stfp, 177 stfp->input_to_slot, 178 stfp->tokens, 179 ST_MAX_SHADER_TOKENS); 180 assert(stfp->fs); 181 } 182 183 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. 187 */ 188 for (xvp = stfp->vertex_programs; xvp; xvp = xvp->next) { 189 if (xvp->master == stvp && xvp->frag_inputs == fragInputsRead) { 190 break; 191 } 192 } 193 194 /* No? Allocate translated vp object now */ 195 if (!xvp) { 196 xvp = CALLOC_STRUCT(translated_vertex_program); 197 xvp->frag_inputs = fragInputsRead; 198 xvp->master = stvp; 199 200 xvp->next = stfp->vertex_programs; 201 stfp->vertex_programs = xvp; 202 } 203 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; 209 210 /* Compute mapping of vertex program outputs to slots, which depends 211 * on the fragment program's input->slot mapping. 212 */ 213 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { 214 /* set default: */ 215 xvp->output_to_slot[outAttr] = UNUSED; 216 217 if (outAttr == VERT_RESULT_HPOS) { 218 /* always put xformed position into slot zero */ 219 xvp->output_to_slot[VERT_RESULT_HPOS] = 0; 220 numVpOuts++; 221 } 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; 229 numVpOuts++; 230 } 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++; 236 } 237 } 238 /* 239 printf("output_to_slot[%d] = %d\n", outAttr, 240 xvp->output_to_slot[outAttr]); 241 */ 242 } 243 244 /* Unneeded vertex program outputs will go to this slot. 245 * We could use this info to do dead code elimination in the 246 * vertex program. 247 */ 248 dummySlot = stfp->num_input_slots; 249 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; 255 } 256 } 257 258 assert(stvp->Base.Base.NumInstructions > 1); 259 260 xvp->vs = st_translate_vertex_program(st, stvp, 261 xvp->output_to_slot, 262 xvp->tokens, 263 ST_MAX_SHADER_TOKENS); 264 assert(xvp->vs); 265 stvp->vs = NULL; /* don't want to use this */ 266 267 /* translated VP is up to date now */ 268 xvp->serialNo = stvp->serialNo; 269 } 270 271 return xvp; 272} 273 274 275static void 276update_linkage( struct st_context *st ) 277{ 278 struct st_vertex_program *stvp; 279 struct st_fragment_program *stfp; 280 struct translated_vertex_program *xvp; 281 282 /* find active shader and params -- Should be covered by 283 * ST_NEW_VERTEX_PROGRAM 284 */ 285 assert(st->ctx->VertexProgram._Current); 286 stvp = st_vertex_program(st->ctx->VertexProgram._Current); 287 288 assert(st->ctx->FragmentProgram._Current); 289 stfp = st_fragment_program(st->ctx->FragmentProgram._Current); 290 291 xvp = find_translated_vp(st, stvp, stfp); 292 293 st->vp = stvp; 294 st->state.vs = xvp->vs; 295 st->pipe->bind_vs_state(st->pipe, st->state.vs->data); 296 297 st->fp = stfp; 298 st->state.fs = stfp->fs; 299 st->pipe->bind_fs_state(st->pipe, st->state.fs->data); 300 301 st->vertex_result_to_slot = xvp->output_to_slot; 302} 303 304 305const struct st_tracked_state st_update_shader = { 306 .name = "st_update_shader", 307 .dirty = { 308 .mesa = 0, 309 .st = ST_NEW_VERTEX_PROGRAM | ST_NEW_FRAGMENT_PROGRAM 310 }, 311 .update = update_linkage 312}; 313