st_atom_shader.c revision a35c1ca3ad4361fee30d21ef13d8d37ae91aee66
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 "cso_cache/cso_context.h" 47 48#include "st_context.h" 49#include "st_atom.h" 50#include "st_program.h" 51#include "st_atom_shader.h" 52#include "st_mesa_to_tgsi.h" 53 54 55/** 56 * This represents a vertex program, especially translated to match 57 * the inputs of a particular fragment shader. 58 */ 59struct translated_vertex_program 60{ 61 struct st_vertex_program *master; 62 63 /** The fragment shader "signature" this vertex shader is meant for: */ 64 GLbitfield frag_inputs; 65 66 /** Compared against master vertex program's serialNo: */ 67 GLuint serialNo; 68 69 /** Maps VERT_RESULT_x to slot */ 70 GLuint output_to_slot[VERT_RESULT_MAX]; 71 72 /** Pointer to the translated vertex program */ 73 struct st_vertex_program *vp; 74 75 struct translated_vertex_program *next; /**< next in linked list */ 76}; 77 78 79 80/** 81 * Given a vertex program output attribute, return the corresponding 82 * fragment program input attribute. 83 * \return -1 for vertex outputs that have no corresponding fragment input 84 */ 85static GLint 86vp_out_to_fp_in(GLuint vertResult) 87{ 88 if (vertResult >= VERT_RESULT_TEX0 && 89 vertResult < VERT_RESULT_TEX0 + MAX_TEXTURE_COORD_UNITS) 90 return FRAG_ATTRIB_TEX0 + (vertResult - VERT_RESULT_TEX0); 91 92 if (vertResult >= VERT_RESULT_VAR0 && 93 vertResult < VERT_RESULT_VAR0 + MAX_VARYING) 94 return FRAG_ATTRIB_VAR0 + (vertResult - VERT_RESULT_VAR0); 95 96 switch (vertResult) { 97 case VERT_RESULT_HPOS: 98 return FRAG_ATTRIB_WPOS; 99 case VERT_RESULT_COL0: 100 return FRAG_ATTRIB_COL0; 101 case VERT_RESULT_COL1: 102 return FRAG_ATTRIB_COL1; 103 case VERT_RESULT_FOGC: 104 return FRAG_ATTRIB_FOGC; 105 default: 106 /* Back-face colors, edge flags, etc */ 107 return -1; 108 } 109} 110 111 112/** 113 * Find a translated vertex program that corresponds to stvp and 114 * has outputs matched to stfp's inputs. 115 * This performs vertex and fragment translation (to TGSI) when needed. 116 */ 117static struct translated_vertex_program * 118find_translated_vp(struct st_context *st, 119 struct st_vertex_program *stvp, 120 struct st_fragment_program *stfp) 121{ 122 static const GLuint UNUSED = ~0; 123 struct translated_vertex_program *xvp; 124 const GLbitfield fragInputsRead = stfp->Base.Base.InputsRead; 125 126 /* 127 * Translate fragment program if needed. 128 */ 129 if (!stfp->state.tokens) { 130 GLuint inAttr, numIn = 0; 131 132 for (inAttr = 0; inAttr < FRAG_ATTRIB_MAX; inAttr++) { 133 if (fragInputsRead & (1 << inAttr)) { 134 stfp->input_to_slot[inAttr] = numIn; 135 numIn++; 136 } 137 else { 138 stfp->input_to_slot[inAttr] = UNUSED; 139 } 140 } 141 142 stfp->num_input_slots = numIn; 143 144 assert(stfp->Base.Base.NumInstructions > 1); 145 146 st_translate_fragment_program(st, stfp, stfp->input_to_slot); 147 } 148 149 150 /* See if we've got a translated vertex program whose outputs match 151 * the fragment program's inputs. 152 * XXX This could be a hash lookup, using InputsRead as the key. 153 */ 154 for (xvp = stfp->vertex_programs; xvp; xvp = xvp->next) { 155 if (xvp->master == stvp && xvp->frag_inputs == fragInputsRead) { 156 break; 157 } 158 } 159 160 /* No? Allocate translated vp object now */ 161 if (!xvp) { 162 xvp = CALLOC_STRUCT(translated_vertex_program); 163 xvp->frag_inputs = fragInputsRead; 164 xvp->master = stvp; 165 166 xvp->next = stfp->vertex_programs; 167 stfp->vertex_programs = xvp; 168 } 169 170 /* See if we need to translate vertex program to TGSI form */ 171 if (xvp->serialNo != stvp->serialNo) { 172 GLuint outAttr, dummySlot; 173 const GLbitfield outputsWritten = stvp->Base.Base.OutputsWritten; 174 GLuint numVpOuts = 0; 175 176 /* Compute mapping of vertex program outputs to slots, which depends 177 * on the fragment program's input->slot mapping. 178 */ 179 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { 180 /* set default: */ 181 xvp->output_to_slot[outAttr] = UNUSED; 182 183 if (outAttr == VERT_RESULT_HPOS) { 184 /* always put xformed position into slot zero */ 185 xvp->output_to_slot[VERT_RESULT_HPOS] = 0; 186 numVpOuts++; 187 } 188 else if (outputsWritten & (1 << outAttr)) { 189 /* see if the frag prog wants this vert output */ 190 GLint fpInAttrib = vp_out_to_fp_in(outAttr); 191 if (fpInAttrib >= 0) { 192 GLuint fpInSlot = stfp->input_to_slot[fpInAttrib]; 193 if (fpInSlot != ~0) { 194 GLuint vpOutSlot = stfp->input_map[fpInSlot]; 195 xvp->output_to_slot[outAttr] = vpOutSlot; 196 numVpOuts++; 197 } 198 } 199 else if (outAttr == VERT_RESULT_PSIZ || 200 outAttr == VERT_RESULT_BFC0 || 201 outAttr == VERT_RESULT_BFC1) { 202 /* backface colors go into last slots */ 203 xvp->output_to_slot[outAttr] = numVpOuts++; 204 } 205 } 206 /* 207 printf("output_to_slot[%d] = %d\n", outAttr, 208 xvp->output_to_slot[outAttr]); 209 */ 210 } 211 212 /* Unneeded vertex program outputs will go to this slot. 213 * We could use this info to do dead code elimination in the 214 * vertex program. 215 */ 216 dummySlot = numVpOuts; 217 218 /* Map vert program outputs that aren't used to the dummy slot */ 219 for (outAttr = 0; outAttr < VERT_RESULT_MAX; outAttr++) { 220 if (outputsWritten & (1 << outAttr)) { 221 if (xvp->output_to_slot[outAttr] == UNUSED) 222 xvp->output_to_slot[outAttr] = dummySlot; 223 } 224 } 225 226 assert(stvp->Base.Base.NumInstructions > 1); 227 228 st_translate_vertex_program(st, stvp, xvp->output_to_slot); 229 230 xvp->vp = stvp; 231 232 /* translated VP is up to date now */ 233 xvp->serialNo = stvp->serialNo; 234 } 235 236 return xvp; 237} 238 239 240void 241st_free_translated_vertex_programs(struct st_context *st, 242 struct translated_vertex_program *xvp) 243{ 244 struct translated_vertex_program *next; 245 246 while (xvp) { 247 next = xvp->next; 248 free(xvp); 249 xvp = next; 250 } 251} 252 253 254 255static void 256update_linkage( struct st_context *st ) 257{ 258 struct st_vertex_program *stvp; 259 struct st_fragment_program *stfp; 260 struct translated_vertex_program *xvp; 261 262 /* find active shader and params -- Should be covered by 263 * ST_NEW_VERTEX_PROGRAM 264 */ 265 assert(st->ctx->VertexProgram._Current); 266 stvp = st_vertex_program(st->ctx->VertexProgram._Current); 267 268 assert(st->ctx->FragmentProgram._Current); 269 stfp = st_fragment_program(st->ctx->FragmentProgram._Current); 270 271 xvp = find_translated_vp(st, stvp, stfp); 272 273 st->vp = stvp; 274 st->fp = stfp; 275 276 st->pipe->bind_vs_state(st->pipe, stvp->driver_shader); 277 st->pipe->bind_fs_state(st->pipe, stfp->driver_shader); 278 279 st->vertex_result_to_slot = xvp->output_to_slot; 280} 281 282 283const struct st_tracked_state st_update_shader = { 284 .name = "st_update_shader", 285 .dirty = { 286 .mesa = 0, 287 .st = ST_NEW_VERTEX_PROGRAM | ST_NEW_FRAGMENT_PROGRAM 288 }, 289 .update = update_linkage 290}; 291