1 /*
2  * Copyright (C) 2009-2010 Francisco Jerez.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  */
26 
27 #include "nouveau_driver.h"
28 #include "nouveau_bufferobj.h"
29 #include "nouveau_util.h"
30 
31 #include "main/bufferobj.h"
32 #include "main/glformats.h"
33 #include "main/varray.h"
34 #include "main/image.h"
35 
36 /* Arbitrary pushbuf length we can assume we can get with a single
37  * call to WAIT_RING. */
38 #define PUSHBUF_DWORDS 65536
39 
40 /* Functions to turn GL arrays or index buffers into nouveau_array
41  * structures. */
42 
43 static int
get_array_stride(struct gl_context * ctx,const struct tnl_vertex_array * a)44 get_array_stride(struct gl_context *ctx, const struct tnl_vertex_array *a)
45 {
46 	struct nouveau_render_state *render = to_render_state(ctx);
47 	const struct gl_vertex_buffer_binding *binding = a->BufferBinding;
48 
49 	if (render->mode == VBO && !binding->BufferObj) {
50 		const struct gl_array_attributes *attrib = a->VertexAttrib;
51 		/* Pack client buffers. */
52 		return align(attrib->Format._ElementSize, 4);
53 	} else {
54 		return binding->Stride;
55 	}
56 }
57 
58 static void
vbo_init_arrays(struct gl_context * ctx,const struct _mesa_index_buffer * ib,const struct tnl_vertex_array * arrays)59 vbo_init_arrays(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
60 		const struct tnl_vertex_array *arrays)
61 {
62 	struct nouveau_render_state *render = to_render_state(ctx);
63 	GLboolean imm = (render->mode == IMM);
64 	int i, attr;
65 
66 	if (ib) {
67 		GLenum ib_type;
68 
69 		if (ib->index_size_shift == 2)
70 			ib_type = GL_UNSIGNED_INT;
71 		else if (ib->index_size_shift == 1)
72 			ib_type = GL_UNSIGNED_SHORT;
73 		else
74 			ib_type = GL_UNSIGNED_BYTE;
75 
76 		nouveau_init_array(&render->ib, 0, 0, ib->count, ib_type,
77 				   ib->obj, ib->ptr, GL_TRUE, ctx);
78 	}
79 
80 	FOR_EACH_BOUND_ATTR(render, i, attr) {
81 		const struct tnl_vertex_array *array = &arrays[attr];
82 		const struct gl_vertex_buffer_binding *binding =
83 			array->BufferBinding;
84 		const struct gl_array_attributes *attrib = array->VertexAttrib;
85 		const GLubyte *p = _mesa_vertex_attrib_address(attrib, binding);
86 
87 		nouveau_init_array(&render->attrs[attr], attr,
88 				   get_array_stride(ctx, array),
89 				   attrib->Format.Size, attrib->Format.Type,
90 				   imm ? binding->BufferObj : NULL,
91 				   p, imm, ctx);
92 	}
93 }
94 
95 static void
vbo_deinit_arrays(struct gl_context * ctx,const struct _mesa_index_buffer * ib,const struct tnl_vertex_array * arrays)96 vbo_deinit_arrays(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
97 		  const struct tnl_vertex_array *arrays)
98 {
99 	struct nouveau_render_state *render = to_render_state(ctx);
100 	int i, attr;
101 
102 	if (ib)
103 		nouveau_cleanup_array(&render->ib);
104 
105 	FOR_EACH_BOUND_ATTR(render, i, attr) {
106 		struct nouveau_array *a = &render->attrs[attr];
107 
108 		if (render->mode == IMM)
109 			nouveau_bo_ref(NULL, &a->bo);
110 
111 		nouveau_deinit_array(a);
112 		render->map[i] = -1;
113 	}
114 
115 	render->attr_count = 0;
116 }
117 
118 /* Make some rendering decisions from the GL context. */
119 
120 static void
vbo_choose_render_mode(struct gl_context * ctx,const struct tnl_vertex_array * arrays)121 vbo_choose_render_mode(struct gl_context *ctx, const struct tnl_vertex_array *arrays)
122 {
123 	struct nouveau_render_state *render = to_render_state(ctx);
124 	int i;
125 
126 	render->mode = VBO;
127 
128 	if (ctx->Light.Enabled) {
129 		for (i = 0; i < VERT_ATTRIB_MAT_MAX; i++) {
130 			if (arrays[VERT_ATTRIB_MAT(i)].BufferBinding->Stride) {
131 				render->mode = IMM;
132 				break;
133 			}
134 		}
135 	}
136 }
137 
138 static void
vbo_emit_attr(struct gl_context * ctx,const struct tnl_vertex_array * arrays,int attr)139 vbo_emit_attr(struct gl_context *ctx, const struct tnl_vertex_array *arrays,
140 	      int attr)
141 {
142 	struct nouveau_pushbuf *push = context_push(ctx);
143 	struct nouveau_render_state *render = to_render_state(ctx);
144 	const struct tnl_vertex_array *array = &arrays[attr];
145 	const struct gl_vertex_buffer_binding *binding = array->BufferBinding;
146 	const struct gl_array_attributes *attrib = array->VertexAttrib;
147 	const GLubyte *p = _mesa_vertex_attrib_address(attrib, binding);
148 	struct nouveau_array *a = &render->attrs[attr];
149 	RENDER_LOCALS(ctx);
150 
151 	if (!binding->Stride) {
152 		if (attr >= VERT_ATTRIB_MAT(0))
153 			/* nouveau_update_state takes care of materials. */
154 			return;
155 
156 		/* Constant attribute. */
157 		nouveau_init_array(a, attr, binding->Stride, attrib->Format.Size,
158 				   attrib->Format.Type, binding->BufferObj, p,
159 				   GL_TRUE, ctx);
160 		EMIT_IMM(ctx, a, 0);
161 		nouveau_deinit_array(a);
162 
163 	} else {
164 		/* Varying attribute. */
165 		struct nouveau_attr_info *info = &TAG(vertex_attrs)[attr];
166 
167 		if (render->mode == VBO) {
168 			render->map[info->vbo_index] = attr;
169 			render->vertex_size += attrib->Format._ElementSize;
170 			render->attr_count = MAX2(render->attr_count,
171 						  info->vbo_index + 1);
172 		} else {
173 			render->map[render->attr_count++] = attr;
174 			render->vertex_size += 4 * info->imm_fields;
175 		}
176 	}
177 }
178 
179 #define MAT(a) VERT_ATTRIB_MAT(MAT_ATTRIB_##a)
180 
181 static void
vbo_choose_attrs(struct gl_context * ctx,const struct tnl_vertex_array * arrays)182 vbo_choose_attrs(struct gl_context *ctx, const struct tnl_vertex_array *arrays)
183 {
184 	struct nouveau_render_state *render = to_render_state(ctx);
185 	int i;
186 
187 	/* Reset the vertex size. */
188 	render->vertex_size = 0;
189 	render->attr_count = 0;
190 
191 	vbo_emit_attr(ctx, arrays, VERT_ATTRIB_COLOR0);
192 	if (ctx->Fog.ColorSumEnabled && !ctx->Light.Enabled)
193 		vbo_emit_attr(ctx, arrays, VERT_ATTRIB_COLOR1);
194 
195 	for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
196 		if (ctx->Texture._EnabledCoordUnits & (1 << i))
197 			vbo_emit_attr(ctx, arrays, VERT_ATTRIB_TEX0 + i);
198 	}
199 
200 	if (ctx->Fog.Enabled && ctx->Fog.FogCoordinateSource == GL_FOG_COORD)
201 		vbo_emit_attr(ctx, arrays, VERT_ATTRIB_FOG);
202 
203 	if (ctx->Light.Enabled ||
204 	    (ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS))
205 		vbo_emit_attr(ctx, arrays, VERT_ATTRIB_NORMAL);
206 
207 	if (ctx->Light.Enabled && render->mode == IMM) {
208 		vbo_emit_attr(ctx, arrays, MAT(FRONT_AMBIENT));
209 		vbo_emit_attr(ctx, arrays, MAT(FRONT_DIFFUSE));
210 		vbo_emit_attr(ctx, arrays, MAT(FRONT_SPECULAR));
211 		vbo_emit_attr(ctx, arrays, MAT(FRONT_SHININESS));
212 
213 		if (ctx->Light.Model.TwoSide) {
214 			vbo_emit_attr(ctx, arrays, MAT(BACK_AMBIENT));
215 			vbo_emit_attr(ctx, arrays, MAT(BACK_DIFFUSE));
216 			vbo_emit_attr(ctx, arrays, MAT(BACK_SPECULAR));
217 			vbo_emit_attr(ctx, arrays, MAT(BACK_SHININESS));
218 		}
219 	}
220 
221 	vbo_emit_attr(ctx, arrays, VERT_ATTRIB_POS);
222 }
223 
224 static int
get_max_client_stride(struct gl_context * ctx,const struct tnl_vertex_array * arrays)225 get_max_client_stride(struct gl_context *ctx, const struct tnl_vertex_array *arrays)
226 {
227 	struct nouveau_render_state *render = to_render_state(ctx);
228 	int i, attr, s = 0;
229 
230 	FOR_EACH_BOUND_ATTR(render, i, attr) {
231 		const struct tnl_vertex_array *a = &arrays[attr];
232 
233 		if (!a->BufferBinding->BufferObj)
234 			s = MAX2(s, get_array_stride(ctx, a));
235 	}
236 
237 	return s;
238 }
239 
240 static void
241 TAG(vbo_render_prims)(struct gl_context *ctx,
242 		      const struct tnl_vertex_array *arrays,
243 		      const struct _mesa_prim *prims, GLuint nr_prims,
244 		      const struct _mesa_index_buffer *ib,
245 		      GLboolean index_bounds_valid,
246 		      GLuint min_index, GLuint max_index,
247                       GLuint num_instances, GLuint base_instance);
248 
249 static GLboolean
vbo_maybe_split(struct gl_context * ctx,const struct tnl_vertex_array * arrays,const struct _mesa_prim * prims,GLuint nr_prims,const struct _mesa_index_buffer * ib,GLuint min_index,GLuint max_index,GLuint num_instances,GLuint base_instance)250 vbo_maybe_split(struct gl_context *ctx, const struct tnl_vertex_array *arrays,
251 	    const struct _mesa_prim *prims, GLuint nr_prims,
252 	    const struct _mesa_index_buffer *ib,
253 	    GLuint min_index, GLuint max_index,
254             GLuint num_instances, GLuint base_instance)
255 {
256 	struct nouveau_context *nctx = to_nouveau_context(ctx);
257 	struct nouveau_render_state *render = to_render_state(ctx);
258 	struct nouveau_bufctx *bufctx = nctx->hw.bufctx;
259 	unsigned pushbuf_avail = PUSHBUF_DWORDS - 2 * (bufctx->relocs +
260 						       render->attr_count),
261 		vert_avail = get_max_vertices(ctx, NULL, pushbuf_avail),
262 		idx_avail = get_max_vertices(ctx, ib, pushbuf_avail);
263 	int stride;
264 
265 	/* Try to keep client buffers smaller than the scratch BOs. */
266 	if (render->mode == VBO &&
267 	    (stride = get_max_client_stride(ctx, arrays)))
268 		    vert_avail = MIN2(vert_avail,
269 				      NOUVEAU_SCRATCH_SIZE / stride);
270 
271 	if (max_index - min_index > vert_avail ||
272 	    (ib && ib->count > idx_avail)) {
273 		struct split_limits limits = {
274 			.max_verts = vert_avail,
275 			.max_indices = idx_avail,
276 			.max_vb_size = ~0,
277 		};
278 
279 		_tnl_split_prims(ctx, arrays, prims, nr_prims, ib, min_index,
280 				 max_index, num_instances, base_instance,
281                                  TAG(vbo_render_prims), &limits);
282 		return GL_TRUE;
283 	}
284 
285 	return GL_FALSE;
286 }
287 
288 /* VBO rendering path. */
289 
290 static GLboolean
check_update_array(struct nouveau_array * a,unsigned offset,struct nouveau_bo * bo,int * pdelta)291 check_update_array(struct nouveau_array *a, unsigned offset,
292 		   struct nouveau_bo *bo, int *pdelta)
293 {
294 	int delta = *pdelta;
295 	GLboolean dirty;
296 
297 	if (a->bo == bo) {
298 		if (delta < 0)
299 			delta = ((int)offset - (int)a->offset) / a->stride;
300 
301 		dirty = (delta < 0 ||
302 			 offset != (a->offset + delta * a->stride));
303 	} else {
304 		dirty = GL_TRUE;
305 	}
306 
307 	*pdelta = (dirty ? 0 : delta);
308 	return dirty;
309 }
310 
311 static void
vbo_bind_vertices(struct gl_context * ctx,const struct tnl_vertex_array * arrays,int base,unsigned min_index,unsigned max_index,int * pdelta)312 vbo_bind_vertices(struct gl_context *ctx, const struct tnl_vertex_array *arrays,
313 		  int base, unsigned min_index, unsigned max_index, int *pdelta)
314 {
315 	struct nouveau_render_state *render = to_render_state(ctx);
316 	struct nouveau_pushbuf *push = context_push(ctx);
317 	struct nouveau_bo *bo[NUM_VERTEX_ATTRS];
318 	unsigned offset[NUM_VERTEX_ATTRS];
319 	GLboolean dirty = GL_FALSE;
320 	int i, j, attr;
321 	RENDER_LOCALS(ctx);
322 
323 	*pdelta = -1;
324 
325 	FOR_EACH_BOUND_ATTR(render, i, attr) {
326 		const struct tnl_vertex_array *array = &arrays[attr];
327 		const struct gl_vertex_buffer_binding *binding =
328 			array->BufferBinding;
329 		const struct gl_array_attributes *attrib = array->VertexAttrib;
330 		const GLubyte *p = _mesa_vertex_attrib_address(attrib, binding);
331 		struct gl_buffer_object *obj = binding->BufferObj;
332 		struct nouveau_array *a = &render->attrs[attr];
333 		unsigned delta = (base + min_index) * binding->Stride;
334 
335 		bo[i] = NULL;
336 
337 		if (nouveau_bufferobj_hw(obj)) {
338 			/* Array in a buffer obj. */
339 			nouveau_bo_ref(to_nouveau_bufferobj(obj)->bo, &bo[i]);
340 			offset[i] = delta + (intptr_t)p;
341 
342 		} else {
343 			int n = max_index - min_index + 1;
344 			const char *sp;
345                         if (obj) {
346                            sp = (char *)ADD_POINTERS(
347 				nouveau_bufferobj_sys(obj), p) + delta;
348                         } else {
349                            sp = (char *)(p + delta);
350                         }
351 			char *dp  = nouveau_get_scratch(ctx, n * a->stride,
352 							&bo[i], &offset[i]);
353 
354 			/* Array in client memory, move it to a
355 			 * scratch buffer obj. */
356 			for (j = 0; j < n; j++)
357 				memcpy(dp + j * a->stride,
358 				       sp + j * binding->Stride,
359 				       a->stride);
360 		}
361 
362 		dirty |= check_update_array(a, offset[i], bo[i], pdelta);
363 	}
364 
365 	*pdelta -= min_index;
366 
367 	if (dirty) {
368 		/* Buffers changed, update the attribute binding. */
369 		FOR_EACH_BOUND_ATTR(render, i, attr) {
370 			struct nouveau_array *a = &render->attrs[attr];
371 
372 			nouveau_bo_ref(NULL, &a->bo);
373 			a->offset = offset[i];
374 			a->bo = bo[i];
375 		}
376 
377 		TAG(render_release_vertices)(ctx);
378 		TAG(render_bind_vertices)(ctx);
379 	} else {
380 		/* Just cleanup. */
381 		FOR_EACH_BOUND_ATTR(render, i, attr)
382 			nouveau_bo_ref(NULL, &bo[i]);
383 	}
384 
385 	BATCH_VALIDATE();
386 }
387 
388 static void
vbo_draw_vbo(struct gl_context * ctx,const struct tnl_vertex_array * arrays,const struct _mesa_prim * prims,GLuint nr_prims,const struct _mesa_index_buffer * ib,GLuint min_index,GLuint max_index)389 vbo_draw_vbo(struct gl_context *ctx, const struct tnl_vertex_array *arrays,
390 	     const struct _mesa_prim *prims, GLuint nr_prims,
391 	     const struct _mesa_index_buffer *ib, GLuint min_index,
392 	     GLuint max_index)
393 {
394 	struct nouveau_context *nctx = to_nouveau_context(ctx);
395 	struct nouveau_pushbuf *push = context_push(ctx);
396 	dispatch_t dispatch = get_array_dispatch(&to_render_state(ctx)->ib);
397 	int i, delta = 0, basevertex = 0;
398 	RENDER_LOCALS(ctx);
399 
400 	TAG(render_set_format)(ctx);
401 
402 	for (i = 0; i < nr_prims; i++) {
403 		unsigned start = prims[i].start,
404 			count = prims[i].count;
405 
406 		if (i == 0 || basevertex != prims[i].basevertex) {
407 			basevertex = prims[i].basevertex;
408 			vbo_bind_vertices(ctx, arrays, basevertex, min_index,
409 					  max_index, &delta);
410 
411 			nouveau_pushbuf_bufctx(push, nctx->hw.bufctx);
412 			if (nouveau_pushbuf_validate(push)) {
413 				nouveau_pushbuf_bufctx(push, NULL);
414 				return;
415 			}
416 		}
417 
418 		if (count > get_max_vertices(ctx, ib, PUSH_AVAIL(push)))
419 			PUSH_SPACE(push, PUSHBUF_DWORDS);
420 
421 		BATCH_BEGIN(nvgl_primitive(prims[i].mode));
422 		dispatch(ctx, start, delta, count);
423 		BATCH_END();
424 	}
425 
426 	nouveau_pushbuf_bufctx(push, NULL);
427 	TAG(render_release_vertices)(ctx);
428 }
429 
430 /* Immediate rendering path. */
431 
432 static unsigned
extract_id(struct nouveau_array * a,int i,int j)433 extract_id(struct nouveau_array *a, int i, int j)
434 {
435 	return j;
436 }
437 
438 static void
vbo_draw_imm(struct gl_context * ctx,const struct tnl_vertex_array * arrays,const struct _mesa_prim * prims,GLuint nr_prims,const struct _mesa_index_buffer * ib,GLuint min_index,GLuint max_index)439 vbo_draw_imm(struct gl_context *ctx, const struct tnl_vertex_array *arrays,
440 	     const struct _mesa_prim *prims, GLuint nr_prims,
441 	     const struct _mesa_index_buffer *ib, GLuint min_index,
442 	     GLuint max_index)
443 {
444 	struct nouveau_render_state *render = to_render_state(ctx);
445 	struct nouveau_context *nctx = to_nouveau_context(ctx);
446 	struct nouveau_pushbuf *push = context_push(ctx);
447 	extract_u_t extract = ib ? render->ib.extract_u : extract_id;
448 	int i, j, k, attr;
449 	RENDER_LOCALS(ctx);
450 
451 	nouveau_pushbuf_bufctx(push, nctx->hw.bufctx);
452 	if (nouveau_pushbuf_validate(push)) {
453 		nouveau_pushbuf_bufctx(push, NULL);
454 		return;
455 	}
456 
457 	for (i = 0; i < nr_prims; i++) {
458 		unsigned start = prims[i].start,
459 			end = start + prims[i].count;
460 
461 		if (prims[i].count > get_max_vertices(ctx, ib,
462 						      PUSH_AVAIL(push)))
463 			PUSH_SPACE(push, PUSHBUF_DWORDS);
464 
465 		BATCH_BEGIN(nvgl_primitive(prims[i].mode));
466 
467 		for (; start < end; start++) {
468 			j = prims[i].basevertex +
469 				extract(&render->ib, 0, start);
470 
471 			FOR_EACH_BOUND_ATTR(render, k, attr)
472 				EMIT_IMM(ctx, &render->attrs[attr], j);
473 		}
474 
475 		BATCH_END();
476 	}
477 
478 	nouveau_pushbuf_bufctx(push, NULL);
479 }
480 
481 /* draw_prims entry point when we're doing hw-tnl. */
482 
483 static void
TAG(vbo_render_prims)484 TAG(vbo_render_prims)(struct gl_context *ctx,
485 		      const struct tnl_vertex_array *arrays,
486 		      const struct _mesa_prim *prims, GLuint nr_prims,
487 		      const struct _mesa_index_buffer *ib,
488 		      GLboolean index_bounds_valid,
489 		      GLuint min_index, GLuint max_index,
490                       GLuint num_instances, GLuint base_instance)
491 {
492 	struct nouveau_render_state *render = to_render_state(ctx);
493 
494 	if (!index_bounds_valid)
495 		vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
496 				       nr_prims, 0, false);
497 
498 	vbo_choose_render_mode(ctx, arrays);
499 	vbo_choose_attrs(ctx, arrays);
500 
501 	if (vbo_maybe_split(ctx, arrays, prims, nr_prims, ib, min_index,
502 			    max_index, num_instances, base_instance))
503 		return;
504 
505 	vbo_init_arrays(ctx, ib, arrays);
506 
507 	if (render->mode == VBO)
508 		vbo_draw_vbo(ctx, arrays, prims, nr_prims, ib, min_index,
509 			     max_index);
510 	else
511 		vbo_draw_imm(ctx, arrays, prims, nr_prims, ib, min_index,
512 			     max_index);
513 
514 	vbo_deinit_arrays(ctx, ib, arrays);
515 }
516 
517 /* VBO rendering entry points. */
518 
519 static void
TAG(vbo_check_render_prims)520 TAG(vbo_check_render_prims)(struct gl_context *ctx,
521 			    const struct tnl_vertex_array *arrays,
522 			    const struct _mesa_prim *prims, GLuint nr_prims,
523 			    const struct _mesa_index_buffer *ib,
524 			    GLboolean index_bounds_valid,
525 			    GLuint min_index, GLuint max_index,
526                             GLuint num_instances, GLuint base_instance)
527 {
528 	struct nouveau_context *nctx = to_nouveau_context(ctx);
529 
530 	nouveau_validate_framebuffer(ctx);
531 
532 	if (nctx->fallback == HWTNL)
533 		TAG(vbo_render_prims)(ctx, arrays, prims, nr_prims, ib,
534 				      index_bounds_valid, min_index, max_index,
535 				      num_instances, base_instance);
536 
537 	if (nctx->fallback == SWTNL)
538 		_tnl_draw_prims(ctx, arrays, prims, nr_prims, ib,
539 				index_bounds_valid, min_index, max_index,
540                                 num_instances, base_instance);
541 }
542 
543 static void
TAG(vbo_draw)544 TAG(vbo_draw)(struct gl_context *ctx,
545 	      const struct _mesa_prim *prims, unsigned nr_prims,
546 	      const struct _mesa_index_buffer *ib,
547 	      bool index_bounds_valid,
548               bool primitive_restart,
549               unsigned restart_index,
550               unsigned min_index, unsigned max_index,
551               unsigned num_instances, unsigned base_instance)
552 {
553 	/* Borrow and update the inputs list from the tnl context */
554 	const struct tnl_vertex_array* arrays = _tnl_bind_inputs(ctx);
555 
556 	TAG(vbo_check_render_prims)(ctx, arrays,
557 				    prims, nr_prims, ib,
558 				    index_bounds_valid, min_index, max_index,
559                                     num_instances, base_instance);
560 }
561 
562 void
TAG(vbo_init)563 TAG(vbo_init)(struct gl_context *ctx)
564 {
565 	struct nouveau_render_state *render = to_render_state(ctx);
566 	int i;
567 
568 	for (i = 0; i < VERT_ATTRIB_MAX; i++)
569 		render->map[i] = -1;
570 
571 	/* Overwrite our draw function */
572 	ctx->Driver.Draw = TAG(vbo_draw);
573 }
574 
575 void
TAG(vbo_destroy)576 TAG(vbo_destroy)(struct gl_context *ctx)
577 {
578 }
579