draw_pt_fetch_emit.c revision 49becd2d7c751e563ce6be9051dd8e6dad88d1f7
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 /*
29  * Authors:
30  *   Keith Whitwell <keith@tungstengraphics.com>
31  */
32
33#include "pipe/p_util.h"
34#include "draw/draw_context.h"
35#include "draw/draw_private.h"
36#include "draw/draw_vbuf.h"
37#include "draw/draw_vertex.h"
38#include "draw/draw_pt.h"
39
40/* The simplest 'middle end' in the new vertex code.
41 *
42 * The responsibilities of a middle end are to:
43 *  - perform vertex fetch using
44 *       - draw vertex element/buffer state
45 *       - a list of fetch indices we received as an input
46 *  - run the vertex shader
47 *  - cliptest,
48 *  - clip coord calculation
49 *  - viewport transformation
50 *  - if necessary, run the primitive pipeline, passing it:
51 *       - a linear array of vertex_header vertices constructed here
52 *       - a set of draw indices we received as an input
53 *  - otherwise, drive the hw backend,
54 *       - allocate space for hardware format vertices
55 *       - translate the vertex-shader output vertices to hw format
56 *       - calling the backend draw functions.
57 *
58 * For convenience, we provide a helper function to drive the hardware
59 * backend given similar inputs to those required to run the pipeline.
60 *
61 * In the case of passthrough mode, many of these actions are disabled
62 * or noops, so we end up doing:
63 *
64 *  - perform vertex fetch
65 *  - drive the hw backend
66 *
67 * IE, basically just vertex fetch to post-vs-format vertices,
68 * followed by a call to the backend helper function.
69 */
70
71
72struct fetch_emit_middle_end {
73   struct draw_pt_middle_end base;
74   struct draw_context *draw;
75
76   struct {
77      const ubyte *ptr;
78      unsigned pitch;
79      void (*fetch)( const void *from, float *attrib);
80      void (*emit)( const float *attrib, float **out );
81   } fetch[PIPE_MAX_ATTRIBS];
82
83   unsigned nr_fetch;
84   unsigned hw_vertex_size;
85};
86
87
88
89static void fetch_R32_FLOAT( const void *from,
90                             float *attrib )
91{
92   float *f = (float *) from;
93   attrib[0] = f[0];
94   attrib[1] = 0.0;
95   attrib[2] = 0.0;
96   attrib[3] = 1.0;
97}
98
99
100static void emit_R32_FLOAT( const float *attrib,
101                            float **out )
102{
103   (*out)[0] = attrib[0];
104   (*out) += 1;
105}
106
107static void emit_R32G32_FLOAT( const float *attrib,
108                               float **out )
109{
110   (*out)[0] = attrib[0];
111   (*out)[1] = attrib[1];
112   (*out) += 2;
113}
114
115static void emit_R32G32B32_FLOAT( const float *attrib,
116                                  float **out )
117{
118   (*out)[0] = attrib[0];
119   (*out)[1] = attrib[1];
120   (*out)[2] = attrib[2];
121   (*out) += 3;
122}
123
124static void emit_R32G32B32A32_FLOAT( const float *attrib,
125                                     float **out )
126{
127   (*out)[0] = attrib[0];
128   (*out)[1] = attrib[1];
129   (*out)[2] = attrib[2];
130   (*out)[3] = attrib[3];
131   (*out) += 4;
132}
133
134
135/**
136 * General-purpose fetch from user's vertex arrays, emit to driver's
137 * vertex buffer.
138 *
139 * XXX this is totally temporary.
140 */
141static void
142fetch_store_general( struct fetch_emit_middle_end *feme,
143                     void *out_ptr,
144                     const unsigned *fetch_elts,
145                     unsigned count )
146{
147   float *out = (float *)out_ptr;
148   uint i, j;
149
150   for (i = 0; i < count; i++) {
151      unsigned elt = fetch_elts[i] & ~DRAW_PT_FLAG_MASK;
152
153      for (j = 0; j < feme->nr_fetch; j++) {
154         float attrib[4];
155         const ubyte *from = (feme->fetch[j].ptr +
156                              feme->fetch[j].pitch * elt);
157
158         feme->fetch[j].fetch( from, attrib );
159         feme->fetch[j].emit( attrib, &out );
160      }
161   }
162}
163
164
165
166static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
167                                unsigned prim,
168				unsigned opt )
169{
170   struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
171   struct draw_context *draw = feme->draw;
172   const struct vertex_info *vinfo;
173   unsigned i;
174   boolean ok;
175
176
177   ok = draw->render->set_primitive( draw->render,
178                                     prim );
179   if (!ok) {
180      assert(0);
181      return;
182   }
183
184   /* Must do this after set_primitive() above:
185    */
186   vinfo = draw->render->get_vertex_info(draw->render);
187
188
189   /* This is unique as it transforms straight from API vertex
190    * information to HW vertices.  All other cases go through our
191    * intermediate float[4] format.
192    */
193   for (i = 0; i < vinfo->num_attribs; i++) {
194      unsigned src_element = vinfo->src_index[i];
195      unsigned src_buffer = draw->vertex_element[src_element].vertex_buffer_index;
196
197      feme->fetch[i].ptr = ((const ubyte *)draw->user.vbuffer[src_buffer] +
198                            draw->vertex_buffer[src_buffer].buffer_offset +
199                            draw->vertex_element[src_element].src_offset);
200
201      feme->fetch[i].pitch = draw->vertex_buffer[src_buffer].pitch;
202
203      feme->fetch[i].fetch = draw_get_fetch_func(draw->vertex_element[src_element].src_format);
204
205
206      switch (vinfo->emit[i]) {
207      case EMIT_4F:
208         feme->fetch[i].emit = emit_R32G32B32A32_FLOAT;
209         break;
210      case EMIT_3F:
211         feme->fetch[i].emit = emit_R32G32B32_FLOAT;
212         break;
213      case EMIT_2F:
214         feme->fetch[i].emit = emit_R32G32_FLOAT;
215         break;
216      case EMIT_1F:
217         feme->fetch[i].emit = emit_R32_FLOAT;
218         break;
219      case EMIT_1F_PSIZE:
220         feme->fetch[i].ptr = (const ubyte *)&feme->draw->rasterizer->point_size;
221         feme->fetch[i].pitch = 0;
222         feme->fetch[i].fetch = fetch_R32_FLOAT;
223         feme->fetch[i].emit = emit_R32_FLOAT;
224         break;
225      default:
226         assert(0);
227         feme->fetch[i].emit = NULL;
228         break;
229      }
230   }
231
232   feme->nr_fetch = vinfo->num_attribs;
233   feme->hw_vertex_size = vinfo->size * 4;
234}
235
236
237
238
239
240static void fetch_emit_run( struct draw_pt_middle_end *middle,
241                            const unsigned *fetch_elts,
242                            unsigned fetch_count,
243                            const ushort *draw_elts,
244                            unsigned draw_count )
245{
246   struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
247   struct draw_context *draw = feme->draw;
248   void *hw_verts;
249
250   /* XXX: need to flush to get prim_vbuf.c to release its allocation??
251    */
252   draw_do_flush( draw, DRAW_FLUSH_BACKEND );
253
254   hw_verts = draw->render->allocate_vertices( draw->render,
255                                               (ushort)feme->hw_vertex_size,
256                                               (ushort)fetch_count );
257   if (!hw_verts) {
258      assert(0);
259      return;
260   }
261
262
263   /* Single routine to fetch vertices and emit HW verts.
264    */
265   fetch_store_general( feme,
266                        hw_verts,
267                        fetch_elts,
268                        fetch_count );
269
270   /* XXX: Draw arrays path to avoid re-emitting index list again and
271    * again.
272    */
273   draw->render->draw( draw->render,
274                       draw_elts,
275                       draw_count );
276
277   /* Done -- that was easy, wasn't it:
278    */
279   draw->render->release_vertices( draw->render,
280                                   hw_verts,
281                                   feme->hw_vertex_size,
282                                   fetch_count );
283
284}
285
286
287
288static void fetch_emit_finish( struct draw_pt_middle_end *middle )
289{
290   /* nothing to do */
291}
292
293static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
294{
295   FREE(middle);
296}
297
298
299struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
300{
301   struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end );
302
303   fetch_emit->base.prepare = fetch_emit_prepare;
304   fetch_emit->base.run     = fetch_emit_run;
305   fetch_emit->base.finish  = fetch_emit_finish;
306   fetch_emit->base.destroy = fetch_emit_destroy;
307
308   fetch_emit->draw = draw;
309
310   return &fetch_emit->base;
311}
312
313