Merge commit 'origin/gallium-0.1' into 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 return &i915->current.vertex_info;
87 }
88
89
90 static void *
91 i915_vbuf_render_allocate_vertices( struct vbuf_render *render,
92 ushort vertex_size,
93 ushort nr_vertices )
94 {
95 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
96 struct i915_context *i915 = i915_render->i915;
97 struct pipe_winsys *winsys = i915->pipe.winsys;
98 size_t size = (size_t)vertex_size * (size_t)nr_vertices;
99
100 /* FIXME: handle failure */
101 assert(!i915->vbo);
102 i915->vbo = winsys->buffer_create(winsys, 64, I915_BUFFER_USAGE_LIT_VERTEX,
103 size);
104
105 i915->dirty |= I915_NEW_VBO;
106
107 return winsys->buffer_map(winsys,
108 i915->vbo,
109 PIPE_BUFFER_USAGE_CPU_WRITE);
110 }
111
112
113 static void
114 i915_vbuf_render_set_primitive( struct vbuf_render *render,
115 unsigned prim )
116 {
117 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
118
119 switch(prim) {
120 case PIPE_PRIM_POINTS:
121 i915_render->hwprim = PRIM3D_POINTLIST;
122 break;
123 case PIPE_PRIM_LINES:
124 i915_render->hwprim = PRIM3D_LINELIST;
125 break;
126 case PIPE_PRIM_TRIANGLES:
127 i915_render->hwprim = PRIM3D_TRILIST;
128 break;
129 default:
130 assert(0);
131 }
132 }
133
134
135 static void
136 i915_vbuf_render_draw( struct vbuf_render *render,
137 const ushort *indices,
138 uint nr_indices)
139 {
140 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
141 struct i915_context *i915 = i915_render->i915;
142 unsigned i;
143
144 assert(nr_indices);
145
146 assert((i915->dirty & ~I915_NEW_VBO) == 0);
147
148 if (i915->dirty)
149 i915_update_derived( i915 );
150
151 if (i915->hardware_dirty)
152 i915_emit_hardware_state( i915 );
153
154 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
155 FLUSH_BATCH();
156
157 /* Make sure state is re-emitted after a flush:
158 */
159 i915_update_derived( i915 );
160 i915_emit_hardware_state( i915 );
161
162 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
163 assert(0);
164 return;
165 }
166 }
167
168 OUT_BATCH( _3DPRIMITIVE |
169 PRIM_INDIRECT |
170 i915_render->hwprim |
171 PRIM_INDIRECT_ELTS |
172 nr_indices );
173 for (i = 0; i + 1 < nr_indices; i += 2) {
174 OUT_BATCH( indices[i] |
175 (indices[i + 1] << 16) );
176 }
177 if (i < nr_indices) {
178 OUT_BATCH( indices[i] );
179 }
180 }
181
182
183 static void
184 i915_vbuf_render_release_vertices( struct vbuf_render *render,
185 void *vertices,
186 unsigned vertex_size,
187 unsigned vertices_used )
188 {
189 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
190 struct i915_context *i915 = i915_render->i915;
191 struct pipe_winsys *winsys = i915->pipe.winsys;
192
193 assert(i915->vbo);
194 winsys->buffer_unmap(winsys, i915->vbo);
195 pipe_buffer_reference(winsys, &i915->vbo, NULL);
196 }
197
198
199 static void
200 i915_vbuf_render_destroy( struct vbuf_render *render )
201 {
202 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
203 FREE(i915_render);
204 }
205
206
207 /**
208 * Create a new primitive render.
209 */
210 static struct vbuf_render *
211 i915_vbuf_render_create( struct i915_context *i915 )
212 {
213 struct i915_vbuf_render *i915_render = CALLOC_STRUCT(i915_vbuf_render);
214
215 i915_render->i915 = i915;
216
217 i915_render->base.max_vertex_buffer_bytes = 128*1024;
218
219 /* NOTE: it must be such that state and vertices indices fit in a single
220 * batch buffer.
221 */
222 i915_render->base.max_indices = 16*1024;
223
224 i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info;
225 i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices;
226 i915_render->base.set_primitive = i915_vbuf_render_set_primitive;
227 i915_render->base.draw = i915_vbuf_render_draw;
228 i915_render->base.release_vertices = i915_vbuf_render_release_vertices;
229 i915_render->base.destroy = i915_vbuf_render_destroy;
230
231 return &i915_render->base;
232 }
233
234
235 /**
236 * Create a new primitive vbuf/render stage.
237 */
238 struct draw_stage *i915_draw_vbuf_stage( struct i915_context *i915 )
239 {
240 struct vbuf_render *render;
241 struct draw_stage *stage;
242
243 render = i915_vbuf_render_create(i915);
244 if(!render)
245 return NULL;
246
247 stage = draw_vbuf_stage( i915->draw, render );
248 if(!stage) {
249 render->destroy(render);
250 return NULL;
251 }
252
253 return stage;
254 }