st_atom_shader.c revision fa0f48504a32642d688d4b81f62eea54c693b23f
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#include "main/macros.h" 43#include "shader/program.h" 44 45#include "pipe/p_context.h" 46#include "pipe/p_shader_tokens.h" 47 48#include "util/u_simple_shaders.h" 49 50#include "cso_cache/cso_context.h" 51 52#include "st_context.h" 53#include "st_atom.h" 54#include "st_program.h" 55#include "st_atom_shader.h" 56#include "st_mesa_to_tgsi.h" 57 58 59/** 60 * This represents a vertex program, especially translated to match 61 * the inputs of a particular fragment shader. 62 */ 63struct translated_vertex_program 64{ 65 struct st_vertex_program *master; 66 67 /** The fragment shader "signature" this vertex shader is meant for: */ 68 GLbitfield frag_inputs; 69 70 /** Compared against master vertex program's serialNo: */ 71 GLuint serialNo; 72 73 /** Maps VERT_RESULT_x to slot */ 74 GLuint output_to_slot[VERT_RESULT_MAX]; 75 ubyte output_to_semantic_name[VERT_RESULT_MAX]; 76 ubyte output_to_semantic_index[VERT_RESULT_MAX]; 77 78 /** Pointer to the translated vertex program */ 79 struct st_vertex_program *vp; 80 81 struct translated_vertex_program *next; /**< next in linked list */ 82}; 83 84 85 86/** 87 * Given a vertex program output attribute, return the corresponding 88 * fragment program input attribute. 89 * \return -1 for vertex outputs that have no corresponding fragment input 90 */ 91static GLint 92vp_out_to_fp_in(GLuint vertResult) 93{ 94 if (vertResult >= VERT_RESULT_TEX0 && 95 vertResult < VERT_RESULT_TEX0 + MAX_TEXTURE_COORD_UNITS) 96 return FRAG_ATTRIB_TEX0 + (vertResult - VERT_RESULT_TEX0); 97 98 if (vertResult >= VERT_RESULT_VAR0 && 99 vertResult < VERT_RESULT_VAR0 + MAX_VARYING) 100 return FRAG_ATTRIB_VAR0 + (vertResult - VERT_RESULT_VAR0); 101 102 switch (vertResult) { 103 case VERT_RESULT_HPOS: 104 return FRAG_ATTRIB_WPOS; 105 case VERT_RESULT_COL0: 106 return FRAG_ATTRIB_COL0; 107 case VERT_RESULT_COL1: 108 return FRAG_ATTRIB_COL1; 109 case VERT_RESULT_FOGC: 110 return FRAG_ATTRIB_FOGC; 111 default: 112 /* Back-face colors, edge flags, etc */ 113 return -1; 114 } 115} 116 117 118/** 119 * Find a translated vertex program that corresponds to stvp and 120 * has outputs matched to stfp's inputs. 121 * This performs vertex and fragment translation (to TGSI) when needed. 122 */ 123static struct translated_vertex_program * 124find_translated_vp(struct st_context *st, 125 struct st_vertex_program *stvp, 126 struct st_fragment_program *stfp) 127{ 128 static const GLuint UNUSED = ~0; 129 struct translated_vertex_program *xvp; 130 const GLbitfield fragInputsRead = stfp->Base.Base.InputsRead; 131 132 /* 133 * Translate fragment program if needed. 134 */ 135 if (!stfp->state.tokens) { 136 GLuint inAttr, numIn = 0; 137 138 for (inAttr = 0; inAttr < FRAG_ATTRIB_MAX; inAttr++) { 139 if (fragInputsRead & (1 << inAttr)) { 140 stfp->input_to_slot[inAttr] = numIn; 141 numIn++; 142 } 143 else { 144 stfp->input_to_slot[inAttr] = UNUSED; 145 } 146 } 147 148 stfp->num_input_slots = numIn; 149 150 assert(stfp->Base.Base.NumInstructions > 1); 151 152 st_translate_fragment_program(st, stfp, stfp->input_to_slot); 153 } 154 155 156 /* See if we've got a translated vertex program whose outputs match 157 * the fragment program's inputs. 158 * XXX This could be a hash lookup, using InputsRead as the key. 159 */ 160 for (xvp = stfp->vertex_programs; xvp; xvp = xvp->next) { 161 if (xvp->master == stvp && xvp->frag_inputs == fragInputsRead) { 162 break; 163 } 164 } 165 166 /* No? Allocate translated vp object now */ 167 if (!xvp) { 168 xvp = ST_CALLOC_STRUCT(translated_vertex_program); 169 xvp->frag_inputs = fragInputsRead; 170 xvp->master = stvp; 171 172 xvp->next = stfp->vertex_programs; 173 stfp->vertex_programs = xvp; 174 } 175 176 /* See if we need to translate vertex program to TGSI form */ 177 if (xvp->serialNo != stvp->serialNo) { 178 GLuint outAttr, dummySlot; 179 const GLbitfield outputsWritten = stvp->Base.Base.OutputsWritten; 180 GLuint numVpOuts = 0; 181 GLboolean emitPntSize = GL_FALSE, emitBFC0 = GL_FALSE, emitBFC1 = GL_FALSE; 182 GLint maxGeneric; 183 184 /* Compute mapping of vertex program outputs to slots, which depends 185 * on the fragment program's input->slot mapping. 186 */ 187 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { 188 /* set defaults: */ 189 xvp->output_to_slot[outAttr] = UNUSED; 190 xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_COUNT; 191 xvp->output_to_semantic_index[outAttr] = 99; 192 193 if (outAttr == VERT_RESULT_HPOS) { 194 /* always put xformed position into slot zero */ 195 xvp->output_to_slot[VERT_RESULT_HPOS] = 0; 196 xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_POSITION; 197 xvp->output_to_semantic_index[outAttr] = 0; 198 numVpOuts++; 199 } 200 else if (outputsWritten & (1 << outAttr)) { 201 /* see if the frag prog wants this vert output */ 202 GLint fpInAttrib = vp_out_to_fp_in(outAttr); 203 if (fpInAttrib >= 0) { 204 GLuint fpInSlot = stfp->input_to_slot[fpInAttrib]; 205 if (fpInSlot != ~0) { 206 /* match this vp output to the fp input */ 207 GLuint vpOutSlot = stfp->input_map[fpInSlot]; 208 xvp->output_to_slot[outAttr] = vpOutSlot; 209 xvp->output_to_semantic_name[outAttr] = stfp->input_semantic_name[fpInSlot]; 210 xvp->output_to_semantic_index[outAttr] = stfp->input_semantic_index[fpInSlot]; 211 numVpOuts++; 212 } 213 } 214 else if (outAttr == VERT_RESULT_PSIZ) 215 emitPntSize = GL_TRUE; 216 else if (outAttr == VERT_RESULT_BFC0) 217 emitBFC0 = GL_TRUE; 218 else if (outAttr == VERT_RESULT_BFC1) 219 emitBFC1 = GL_TRUE; 220 } 221#if 0 /*debug*/ 222 printf("assign vp output_to_slot[%d] = %d\n", outAttr, 223 xvp->output_to_slot[outAttr]); 224#endif 225 } 226 227 /* must do these last */ 228 if (emitPntSize) { 229 xvp->output_to_slot[VERT_RESULT_PSIZ] = numVpOuts++; 230 xvp->output_to_semantic_name[VERT_RESULT_PSIZ] = TGSI_SEMANTIC_PSIZE; 231 xvp->output_to_semantic_index[VERT_RESULT_PSIZ] = 0; 232 } 233 if (emitBFC0) { 234 xvp->output_to_slot[VERT_RESULT_BFC0] = numVpOuts++; 235 xvp->output_to_semantic_name[VERT_RESULT_BFC0] = TGSI_SEMANTIC_COLOR; 236 xvp->output_to_semantic_index[VERT_RESULT_BFC0] = 0; 237 } 238 if (emitBFC1) { 239 xvp->output_to_slot[VERT_RESULT_BFC1] = numVpOuts++; 240 xvp->output_to_semantic_name[VERT_RESULT_BFC0] = TGSI_SEMANTIC_COLOR; 241 xvp->output_to_semantic_index[VERT_RESULT_BFC0] = 1; 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 = numVpOuts; 249 250 /* find max GENERIC slot index */ 251 maxGeneric = -1; 252 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { 253 if (xvp->output_to_semantic_name[outAttr] == TGSI_SEMANTIC_GENERIC) { 254 maxGeneric = MAX2(maxGeneric, 255 xvp->output_to_semantic_index[outAttr]); 256 } 257 } 258 259 /* Map vert program outputs that aren't used to the dummy slot 260 * (and an unused generic attribute slot). 261 */ 262 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { 263 if (outputsWritten & (1 << outAttr)) { 264 if (xvp->output_to_slot[outAttr] == UNUSED) { 265 xvp->output_to_slot[outAttr] = dummySlot; 266 xvp->output_to_semantic_name[outAttr] = TGSI_SEMANTIC_GENERIC; 267 xvp->output_to_semantic_index[outAttr] = maxGeneric + 1; 268 } 269 } 270 271#if 0 /*debug*/ 272 printf("vp output_to_slot[%d] = %d\n", outAttr, 273 xvp->output_to_slot[outAttr]); 274#endif 275 } 276 277 assert(stvp->Base.Base.NumInstructions > 1); 278 279 st_translate_vertex_program(st, stvp, xvp->output_to_slot, 280 xvp->output_to_semantic_name, 281 xvp->output_to_semantic_index); 282 283 xvp->vp = stvp; 284 285 /* translated VP is up to date now */ 286 xvp->serialNo = stvp->serialNo; 287 } 288 289 return xvp; 290} 291 292 293void 294st_free_translated_vertex_programs(struct st_context *st, 295 struct translated_vertex_program *xvp) 296{ 297 struct translated_vertex_program *next; 298 299 while (xvp) { 300 next = xvp->next; 301 _mesa_free(xvp); 302 xvp = next; 303 } 304} 305 306 307static void * 308get_passthrough_fs(struct st_context *st) 309{ 310 if (!st->passthrough_fs) { 311 st->passthrough_fs = 312 util_make_fragment_passthrough_shader(st->pipe); 313 } 314 315 return st->passthrough_fs; 316} 317 318 319static void 320update_linkage( struct st_context *st ) 321{ 322 struct st_vertex_program *stvp; 323 struct st_fragment_program *stfp; 324 struct translated_vertex_program *xvp; 325 326 /* find active shader and params -- Should be covered by 327 * ST_NEW_VERTEX_PROGRAM 328 */ 329 assert(st->ctx->VertexProgram._Current); 330 stvp = st_vertex_program(st->ctx->VertexProgram._Current); 331 assert(stvp->Base.Base.Target == GL_VERTEX_PROGRAM_ARB); 332 333 assert(st->ctx->FragmentProgram._Current); 334 stfp = st_fragment_program(st->ctx->FragmentProgram._Current); 335 assert(stfp->Base.Base.Target == GL_FRAGMENT_PROGRAM_ARB); 336 337 xvp = find_translated_vp(st, stvp, stfp); 338 339 st_reference_vertprog(st, &st->vp, stvp); 340 st_reference_fragprog(st, &st->fp, stfp); 341 342 cso_set_vertex_shader_handle(st->cso_context, stvp->driver_shader); 343 344 if (st->missing_textures) { 345 /* use a pass-through frag shader that uses no textures */ 346 void *fs = get_passthrough_fs(st); 347 cso_set_fragment_shader_handle(st->cso_context, fs); 348 } 349 else { 350 cso_set_fragment_shader_handle(st->cso_context, stfp->driver_shader); 351 } 352 353 st->vertex_result_to_slot = xvp->output_to_slot; 354} 355 356 357const struct st_tracked_state st_update_shader = { 358 "st_update_shader", /* name */ 359 { /* dirty */ 360 0, /* mesa */ 361 ST_NEW_VERTEX_PROGRAM | ST_NEW_FRAGMENT_PROGRAM /* st */ 362 }, 363 update_linkage /* update */ 364}; 365