Merge 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 void
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 break;
129 case PIPE_PRIM_LINES:
130 i915_render->hwprim = PRIM3D_LINELIST;
131 break;
132 case PIPE_PRIM_TRIANGLES:
133 i915_render->hwprim = PRIM3D_TRILIST;
134 break;
135 default:
136 assert(0);
137 }
138 }
139
140
141 static void
142 i915_vbuf_render_draw( struct vbuf_render *render,
143 const ushort *indices,
144 uint nr_indices)
145 {
146 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
147 struct i915_context *i915 = i915_render->i915;
148 unsigned i;
149
150 assert(nr_indices);
151
152 /* this seems to be bogus, since we validate state right after this */
153 /*assert((i915->dirty & ~I915_NEW_VBO) == 0);*/
154
155 if (i915->dirty)
156 i915_update_derived( i915 );
157
158 if (i915->hardware_dirty)
159 i915_emit_hardware_state( i915 );
160
161 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
162 FLUSH_BATCH();
163
164 /* Make sure state is re-emitted after a flush:
165 */
166 i915_update_derived( i915 );
167 i915_emit_hardware_state( i915 );
168
169 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
170 assert(0);
171 return;
172 }
173 }
174
175 OUT_BATCH( _3DPRIMITIVE |
176 PRIM_INDIRECT |
177 i915_render->hwprim |
178 PRIM_INDIRECT_ELTS |
179 nr_indices );
180 for (i = 0; i + 1 < nr_indices; i += 2) {
181 OUT_BATCH( indices[i] |
182 (indices[i + 1] << 16) );
183 }
184 if (i < nr_indices) {
185 OUT_BATCH( indices[i] );
186 }
187 }
188
189
190 static void
191 i915_vbuf_render_release_vertices( struct vbuf_render *render,
192 void *vertices,
193 unsigned vertex_size,
194 unsigned vertices_used )
195 {
196 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
197 struct i915_context *i915 = i915_render->i915;
198 struct pipe_winsys *winsys = i915->pipe.winsys;
199
200 assert(i915->vbo);
201 winsys->buffer_unmap(winsys, i915->vbo);
202 pipe_buffer_reference(winsys, &i915->vbo, NULL);
203 }
204
205
206 static void
207 i915_vbuf_render_destroy( struct vbuf_render *render )
208 {
209 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
210 FREE(i915_render);
211 }
212
213
214 /**
215 * Create a new primitive render.
216 */
217 static struct vbuf_render *
218 i915_vbuf_render_create( struct i915_context *i915 )
219 {
220 struct i915_vbuf_render *i915_render = CALLOC_STRUCT(i915_vbuf_render);
221
222 i915_render->i915 = i915;
223
224 i915_render->base.max_vertex_buffer_bytes = 128*1024;
225
226 /* NOTE: it must be such that state and vertices indices fit in a single
227 * batch buffer.
228 */
229 i915_render->base.max_indices = 16*1024;
230
231 i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info;
232 i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices;
233 i915_render->base.set_primitive = i915_vbuf_render_set_primitive;
234 i915_render->base.draw = i915_vbuf_render_draw;
235 i915_render->base.release_vertices = i915_vbuf_render_release_vertices;
236 i915_render->base.destroy = i915_vbuf_render_destroy;
237
238 return &i915_render->base;
239 }
240
241
242 /**
243 * Create a new primitive vbuf/render stage.
244 */
245 struct draw_stage *i915_draw_vbuf_stage( struct i915_context *i915 )
246 {
247 struct vbuf_render *render;
248 struct draw_stage *stage;
249
250 render = i915_vbuf_render_create(i915);
251 if(!render)
252 return NULL;
253
254 stage = draw_vbuf_stage( i915->draw, render );
255 if(!stage) {
256 render->destroy(render);
257 return NULL;
258 }
259
260 return stage;
261 }