gallium: Implement draw_vbo and set_index_buffer for all drivers.
[mesa.git] / src / gallium / drivers / i965 / brw_draw.c
1 /**************************************************************************
2 *
3 * Copyright 2003 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 #include "util/u_inlines.h"
30 #include "util/u_prim.h"
31 #include "util/u_upload_mgr.h"
32 #include "util/u_draw_quad.h"
33
34 #include "brw_draw.h"
35 #include "brw_defines.h"
36 #include "brw_context.h"
37 #include "brw_state.h"
38 #include "brw_debug.h"
39
40 #include "brw_batchbuffer.h"
41
42
43 static uint32_t prim_to_hw_prim[PIPE_PRIM_POLYGON+1] = {
44 _3DPRIM_POINTLIST,
45 _3DPRIM_LINELIST,
46 _3DPRIM_LINELOOP,
47 _3DPRIM_LINESTRIP,
48 _3DPRIM_TRILIST,
49 _3DPRIM_TRISTRIP,
50 _3DPRIM_TRIFAN,
51 _3DPRIM_QUADLIST,
52 _3DPRIM_QUADSTRIP,
53 _3DPRIM_POLYGON
54 };
55
56
57
58 /* When the primitive changes, set a state bit and re-validate. Not
59 * the nicest and would rather deal with this by having all the
60 * programs be immune to the active primitive (ie. cope with all
61 * possibilities). That may not be realistic however.
62 */
63 static int brw_set_prim(struct brw_context *brw, unsigned prim )
64 {
65
66 if (BRW_DEBUG & DEBUG_PRIMS)
67 debug_printf("PRIM: %s\n", u_prim_name(prim));
68
69 if (prim != brw->primitive) {
70 unsigned reduced_prim;
71
72 brw->primitive = prim;
73 brw->state.dirty.brw |= BRW_NEW_PRIMITIVE;
74
75 reduced_prim = u_reduced_prim(prim);
76 if (reduced_prim != brw->reduced_primitive) {
77 brw->reduced_primitive = reduced_prim;
78 brw->state.dirty.brw |= BRW_NEW_REDUCED_PRIMITIVE;
79 }
80 }
81
82 return prim_to_hw_prim[prim];
83 }
84
85
86
87 static int brw_emit_prim(struct brw_context *brw,
88 unsigned start,
89 unsigned count,
90 boolean indexed,
91 uint32_t hw_prim)
92 {
93 struct brw_3d_primitive prim_packet;
94 int ret;
95
96 if (BRW_DEBUG & DEBUG_PRIMS)
97 debug_printf("%s start %d count %d indexed %d hw_prim %d\n",
98 __FUNCTION__, start, count, indexed, hw_prim);
99
100 prim_packet.header.opcode = CMD_3D_PRIM;
101 prim_packet.header.length = sizeof(prim_packet)/4 - 2;
102 prim_packet.header.pad = 0;
103 prim_packet.header.topology = hw_prim;
104 prim_packet.header.indexed = indexed;
105
106 prim_packet.verts_per_instance = count;
107 prim_packet.start_vert_location = start;
108 if (indexed)
109 prim_packet.start_vert_location += brw->ib.start_vertex_offset;
110 prim_packet.instance_count = 1;
111 prim_packet.start_instance_location = 0;
112 prim_packet.base_vert_location = 0; /* prim->basevertex; XXX: add this to gallium */
113
114
115 /* If we're set to always flush, do it before and after the primitive emit.
116 * We want to catch both missed flushes that hurt instruction/state cache
117 * and missed flushes of the render cache as it heads to other parts of
118 * the besides the draw code.
119 */
120 if (0) {
121 BEGIN_BATCH(1, IGNORE_CLIPRECTS);
122 OUT_BATCH((CMD_MI_FLUSH << 16) | BRW_FLUSH_STATE_CACHE);
123 ADVANCE_BATCH();
124 }
125 if (prim_packet.verts_per_instance) {
126 ret = brw_batchbuffer_data( brw->batch, &prim_packet,
127 sizeof(prim_packet), LOOP_CLIPRECTS);
128 if (ret)
129 return ret;
130 }
131 if (0) {
132 BEGIN_BATCH(1, IGNORE_CLIPRECTS);
133 OUT_BATCH((CMD_MI_FLUSH << 16) | BRW_FLUSH_STATE_CACHE);
134 ADVANCE_BATCH();
135 }
136
137 return 0;
138 }
139
140
141 /* May fail if out of video memory for texture or vbo upload, or on
142 * fallback conditions.
143 */
144 static int
145 try_draw_range_elements(struct brw_context *brw,
146 boolean indexed,
147 unsigned hw_prim,
148 unsigned start, unsigned count)
149 {
150 int ret;
151
152 ret = brw_validate_state(brw);
153 if (ret)
154 return ret;
155
156 /* Check that we can fit our state in with our existing batchbuffer, or
157 * flush otherwise.
158 */
159 ret = brw->sws->check_aperture_space(brw->sws,
160 brw->state.validated_bos,
161 brw->state.validated_bo_count);
162 if (ret)
163 return ret;
164
165 ret = brw_upload_state(brw);
166 if (ret)
167 return ret;
168
169 ret = brw_emit_prim(brw, start, count, indexed, hw_prim);
170 if (ret)
171 return ret;
172
173 if (brw->flags.always_flush_batch)
174 brw_context_flush( brw );
175
176 return 0;
177 }
178
179
180 static void
181 brw_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
182 {
183 struct brw_context *brw = brw_context(pipe);
184 int ret;
185 uint32_t hw_prim;
186
187 hw_prim = brw_set_prim(brw, info->mode);
188
189 if (BRW_DEBUG & DEBUG_PRIMS)
190 debug_printf("PRIM: %s start %d count %d index_buffer %p\n",
191 u_prim_name(info->mode), info->start, info->count,
192 (void *) brw->curr.index_buffer);
193
194 assert(info->index_bias == 0);
195
196 /* Potentially trigger upload of new index buffer range.
197 * XXX: do we really care?
198 */
199 if (brw->curr.min_index != info->min_index ||
200 brw->curr.max_index != info->max_index)
201 {
202 brw->curr.min_index = info->min_index;
203 brw->curr.max_index = info->max_index;
204 brw->state.dirty.mesa |= PIPE_NEW_INDEX_RANGE;
205 }
206
207
208 /* Make a first attempt at drawing:
209 */
210 ret = try_draw_range_elements(brw, info->indexed,
211 hw_prim, info->start, info->count);
212
213 /* Otherwise, flush and retry:
214 */
215 if (ret != 0) {
216 brw_context_flush( brw );
217 ret = try_draw_range_elements(brw, info->indexed,
218 hw_prim, info->start, info->count);
219 assert(ret == 0);
220 }
221 }
222
223 static void
224 brw_draw_range_elements(struct pipe_context *pipe,
225 struct pipe_resource *index_buffer,
226 unsigned index_size, int index_bias,
227 unsigned min_index,
228 unsigned max_index,
229 unsigned mode, unsigned start, unsigned count)
230 {
231 struct brw_context *brw = brw_context(pipe);
232 struct pipe_draw_info info;
233 struct pipe_index_buffer saved_ib, ib;
234
235 util_draw_init_info(&info);
236 info.mode = mode;
237 info.start = start;
238 info.count = count;
239 info.index_bias = index_bias;
240 info.min_index = min_index;
241 info.max_index = max_index;
242
243 if (index_buffer) {
244 info.indexed = TRUE;
245 saved_ib.buffer = brw->curr.index_buffer;
246 saved_ib.offset = brw->curr.index_offset;
247 saved_ib.index_size = brw->curr.index_size;
248
249 ib.buffer = index_buffer;
250 ib.offset = 0;
251 ib.index_size = index_size;
252 pipe->set_index_buffer(pipe, &ib);
253 }
254
255 brw_draw_vbo(pipe, &info);
256
257 if (index_buffer)
258 pipe->set_index_buffer(pipe, &saved_ib);
259 }
260
261 static void
262 brw_draw_elements(struct pipe_context *pipe,
263 struct pipe_resource *index_buffer,
264 unsigned index_size, int index_bias,
265 unsigned mode,
266 unsigned start, unsigned count)
267 {
268 brw_draw_range_elements( pipe, index_buffer,
269 index_size, index_bias,
270 0, 0xffffffff,
271 mode,
272 start, count );
273 }
274
275 static void
276 brw_draw_arrays(struct pipe_context *pipe, unsigned mode,
277 unsigned start, unsigned count)
278 {
279 brw_draw_elements(pipe, NULL, 0, 0, mode, start, count);
280 }
281
282
283
284 boolean brw_draw_init( struct brw_context *brw )
285 {
286 /* Register our drawing function:
287 */
288 brw->base.draw_arrays = brw_draw_arrays;
289 brw->base.draw_elements = brw_draw_elements;
290 brw->base.draw_range_elements = brw_draw_range_elements;
291 brw->base.draw_vbo = brw_draw_vbo;
292
293 /* Create helpers for uploading data in user buffers:
294 */
295 brw->vb.upload_vertex = u_upload_create( &brw->base,
296 128 * 1024,
297 64,
298 PIPE_BIND_VERTEX_BUFFER );
299 if (brw->vb.upload_vertex == NULL)
300 return FALSE;
301
302 brw->vb.upload_index = u_upload_create( &brw->base,
303 32 * 1024,
304 64,
305 PIPE_BIND_INDEX_BUFFER );
306 if (brw->vb.upload_index == NULL)
307 return FALSE;
308
309 return TRUE;
310 }
311
312 void brw_draw_cleanup( struct brw_context *brw )
313 {
314 u_upload_destroy( brw->vb.upload_vertex );
315 u_upload_destroy( brw->vb.upload_index );
316
317 bo_reference(&brw->ib.bo, NULL);
318 }