draw_pt_fetch_shade_pipeline.c revision 543b9566bdaa48fea2df1866fa1310c1cdbcde27
1/**************************************************************************
2 *
3 * Copyright 2007 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#include "util/u_math.h"
29#include "util/u_memory.h"
30#include "draw/draw_context.h"
31#include "draw/draw_vbuf.h"
32#include "draw/draw_vertex.h"
33#include "draw/draw_pt.h"
34#include "draw/draw_vs.h"
35#include "translate/translate.h"
36
37
38struct fetch_pipeline_middle_end {
39   struct draw_pt_middle_end base;
40   struct draw_context *draw;
41
42   struct pt_emit *emit;
43   struct pt_fetch *fetch;
44   struct pt_post_vs *post_vs;
45
46   unsigned vertex_data_offset;
47   unsigned vertex_size;
48   unsigned prim;
49   unsigned opt;
50};
51
52
53static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
54                                    unsigned prim,
55				    unsigned opt,
56                                    unsigned *max_vertices )
57{
58   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
59   struct draw_context *draw = fpme->draw;
60   struct draw_vertex_shader *vs = draw->vs.vertex_shader;
61   unsigned i;
62   boolean instance_id_index = ~0;
63
64   /* Add one to num_outputs because the pipeline occasionally tags on
65    * an additional texcoord, eg for AA lines.
66    */
67   unsigned nr = MAX2( vs->info.num_inputs,
68		       vs->info.num_outputs + 1 );
69
70   /* Scan for instanceID system value.
71    */
72   for (i = 0; i < vs->info.num_inputs; i++) {
73      if (vs->info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) {
74         instance_id_index = i;
75         break;
76      }
77   }
78
79   fpme->prim = prim;
80   fpme->opt = opt;
81
82   /* Always leave room for the vertex header whether we need it or
83    * not.  It's hard to get rid of it in particular because of the
84    * viewport code in draw_pt_post_vs.c.
85    */
86   fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
87
88
89
90   draw_pt_fetch_prepare( fpme->fetch,
91                          vs->info.num_inputs,
92                          fpme->vertex_size,
93                          instance_id_index );
94   /* XXX: it's not really gl rasterization rules we care about here,
95    * but gl vs dx9 clip spaces.
96    */
97   draw_pt_post_vs_prepare( fpme->post_vs,
98			    (boolean)draw->bypass_clipping,
99			    (boolean)(draw->identity_viewport ||
100			    draw->rasterizer->bypass_vs_clip_and_viewport),
101			    (boolean)draw->rasterizer->gl_rasterization_rules,
102			    (draw->vs.edgeflag_output ? true : false) );
103
104   if (!(opt & PT_PIPELINE)) {
105      draw_pt_emit_prepare( fpme->emit,
106			    prim,
107                            max_vertices );
108
109      *max_vertices = MAX2( *max_vertices,
110                            DRAW_PIPE_MAX_VERTICES );
111   }
112   else {
113      *max_vertices = DRAW_PIPE_MAX_VERTICES;
114   }
115
116   /* return even number */
117   *max_vertices = *max_vertices & ~1;
118
119   /* No need to prepare the shader.
120    */
121   vs->prepare(vs, draw);
122}
123
124
125
126static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
127                                const unsigned *fetch_elts,
128                                unsigned fetch_count,
129                                const ushort *draw_elts,
130                                unsigned draw_count )
131{
132   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
133   struct draw_context *draw = fpme->draw;
134   struct draw_vertex_shader *shader = draw->vs.vertex_shader;
135   unsigned opt = fpme->opt;
136   unsigned alloc_count = align( fetch_count, 4 );
137
138   struct vertex_header *pipeline_verts =
139      (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
140
141   if (!pipeline_verts) {
142      /* Not much we can do here - just skip the rendering.
143       */
144      assert(0);
145      return;
146   }
147
148   /* Fetch into our vertex buffer
149    */
150   draw_pt_fetch_run( fpme->fetch,
151		      fetch_elts,
152		      fetch_count,
153		      (char *)pipeline_verts );
154
155   /* Run the shader, note that this overwrites the data[] parts of
156    * the pipeline verts.  If there is no shader, eg if
157    * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
158    * already in the correct place.
159    */
160   if (opt & PT_SHADE)
161   {
162      shader->run_linear(shader,
163			 (const float (*)[4])pipeline_verts->data,
164			 (      float (*)[4])pipeline_verts->data,
165			 (const float (*)[4])draw->pt.user.constants,
166			 fetch_count,
167			 fpme->vertex_size,
168			 fpme->vertex_size);
169   }
170
171   if (draw_pt_post_vs_run( fpme->post_vs,
172			    pipeline_verts,
173			    fetch_count,
174			    fpme->vertex_size ))
175   {
176      opt |= PT_PIPELINE;
177   }
178
179   /* Do we need to run the pipeline?
180    */
181   if (opt & PT_PIPELINE) {
182      draw_pipeline_run( fpme->draw,
183                         fpme->prim,
184                         pipeline_verts,
185                         fetch_count,
186                         fpme->vertex_size,
187                         draw_elts,
188                         draw_count );
189   }
190   else {
191      draw_pt_emit( fpme->emit,
192		    (const float (*)[4])pipeline_verts->data,
193		    fetch_count,
194		    fpme->vertex_size,
195		    draw_elts,
196		    draw_count );
197   }
198
199
200   FREE(pipeline_verts);
201}
202
203
204static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
205                                       unsigned start,
206                                       unsigned count)
207{
208   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
209   struct draw_context *draw = fpme->draw;
210   struct draw_vertex_shader *shader = draw->vs.vertex_shader;
211   unsigned opt = fpme->opt;
212   unsigned alloc_count = align( count, 4 );
213
214   struct vertex_header *pipeline_verts =
215      (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
216
217   if (!pipeline_verts) {
218      /* Not much we can do here - just skip the rendering.
219       */
220      assert(0);
221      return;
222   }
223
224   /* Fetch into our vertex buffer
225    */
226   draw_pt_fetch_run_linear( fpme->fetch,
227                             start,
228                             count,
229                             (char *)pipeline_verts );
230
231   /* Run the shader, note that this overwrites the data[] parts of
232    * the pipeline verts.  If there is no shader, ie if
233    * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
234    * already in the correct place.
235    */
236   if (opt & PT_SHADE)
237   {
238      shader->run_linear(shader,
239			 (const float (*)[4])pipeline_verts->data,
240			 (      float (*)[4])pipeline_verts->data,
241			 (const float (*)[4])draw->pt.user.constants,
242			 count,
243			 fpme->vertex_size,
244			 fpme->vertex_size);
245   }
246
247   if (draw_pt_post_vs_run( fpme->post_vs,
248			    pipeline_verts,
249			    count,
250			    fpme->vertex_size ))
251   {
252      opt |= PT_PIPELINE;
253   }
254
255   /* Do we need to run the pipeline?
256    */
257   if (opt & PT_PIPELINE) {
258      draw_pipeline_run_linear( fpme->draw,
259                                fpme->prim,
260                                pipeline_verts,
261                                count,
262                                fpme->vertex_size);
263   }
264   else {
265      draw_pt_emit_linear( fpme->emit,
266                           (const float (*)[4])pipeline_verts->data,
267                           fpme->vertex_size,
268                           count );
269   }
270
271   FREE(pipeline_verts);
272}
273
274
275
276static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle,
277                                            unsigned start,
278                                            unsigned count,
279                                            const ushort *draw_elts,
280                                            unsigned draw_count )
281{
282   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
283   struct draw_context *draw = fpme->draw;
284   struct draw_vertex_shader *shader = draw->vs.vertex_shader;
285   unsigned opt = fpme->opt;
286   unsigned alloc_count = align( count, 4 );
287
288   struct vertex_header *pipeline_verts =
289      (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
290
291   if (!pipeline_verts)
292      return FALSE;
293
294   /* Fetch into our vertex buffer
295    */
296   draw_pt_fetch_run_linear( fpme->fetch,
297                             start,
298                             count,
299                             (char *)pipeline_verts );
300
301   /* Run the shader, note that this overwrites the data[] parts of
302    * the pipeline verts.  If there is no shader, ie if
303    * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
304    * already in the correct place.
305    */
306   if (opt & PT_SHADE)
307   {
308      shader->run_linear(shader,
309			 (const float (*)[4])pipeline_verts->data,
310			 (      float (*)[4])pipeline_verts->data,
311			 (const float (*)[4])draw->pt.user.constants,
312			 count,
313			 fpme->vertex_size,
314			 fpme->vertex_size);
315   }
316
317   if (draw_pt_post_vs_run( fpme->post_vs,
318			    pipeline_verts,
319			    count,
320			    fpme->vertex_size ))
321   {
322      opt |= PT_PIPELINE;
323   }
324
325   /* Do we need to run the pipeline?
326    */
327   if (opt & PT_PIPELINE) {
328      draw_pipeline_run( fpme->draw,
329                         fpme->prim,
330                         pipeline_verts,
331                         count,
332                         fpme->vertex_size,
333                         draw_elts,
334                         draw_count );
335   }
336   else {
337      draw_pt_emit( fpme->emit,
338		    (const float (*)[4])pipeline_verts->data,
339		    count,
340		    fpme->vertex_size,
341		    draw_elts,
342		    draw_count );
343   }
344
345   FREE(pipeline_verts);
346   return TRUE;
347}
348
349
350
351static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
352{
353   /* nothing to do */
354}
355
356static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle )
357{
358   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
359
360   if (fpme->fetch)
361      draw_pt_fetch_destroy( fpme->fetch );
362
363   if (fpme->emit)
364      draw_pt_emit_destroy( fpme->emit );
365
366   if (fpme->post_vs)
367      draw_pt_post_vs_destroy( fpme->post_vs );
368
369   FREE(middle);
370}
371
372
373struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw )
374{
375   struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end );
376   if (!fpme)
377      goto fail;
378
379   fpme->base.prepare        = fetch_pipeline_prepare;
380   fpme->base.run            = fetch_pipeline_run;
381   fpme->base.run_linear     = fetch_pipeline_linear_run;
382   fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
383   fpme->base.finish         = fetch_pipeline_finish;
384   fpme->base.destroy        = fetch_pipeline_destroy;
385
386   fpme->draw = draw;
387
388   fpme->fetch = draw_pt_fetch_create( draw );
389   if (!fpme->fetch)
390      goto fail;
391
392   fpme->post_vs = draw_pt_post_vs_create( draw );
393   if (!fpme->post_vs)
394      goto fail;
395
396   fpme->emit = draw_pt_emit_create( draw );
397   if (!fpme->emit)
398      goto fail;
399
400   return &fpme->base;
401
402 fail:
403   if (fpme)
404      fetch_pipeline_destroy( &fpme->base );
405
406   return NULL;
407}
408