0806076956d9ce5cb8c9a3e1b23b0d7baf03ee7e
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_emit.c
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
72 struct 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
89 static 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
100 static void emit_R32_FLOAT( const float *attrib,
101 float **out )
102 {
103 (*out)[0] = attrib[0];
104 (*out) += 1;
105 }
106
107 static 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
115 static 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
124 static 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 */
141 static void
142 fetch_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 struct vbuf_render *render = feme->draw->render;
149 uint i, j;
150
151 for (i = 0; i < count; i++) {
152 unsigned elt = fetch_elts[i] & ~DRAW_PT_FLAG_MASK;
153
154 for (j = 0; j < feme->nr_fetch; j++) {
155 float attrib[4];
156 const ubyte *from = (feme->fetch[j].ptr +
157 feme->fetch[j].pitch * elt);
158
159 feme->fetch[j].fetch( from, attrib );
160 feme->fetch[j].emit( attrib, &out );
161 }
162 }
163 }
164
165
166
167 static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
168 unsigned prim )
169 {
170 static const float zero = 0;
171 struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
172 struct draw_context *draw = feme->draw;
173 const struct vertex_info *vinfo;
174 unsigned i;
175 boolean ok;
176
177
178 ok = draw->render->set_primitive( draw->render,
179 prim );
180 if (!ok) {
181 assert(0);
182 return;
183 }
184
185 /* Must do this after set_primitive() above:
186 */
187 vinfo = draw->render->get_vertex_info(draw->render);
188
189 for (i = 0; i < vinfo->num_attribs; i++) {
190 unsigned src_element = vinfo->src_index[i];
191 unsigned src_buffer = draw->vertex_element[src_element].vertex_buffer_index;
192
193 feme->fetch[i].ptr = ((const ubyte *)draw->user.vbuffer[src_buffer] +
194 draw->vertex_buffer[src_buffer].buffer_offset +
195 draw->vertex_element[src_element].src_offset);
196
197 feme->fetch[i].pitch = draw->vertex_buffer[src_buffer].pitch;
198
199 feme->fetch[i].fetch = draw_get_fetch_func(draw->vertex_element[src_element].src_format);
200
201
202 switch (vinfo->emit[i]) {
203 case EMIT_4F:
204 feme->fetch[i].emit = emit_R32G32B32A32_FLOAT;
205 break;
206 case EMIT_3F:
207 feme->fetch[i].emit = emit_R32G32B32_FLOAT;
208 break;
209 case EMIT_2F:
210 feme->fetch[i].emit = emit_R32G32_FLOAT;
211 break;
212 case EMIT_1F:
213 feme->fetch[i].emit = emit_R32_FLOAT;
214 break;
215 case EMIT_HEADER:
216 feme->fetch[i].ptr = (const ubyte *)&zero;
217 feme->fetch[i].pitch = 0;
218 feme->fetch[i].fetch = fetch_R32_FLOAT;
219 feme->fetch[i].emit = emit_R32_FLOAT;
220 break;
221 case EMIT_1F_PSIZE:
222 feme->fetch[i].ptr = (const ubyte *)&feme->draw->rasterizer->point_size;
223 feme->fetch[i].pitch = 0;
224 feme->fetch[i].fetch = fetch_R32_FLOAT;
225 feme->fetch[i].emit = emit_R32_FLOAT;
226 break;
227 default:
228 assert(0);
229 feme->fetch[i].emit = NULL;
230 break;
231 }
232 }
233
234 feme->nr_fetch = vinfo->num_attribs;
235 feme->hw_vertex_size = vinfo->size * 4;
236 }
237
238
239
240
241
242 static void fetch_emit_run( struct draw_pt_middle_end *middle,
243 const unsigned *fetch_elts,
244 unsigned fetch_count,
245 const ushort *draw_elts,
246 unsigned draw_count )
247 {
248 struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
249 struct draw_context *draw = feme->draw;
250 void *hw_verts;
251
252 hw_verts = draw->render->allocate_vertices( draw->render,
253 (ushort)feme->hw_vertex_size,
254 (ushort)fetch_count );
255 if (!hw_verts) {
256 assert(0);
257 return;
258 }
259
260
261 /* Single routine to fetch vertices and emit HW verts.
262 */
263 fetch_store_general( feme,
264 hw_verts,
265 fetch_elts,
266 fetch_count );
267
268 /* XXX: Draw arrays path to avoid re-emitting index list again and
269 * again.
270 */
271 draw->render->draw( draw->render,
272 draw_elts,
273 draw_count );
274
275 /* Done -- that was easy, wasn't it:
276 */
277 draw->render->release_vertices( draw->render,
278 hw_verts,
279 feme->hw_vertex_size,
280 fetch_count );
281
282 }
283
284
285
286 static void fetch_emit_finish( struct draw_pt_middle_end *middle )
287 {
288 /* nothing to do */
289 }
290
291 static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
292 {
293 FREE(middle);
294 }
295
296
297 struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
298 {
299 struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end );
300
301 fetch_emit->base.prepare = fetch_emit_prepare;
302 fetch_emit->base.run = fetch_emit_run;
303 fetch_emit->base.finish = fetch_emit_finish;
304 fetch_emit->base.destroy = fetch_emit_destroy;
305
306 fetch_emit->draw = draw;
307
308 return &fetch_emit->base;
309 }
310