Merge remote branch 'upstream/gallium-0.2' into nouveau-gallium-0.2
[mesa.git] / src / gallium / drivers / nv04 / nv04_prim_vbuf.c
1
2 #include "pipe/p_debug.h"
3 #include "pipe/p_inlines.h"
4 #include "pipe/p_winsys.h"
5 #include "pipe/p_compiler.h"
6
7 #include "draw/draw_vbuf.h"
8
9 #include "nv04_context.h"
10 #include "nv04_state.h"
11
12 #define VERTEX_SIZE 40
13 #define VERTEX_BUFFER_SIZE (4096*VERTEX_SIZE) // 4096 vertices of 40 bytes each
14
15 /**
16 * Primitive renderer for nv04.
17 */
18 struct nv04_vbuf_render {
19 struct vbuf_render base;
20
21 struct nv04_context *nv04;
22
23 /** Vertex buffer */
24 unsigned char* buffer;
25
26 /** Vertex size in bytes */
27 unsigned vertex_size;
28
29 /** Current primitive */
30 unsigned prim;
31 };
32
33
34 /**
35 * Basically a cast wrapper.
36 */
37 static INLINE struct nv04_vbuf_render *
38 nv04_vbuf_render( struct vbuf_render *render )
39 {
40 assert(render);
41 return (struct nv04_vbuf_render *)render;
42 }
43
44
45 static const struct vertex_info *
46 nv04_vbuf_render_get_vertex_info( struct vbuf_render *render )
47 {
48 struct nv04_vbuf_render *nv04_render = nv04_vbuf_render(render);
49 struct nv04_context *nv04 = nv04_render->nv04;
50 return &nv04->vertex_info;
51 }
52
53
54 static void *
55 nv04_vbuf_render_allocate_vertices( struct vbuf_render *render,
56 ushort vertex_size,
57 ushort nr_vertices )
58 {
59 struct nv04_vbuf_render *nv04_render = nv04_vbuf_render(render);
60
61 nv04_render->buffer = (unsigned char*) MALLOC(VERTEX_BUFFER_SIZE);
62 assert(!nv04_render->buffer);
63
64 return nv04_render->buffer;
65 }
66
67
68 static boolean
69 nv04_vbuf_render_set_primitive( struct vbuf_render *render,
70 unsigned prim )
71 {
72 struct nv04_vbuf_render *nv04_render = nv04_vbuf_render(render);
73
74 if (prim <= PIPE_PRIM_LINE_STRIP)
75 return FALSE;
76
77 nv04_render->prim = prim;
78 return TRUE;
79 }
80
81 static INLINE void nv04_2triangles(struct nv04_context* nv04, unsigned char* buffer, ushort v0, ushort v1, ushort v2, ushort v3, ushort v4, ushort v5)
82 {
83 BEGIN_RING(fahrenheit,NV04_DX5_TEXTURED_TRIANGLE_TLVERTEX_SX(0xA),49);
84 OUT_RINGp(buffer + VERTEX_SIZE * v0,8);
85 OUT_RINGp(buffer + VERTEX_SIZE * v1,8);
86 OUT_RINGp(buffer + VERTEX_SIZE * v2,8);
87 OUT_RINGp(buffer + VERTEX_SIZE * v3,8);
88 OUT_RINGp(buffer + VERTEX_SIZE * v4,8);
89 OUT_RINGp(buffer + VERTEX_SIZE * v5,8);
90 OUT_RING(0xFEDCBA);
91 }
92
93 static INLINE void nv04_1triangle(struct nv04_context* nv04, unsigned char* buffer, ushort v0, ushort v1, ushort v2)
94 {
95 BEGIN_RING(fahrenheit,NV04_DX5_TEXTURED_TRIANGLE_TLVERTEX_SX(0xD),25);
96 OUT_RINGp(buffer + VERTEX_SIZE * v0,8);
97 OUT_RINGp(buffer + VERTEX_SIZE * v1,8);
98 OUT_RINGp(buffer + VERTEX_SIZE * v2,8);
99 OUT_RING(0xFED);
100 }
101
102 static INLINE void nv04_1quad(struct nv04_context* nv04, unsigned char* buffer, ushort v0, ushort v1, ushort v2, ushort v3)
103 {
104 BEGIN_RING(fahrenheit,NV04_DX5_TEXTURED_TRIANGLE_TLVERTEX_SX(0xC),33);
105 OUT_RINGp(buffer + VERTEX_SIZE * v0,8);
106 OUT_RINGp(buffer + VERTEX_SIZE * v1,8);
107 OUT_RINGp(buffer + VERTEX_SIZE * v2,8);
108 OUT_RINGp(buffer + VERTEX_SIZE * v3,8);
109 OUT_RING(0xFECEDC);
110 }
111
112 static void nv04_vbuf_render_triangles_elts(struct nv04_vbuf_render * render, const ushort * indices, uint nr_indices)
113 {
114 unsigned char* buffer = render->buffer;
115 struct nv04_context* nv04 = render->nv04;
116 int i;
117
118 for( i=0; i< nr_indices-5; i+=6)
119 nv04_2triangles(nv04,
120 buffer,
121 indices[i+0],
122 indices[i+1],
123 indices[i+2],
124 indices[i+3],
125 indices[i+4],
126 indices[i+5]
127 );
128 if (i != nr_indices)
129 {
130 nv04_1triangle(nv04,
131 buffer,
132 indices[i+0],
133 indices[i+1],
134 indices[i+2]
135 );
136 i+=3;
137 }
138 if (i != nr_indices)
139 NOUVEAU_ERR("Houston, we have lost some vertices\n");
140 }
141
142 static void nv04_vbuf_render_tri_strip_elts(struct nv04_vbuf_render* render, const ushort* indices, uint nr_indices)
143 {
144 const uint32_t striptbl[]={0x321210,0x543432,0x765654,0x987876,0xBA9A98,0xDCBCBA,0xFEDEDC};
145 unsigned char* buffer = render->buffer;
146 struct nv04_context* nv04 = render->nv04;
147 int i,j;
148
149 for(i = 0; i<nr_indices; i+=14)
150 {
151 int numvert = MIN2(16, nr_indices - i);
152 int numtri = numvert - 2;
153 if (numvert<3)
154 break;
155
156 BEGIN_RING( fahrenheit, NV04_DX5_TEXTURED_TRIANGLE_TLVERTEX_SX(0x0), numvert*8 );
157 for(j = 0; j<numvert; j++)
158 OUT_RINGp( buffer + VERTEX_SIZE * indices [i+j], 8 );
159
160 BEGIN_RING_NI( fahrenheit, NV04_DX5_TEXTURED_TRIANGLE_TLVERTEX_DRAWPRIMITIVE(0), (numtri+1)/2 );
161 for(j = 0; j<numtri/2; j++ )
162 OUT_RING(striptbl[j]);
163 if (numtri%2)
164 OUT_RING(striptbl[numtri/2]&0xFFF);
165 }
166 }
167
168 static void nv04_vbuf_render_tri_fan_elts(struct nv04_vbuf_render* render, const ushort* indices, uint nr_indices)
169 {
170 const uint32_t fantbl[]={0x320210,0x540430,0x760650,0x980870,0xBA0A90,0xDC0CB0,0xFE0ED0};
171 unsigned char* buffer = render->buffer;
172 struct nv04_context* nv04 = render->nv04;
173 int i,j;
174
175 BEGIN_RING(fahrenheit, NV04_DX5_TEXTURED_TRIANGLE_TLVERTEX_SX(0x0), 8);
176 OUT_RINGp(buffer + VERTEX_SIZE * indices[0], 8);
177
178 for(i = 1; i<nr_indices; i+=14)
179 {
180 int numvert=MIN2(15, nr_indices - i);
181 int numtri=numvert-2;
182 if (numvert < 3)
183 break;
184
185 BEGIN_RING(fahrenheit, NV04_DX5_TEXTURED_TRIANGLE_TLVERTEX_SX(0x1), numvert*8);
186
187 for(j=0;j<numvert;j++)
188 OUT_RINGp( buffer + VERTEX_SIZE * indices[ i+j ], 8 );
189
190 BEGIN_RING_NI(fahrenheit, NV04_DX5_TEXTURED_TRIANGLE_TLVERTEX_DRAWPRIMITIVE(0), (numtri+1)/2);
191 for(j = 0; j<numtri/2; j++)
192 OUT_RING(fantbl[j]);
193 if (numtri%2)
194 OUT_RING(fantbl[numtri/2]&0xFFF);
195 }
196 }
197
198 static void nv04_vbuf_render_quads_elts(struct nv04_vbuf_render* render, const ushort* indices, uint nr_indices)
199 {
200 unsigned char* buffer = render->buffer;
201 struct nv04_context* nv04 = render->nv04;
202 int i;
203
204 for(i = 0; i < nr_indices; i += 4)
205 nv04_1quad(nv04,
206 buffer,
207 indices[i+0],
208 indices[i+1],
209 indices[i+2],
210 indices[i+3]
211 );
212 }
213
214
215 static void
216 nv04_vbuf_render_draw( struct vbuf_render *render,
217 const ushort *indices,
218 uint nr_indices)
219 {
220 struct nv04_vbuf_render *nv04_render = nv04_vbuf_render(render);
221
222 // emit the indices
223 switch( nv04_render->prim )
224 {
225 case PIPE_PRIM_TRIANGLES:
226 nv04_vbuf_render_triangles_elts(nv04_render, indices, nr_indices);
227 break;
228 case PIPE_PRIM_QUAD_STRIP:
229 case PIPE_PRIM_TRIANGLE_STRIP:
230 nv04_vbuf_render_tri_strip_elts(nv04_render, indices, nr_indices);
231 break;
232 case PIPE_PRIM_TRIANGLE_FAN:
233 case PIPE_PRIM_POLYGON:
234 nv04_vbuf_render_tri_fan_elts(nv04_render, indices, nr_indices);
235 break;
236 case PIPE_PRIM_QUADS:
237 nv04_vbuf_render_quads_elts(nv04_render, indices, nr_indices);
238 break;
239 default:
240 NOUVEAU_ERR("You have to implement primitive %d, young padawan\n", nv04_render->prim);
241 break;
242 }
243 }
244
245
246 static void
247 nv04_vbuf_render_release_vertices( struct vbuf_render *render,
248 void *vertices,
249 unsigned vertex_size,
250 unsigned vertices_used )
251 {
252 struct nv04_vbuf_render *nv04_render = nv04_vbuf_render(render);
253
254 free(nv04_render->buffer);
255 nv04_render->buffer = NULL;
256 }
257
258
259 static void
260 nv04_vbuf_render_destroy( struct vbuf_render *render )
261 {
262 struct nv04_vbuf_render *nv04_render = nv04_vbuf_render(render);
263 FREE(nv04_render);
264 }
265
266
267 /**
268 * Create a new primitive render.
269 */
270 static struct vbuf_render *
271 nv04_vbuf_render_create( struct nv04_context *nv04 )
272 {
273 struct nv04_vbuf_render *nv04_render = CALLOC_STRUCT(nv04_vbuf_render);
274
275 nv04_render->nv04 = nv04;
276
277 nv04_render->base.max_vertex_buffer_bytes = VERTEX_BUFFER_SIZE;
278 nv04_render->base.max_indices = 65536;
279 nv04_render->base.get_vertex_info = nv04_vbuf_render_get_vertex_info;
280 nv04_render->base.allocate_vertices = nv04_vbuf_render_allocate_vertices;
281 nv04_render->base.set_primitive = nv04_vbuf_render_set_primitive;
282 nv04_render->base.draw = nv04_vbuf_render_draw;
283 nv04_render->base.release_vertices = nv04_vbuf_render_release_vertices;
284 nv04_render->base.destroy = nv04_vbuf_render_destroy;
285
286 return &nv04_render->base;
287 }
288
289
290 /**
291 * Create a new primitive vbuf/render stage.
292 */
293 struct draw_stage *nv04_draw_vbuf_stage( struct nv04_context *nv04 )
294 {
295 struct vbuf_render *render;
296 struct draw_stage *stage;
297
298 render = nv04_vbuf_render_create(nv04);
299 if(!render)
300 return NULL;
301
302 stage = draw_vbuf_stage( nv04->draw, render );
303 if(!stage) {
304 render->destroy(render);
305 return NULL;
306 }
307
308 return stage;
309 }