Merge remote branch 'upstream/gallium-0.1' into nouveau-gallium-0.1
[mesa.git] / src / gallium / drivers / i915simple / i915_prim_vbuf.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 * \file
30 * Build post-transformation, post-clipping vertex buffers and element
31 * lists by hooking into the end of the primitive pipeline and
32 * manipulating the vertex_id field in the vertex headers.
33 *
34 * XXX: work in progress
35 *
36 * \author José Fonseca <jrfonseca@tungstengraphics.com>
37 * \author Keith Whitwell <keith@tungstengraphics.com>
38 */
39
40
41 #include "draw/draw_vbuf.h"
42 #include "pipe/p_debug.h"
43 #include "pipe/p_util.h"
44 #include "pipe/p_inlines.h"
45 #include "pipe/p_winsys.h"
46
47 #include "i915_context.h"
48 #include "i915_reg.h"
49 #include "i915_winsys.h"
50 #include "i915_batch.h"
51 #include "i915_state.h"
52
53
54 /**
55 * Primitive renderer for i915.
56 */
57 struct i915_vbuf_render {
58 struct vbuf_render base;
59
60 struct i915_context *i915;
61
62 /** Vertex size in bytes */
63 unsigned vertex_size;
64
65 /** Hardware primitive */
66 unsigned hwprim;
67 };
68
69
70 /**
71 * Basically a cast wrapper.
72 */
73 static INLINE struct i915_vbuf_render *
74 i915_vbuf_render( struct vbuf_render *render )
75 {
76 assert(render);
77 return (struct i915_vbuf_render *)render;
78 }
79
80
81 static const struct vertex_info *
82 i915_vbuf_render_get_vertex_info( struct vbuf_render *render )
83 {
84 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
85 struct i915_context *i915 = i915_render->i915;
86
87 if (i915->dirty) {
88 /* make sure we have up to date vertex layout */
89 i915_update_derived( i915 );
90 }
91
92 return &i915->current.vertex_info;
93 }
94
95
96 static void *
97 i915_vbuf_render_allocate_vertices( struct vbuf_render *render,
98 ushort vertex_size,
99 ushort nr_vertices )
100 {
101 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
102 struct i915_context *i915 = i915_render->i915;
103 struct pipe_winsys *winsys = i915->pipe.winsys;
104 size_t size = (size_t)vertex_size * (size_t)nr_vertices;
105
106 /* FIXME: handle failure */
107 assert(!i915->vbo);
108 i915->vbo = winsys->buffer_create(winsys, 64, I915_BUFFER_USAGE_LIT_VERTEX,
109 size);
110
111 i915->dirty |= I915_NEW_VBO;
112
113 return winsys->buffer_map(winsys,
114 i915->vbo,
115 PIPE_BUFFER_USAGE_CPU_WRITE);
116 }
117
118
119 static boolean
120 i915_vbuf_render_set_primitive( struct vbuf_render *render,
121 unsigned prim )
122 {
123 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
124
125 switch(prim) {
126 case PIPE_PRIM_POINTS:
127 i915_render->hwprim = PRIM3D_POINTLIST;
128 return TRUE;
129 case PIPE_PRIM_LINES:
130 i915_render->hwprim = PRIM3D_LINELIST;
131 return TRUE;
132 case PIPE_PRIM_TRIANGLES:
133 i915_render->hwprim = PRIM3D_TRILIST;
134 return TRUE;
135 default:
136 /* Actually, can handle a lot more just fine... Fixme.
137 */
138 return FALSE;
139 }
140 }
141
142
143 static void
144 i915_vbuf_render_draw( struct vbuf_render *render,
145 const ushort *indices,
146 uint nr_indices)
147 {
148 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
149 struct i915_context *i915 = i915_render->i915;
150 unsigned i;
151
152 assert(nr_indices);
153
154 /* this seems to be bogus, since we validate state right after this */
155 /*assert((i915->dirty & ~I915_NEW_VBO) == 0);*/
156
157 if (i915->dirty)
158 i915_update_derived( i915 );
159
160 if (i915->hardware_dirty)
161 i915_emit_hardware_state( i915 );
162
163 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
164 FLUSH_BATCH();
165
166 /* Make sure state is re-emitted after a flush:
167 */
168 i915_update_derived( i915 );
169 i915_emit_hardware_state( i915 );
170
171 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
172 assert(0);
173 return;
174 }
175 }
176
177 OUT_BATCH( _3DPRIMITIVE |
178 PRIM_INDIRECT |
179 i915_render->hwprim |
180 PRIM_INDIRECT_ELTS |
181 nr_indices );
182 for (i = 0; i + 1 < nr_indices; i += 2) {
183 OUT_BATCH( indices[i] |
184 (indices[i + 1] << 16) );
185 }
186 if (i < nr_indices) {
187 OUT_BATCH( indices[i] );
188 }
189 }
190
191
192 static void
193 i915_vbuf_render_release_vertices( struct vbuf_render *render,
194 void *vertices,
195 unsigned vertex_size,
196 unsigned vertices_used )
197 {
198 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
199 struct i915_context *i915 = i915_render->i915;
200 struct pipe_winsys *winsys = i915->pipe.winsys;
201
202 assert(i915->vbo);
203 winsys->buffer_unmap(winsys, i915->vbo);
204 pipe_buffer_reference(winsys, &i915->vbo, NULL);
205 }
206
207
208 static void
209 i915_vbuf_render_destroy( struct vbuf_render *render )
210 {
211 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
212 FREE(i915_render);
213 }
214
215
216 /**
217 * Create a new primitive render.
218 */
219 static struct vbuf_render *
220 i915_vbuf_render_create( struct i915_context *i915 )
221 {
222 struct i915_vbuf_render *i915_render = CALLOC_STRUCT(i915_vbuf_render);
223
224 i915_render->i915 = i915;
225
226 i915_render->base.max_vertex_buffer_bytes = 128*1024;
227
228 /* NOTE: it must be such that state and vertices indices fit in a single
229 * batch buffer.
230 */
231 i915_render->base.max_indices = 16*1024;
232
233 i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info;
234 i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices;
235 i915_render->base.set_primitive = i915_vbuf_render_set_primitive;
236 i915_render->base.draw = i915_vbuf_render_draw;
237 i915_render->base.release_vertices = i915_vbuf_render_release_vertices;
238 i915_render->base.destroy = i915_vbuf_render_destroy;
239
240 return &i915_render->base;
241 }
242
243
244 /**
245 * Create a new primitive vbuf/render stage.
246 */
247 struct draw_stage *i915_draw_vbuf_stage( struct i915_context *i915 )
248 {
249 struct vbuf_render *render;
250 struct draw_stage *stage;
251
252 render = i915_vbuf_render_create(i915);
253 if(!render)
254 return NULL;
255
256 stage = draw_vbuf_stage( i915->draw, render );
257 if(!stage) {
258 render->destroy(render);
259 return NULL;
260 }
261
262 return stage;
263 }