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