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