Home | History | Annotate | Download | only in nouveau
      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/image.h"
     34 
     35 /* Arbitrary pushbuf length we can assume we can get with a single
     36  * call to WAIT_RING. */
     37 #define PUSHBUF_DWORDS 65536
     38 
     39 /* Functions to turn GL arrays or index buffers into nouveau_array
     40  * structures. */
     41 
     42 static int
     43 get_array_stride(struct gl_context *ctx, const struct gl_vertex_array *a)
     44 {
     45 	struct nouveau_render_state *render = to_render_state(ctx);
     46 
     47 	if (render->mode == VBO && !_mesa_is_bufferobj(a->BufferObj))
     48 		/* Pack client buffers. */
     49 		return align(_mesa_sizeof_type(a->Type) * a->Size, 4);
     50 	else
     51 		return a->StrideB;
     52 }
     53 
     54 static void
     55 vbo_init_arrays(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
     56 		const struct gl_vertex_array **arrays)
     57 {
     58 	struct nouveau_render_state *render = to_render_state(ctx);
     59 	GLboolean imm = (render->mode == IMM);
     60 	int i, attr;
     61 
     62 	if (ib)
     63 		nouveau_init_array(&render->ib, 0, 0, ib->count, ib->type,
     64 				   ib->obj, ib->ptr, GL_TRUE, ctx);
     65 
     66 	FOR_EACH_BOUND_ATTR(render, i, attr) {
     67 		const struct gl_vertex_array *array = arrays[attr];
     68 
     69 		nouveau_init_array(&render->attrs[attr], attr,
     70 				   get_array_stride(ctx, array),
     71 				   array->Size, array->Type,
     72 				   imm ? array->BufferObj : NULL,
     73 				   array->Ptr, imm, ctx);
     74 	}
     75 }
     76 
     77 static void
     78 vbo_deinit_arrays(struct gl_context *ctx, const struct _mesa_index_buffer *ib,
     79 		  const struct gl_vertex_array **arrays)
     80 {
     81 	struct nouveau_render_state *render = to_render_state(ctx);
     82 	int i, attr;
     83 
     84 	if (ib)
     85 		nouveau_cleanup_array(&render->ib);
     86 
     87 	FOR_EACH_BOUND_ATTR(render, i, attr) {
     88 		struct nouveau_array *a = &render->attrs[attr];
     89 
     90 		if (render->mode == IMM)
     91 			nouveau_bo_ref(NULL, &a->bo);
     92 
     93 		nouveau_deinit_array(a);
     94 		render->map[i] = -1;
     95 	}
     96 
     97 	render->attr_count = 0;
     98 }
     99 
    100 /* Make some rendering decisions from the GL context. */
    101 
    102 static void
    103 vbo_choose_render_mode(struct gl_context *ctx, const struct gl_vertex_array **arrays)
    104 {
    105 	struct nouveau_render_state *render = to_render_state(ctx);
    106 	int i;
    107 
    108 	render->mode = VBO;
    109 
    110 	if (ctx->Light.Enabled) {
    111 		for (i = 0; i < MAT_ATTRIB_MAX; i++) {
    112 			if (arrays[VERT_ATTRIB_GENERIC0 + i]->StrideB) {
    113 				render->mode = IMM;
    114 				break;
    115 			}
    116 		}
    117 	}
    118 }
    119 
    120 static void
    121 vbo_emit_attr(struct gl_context *ctx, const struct gl_vertex_array **arrays,
    122 	      int attr)
    123 {
    124 	struct nouveau_pushbuf *push = context_push(ctx);
    125 	struct nouveau_render_state *render = to_render_state(ctx);
    126 	const struct gl_vertex_array *array = arrays[attr];
    127 	struct nouveau_array *a = &render->attrs[attr];
    128 	RENDER_LOCALS(ctx);
    129 
    130 	if (!array->StrideB) {
    131 		if (attr >= VERT_ATTRIB_GENERIC0)
    132 			/* nouveau_update_state takes care of materials. */
    133 			return;
    134 
    135 		/* Constant attribute. */
    136 		nouveau_init_array(a, attr, array->StrideB, array->Size,
    137 				   array->Type, array->BufferObj, array->Ptr,
    138 				   GL_TRUE, ctx);
    139 		EMIT_IMM(ctx, a, 0);
    140 		nouveau_deinit_array(a);
    141 
    142 	} else {
    143 		/* Varying attribute. */
    144 		struct nouveau_attr_info *info = &TAG(vertex_attrs)[attr];
    145 
    146 		if (render->mode == VBO) {
    147 			render->map[info->vbo_index] = attr;
    148 			render->vertex_size += array->_ElementSize;
    149 			render->attr_count = MAX2(render->attr_count,
    150 						  info->vbo_index + 1);
    151 		} else {
    152 			render->map[render->attr_count++] = attr;
    153 			render->vertex_size += 4 * info->imm_fields;
    154 		}
    155 	}
    156 }
    157 
    158 #define MAT(a) (VERT_ATTRIB_GENERIC0 + MAT_ATTRIB_##a)
    159 
    160 static void
    161 vbo_choose_attrs(struct gl_context *ctx, const struct gl_vertex_array **arrays)
    162 {
    163 	struct nouveau_render_state *render = to_render_state(ctx);
    164 	int i;
    165 
    166 	/* Reset the vertex size. */
    167 	render->vertex_size = 0;
    168 	render->attr_count = 0;
    169 
    170 	vbo_emit_attr(ctx, arrays, VERT_ATTRIB_COLOR0);
    171 	if (ctx->Fog.ColorSumEnabled && !ctx->Light.Enabled)
    172 		vbo_emit_attr(ctx, arrays, VERT_ATTRIB_COLOR1);
    173 
    174 	for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
    175 		if (ctx->Texture._EnabledCoordUnits & (1 << i))
    176 			vbo_emit_attr(ctx, arrays, VERT_ATTRIB_TEX0 + i);
    177 	}
    178 
    179 	if (ctx->Fog.Enabled && ctx->Fog.FogCoordinateSource == GL_FOG_COORD)
    180 		vbo_emit_attr(ctx, arrays, VERT_ATTRIB_FOG);
    181 
    182 	if (ctx->Light.Enabled ||
    183 	    (ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS))
    184 		vbo_emit_attr(ctx, arrays, VERT_ATTRIB_NORMAL);
    185 
    186 	if (ctx->Light.Enabled && render->mode == IMM) {
    187 		vbo_emit_attr(ctx, arrays, MAT(FRONT_AMBIENT));
    188 		vbo_emit_attr(ctx, arrays, MAT(FRONT_DIFFUSE));
    189 		vbo_emit_attr(ctx, arrays, MAT(FRONT_SPECULAR));
    190 		vbo_emit_attr(ctx, arrays, MAT(FRONT_SHININESS));
    191 
    192 		if (ctx->Light.Model.TwoSide) {
    193 			vbo_emit_attr(ctx, arrays, MAT(BACK_AMBIENT));
    194 			vbo_emit_attr(ctx, arrays, MAT(BACK_DIFFUSE));
    195 			vbo_emit_attr(ctx, arrays, MAT(BACK_SPECULAR));
    196 			vbo_emit_attr(ctx, arrays, MAT(BACK_SHININESS));
    197 		}
    198 	}
    199 
    200 	vbo_emit_attr(ctx, arrays, VERT_ATTRIB_POS);
    201 }
    202 
    203 static int
    204 get_max_client_stride(struct gl_context *ctx, const struct gl_vertex_array **arrays)
    205 {
    206 	struct nouveau_render_state *render = to_render_state(ctx);
    207 	int i, attr, s = 0;
    208 
    209 	FOR_EACH_BOUND_ATTR(render, i, attr) {
    210 		const struct gl_vertex_array *a = arrays[attr];
    211 
    212 		if (!_mesa_is_bufferobj(a->BufferObj))
    213 			s = MAX2(s, get_array_stride(ctx, a));
    214 	}
    215 
    216 	return s;
    217 }
    218 
    219 static void
    220 TAG(vbo_render_prims)(struct gl_context *ctx,
    221 		      const struct _mesa_prim *prims, GLuint nr_prims,
    222 		      const struct _mesa_index_buffer *ib,
    223 		      GLboolean index_bounds_valid,
    224 		      GLuint min_index, GLuint max_index,
    225 		      struct gl_transform_feedback_object *tfb_vertcount,
    226                       unsigned stream,
    227 		      struct gl_buffer_object *indirect);
    228 
    229 static GLboolean
    230 vbo_maybe_split(struct gl_context *ctx, const struct gl_vertex_array **arrays,
    231 	    const struct _mesa_prim *prims, GLuint nr_prims,
    232 	    const struct _mesa_index_buffer *ib,
    233 	    GLuint min_index, GLuint max_index)
    234 {
    235 	struct nouveau_context *nctx = to_nouveau_context(ctx);
    236 	struct nouveau_render_state *render = to_render_state(ctx);
    237 	struct nouveau_bufctx *bufctx = nctx->hw.bufctx;
    238 	unsigned pushbuf_avail = PUSHBUF_DWORDS - 2 * (bufctx->relocs +
    239 						       render->attr_count),
    240 		vert_avail = get_max_vertices(ctx, NULL, pushbuf_avail),
    241 		idx_avail = get_max_vertices(ctx, ib, pushbuf_avail);
    242 	int stride;
    243 
    244 	/* Try to keep client buffers smaller than the scratch BOs. */
    245 	if (render->mode == VBO &&
    246 	    (stride = get_max_client_stride(ctx, arrays)))
    247 		    vert_avail = MIN2(vert_avail,
    248 				      NOUVEAU_SCRATCH_SIZE / stride);
    249 
    250 	if (max_index - min_index > vert_avail ||
    251 	    (ib && ib->count > idx_avail)) {
    252 		struct split_limits limits = {
    253 			.max_verts = vert_avail,
    254 			.max_indices = idx_avail,
    255 			.max_vb_size = ~0,
    256 		};
    257 
    258 		vbo_split_prims(ctx, arrays, prims, nr_prims, ib, min_index,
    259 				max_index, TAG(vbo_render_prims), &limits);
    260 		return GL_TRUE;
    261 	}
    262 
    263 	return GL_FALSE;
    264 }
    265 
    266 /* VBO rendering path. */
    267 
    268 static GLboolean
    269 check_update_array(struct nouveau_array *a, unsigned offset,
    270 		   struct nouveau_bo *bo, int *pdelta)
    271 {
    272 	int delta = *pdelta;
    273 	GLboolean dirty;
    274 
    275 	if (a->bo == bo) {
    276 		if (delta < 0)
    277 			delta = ((int)offset - (int)a->offset) / a->stride;
    278 
    279 		dirty = (delta < 0 ||
    280 			 offset != (a->offset + delta * a->stride));
    281 	} else {
    282 		dirty = GL_TRUE;
    283 	}
    284 
    285 	*pdelta = (dirty ? 0 : delta);
    286 	return dirty;
    287 }
    288 
    289 static void
    290 vbo_bind_vertices(struct gl_context *ctx, const struct gl_vertex_array **arrays,
    291 		  int base, unsigned min_index, unsigned max_index, int *pdelta)
    292 {
    293 	struct nouveau_render_state *render = to_render_state(ctx);
    294 	struct nouveau_pushbuf *push = context_push(ctx);
    295 	struct nouveau_bo *bo[NUM_VERTEX_ATTRS];
    296 	unsigned offset[NUM_VERTEX_ATTRS];
    297 	GLboolean dirty = GL_FALSE;
    298 	int i, j, attr;
    299 	RENDER_LOCALS(ctx);
    300 
    301 	*pdelta = -1;
    302 
    303 	FOR_EACH_BOUND_ATTR(render, i, attr) {
    304 		const struct gl_vertex_array *array = arrays[attr];
    305 		struct gl_buffer_object *obj = array->BufferObj;
    306 		struct nouveau_array *a = &render->attrs[attr];
    307 		unsigned delta = (base + min_index) * array->StrideB;
    308 
    309 		bo[i] = NULL;
    310 
    311 		if (nouveau_bufferobj_hw(obj)) {
    312 			/* Array in a buffer obj. */
    313 			nouveau_bo_ref(to_nouveau_bufferobj(obj)->bo, &bo[i]);
    314 			offset[i] = delta + (intptr_t)array->Ptr;
    315 
    316 		} else {
    317 			int n = max_index - min_index + 1;
    318 			char *sp = (char *)ADD_POINTERS(
    319 				nouveau_bufferobj_sys(obj), array->Ptr) + delta;
    320 			char *dp  = nouveau_get_scratch(ctx, n * a->stride,
    321 							&bo[i], &offset[i]);
    322 
    323 			/* Array in client memory, move it to a
    324 			 * scratch buffer obj. */
    325 			for (j = 0; j < n; j++)
    326 				memcpy(dp + j * a->stride,
    327 				       sp + j * array->StrideB,
    328 				       a->stride);
    329 		}
    330 
    331 		dirty |= check_update_array(a, offset[i], bo[i], pdelta);
    332 	}
    333 
    334 	*pdelta -= min_index;
    335 
    336 	if (dirty) {
    337 		/* Buffers changed, update the attribute binding. */
    338 		FOR_EACH_BOUND_ATTR(render, i, attr) {
    339 			struct nouveau_array *a = &render->attrs[attr];
    340 
    341 			nouveau_bo_ref(NULL, &a->bo);
    342 			a->offset = offset[i];
    343 			a->bo = bo[i];
    344 		}
    345 
    346 		TAG(render_release_vertices)(ctx);
    347 		TAG(render_bind_vertices)(ctx);
    348 	} else {
    349 		/* Just cleanup. */
    350 		FOR_EACH_BOUND_ATTR(render, i, attr)
    351 			nouveau_bo_ref(NULL, &bo[i]);
    352 	}
    353 
    354 	BATCH_VALIDATE();
    355 }
    356 
    357 static void
    358 vbo_draw_vbo(struct gl_context *ctx, const struct gl_vertex_array **arrays,
    359 	     const struct _mesa_prim *prims, GLuint nr_prims,
    360 	     const struct _mesa_index_buffer *ib, GLuint min_index,
    361 	     GLuint max_index)
    362 {
    363 	struct nouveau_context *nctx = to_nouveau_context(ctx);
    364 	struct nouveau_pushbuf *push = context_push(ctx);
    365 	dispatch_t dispatch = get_array_dispatch(&to_render_state(ctx)->ib);
    366 	int i, delta = 0, basevertex = 0;
    367 	RENDER_LOCALS(ctx);
    368 
    369 	TAG(render_set_format)(ctx);
    370 
    371 	for (i = 0; i < nr_prims; i++) {
    372 		unsigned start = prims[i].start,
    373 			count = prims[i].count;
    374 
    375 		if (i == 0 || basevertex != prims[i].basevertex) {
    376 			basevertex = prims[i].basevertex;
    377 			vbo_bind_vertices(ctx, arrays, basevertex, min_index,
    378 					  max_index, &delta);
    379 
    380 			nouveau_pushbuf_bufctx(push, nctx->hw.bufctx);
    381 			if (nouveau_pushbuf_validate(push)) {
    382 				nouveau_pushbuf_bufctx(push, NULL);
    383 				return;
    384 			}
    385 		}
    386 
    387 		if (count > get_max_vertices(ctx, ib, PUSH_AVAIL(push)))
    388 			PUSH_SPACE(push, PUSHBUF_DWORDS);
    389 
    390 		BATCH_BEGIN(nvgl_primitive(prims[i].mode));
    391 		dispatch(ctx, start, delta, count);
    392 		BATCH_END();
    393 	}
    394 
    395 	nouveau_pushbuf_bufctx(push, NULL);
    396 	TAG(render_release_vertices)(ctx);
    397 }
    398 
    399 /* Immediate rendering path. */
    400 
    401 static unsigned
    402 extract_id(struct nouveau_array *a, int i, int j)
    403 {
    404 	return j;
    405 }
    406 
    407 static void
    408 vbo_draw_imm(struct gl_context *ctx, const struct gl_vertex_array **arrays,
    409 	     const struct _mesa_prim *prims, GLuint nr_prims,
    410 	     const struct _mesa_index_buffer *ib, GLuint min_index,
    411 	     GLuint max_index)
    412 {
    413 	struct nouveau_render_state *render = to_render_state(ctx);
    414 	struct nouveau_context *nctx = to_nouveau_context(ctx);
    415 	struct nouveau_pushbuf *push = context_push(ctx);
    416 	extract_u_t extract = ib ? render->ib.extract_u : extract_id;
    417 	int i, j, k, attr;
    418 	RENDER_LOCALS(ctx);
    419 
    420 	nouveau_pushbuf_bufctx(push, nctx->hw.bufctx);
    421 	if (nouveau_pushbuf_validate(push)) {
    422 		nouveau_pushbuf_bufctx(push, NULL);
    423 		return;
    424 	}
    425 
    426 	for (i = 0; i < nr_prims; i++) {
    427 		unsigned start = prims[i].start,
    428 			end = start + prims[i].count;
    429 
    430 		if (prims[i].count > get_max_vertices(ctx, ib,
    431 						      PUSH_AVAIL(push)))
    432 			PUSH_SPACE(push, PUSHBUF_DWORDS);
    433 
    434 		BATCH_BEGIN(nvgl_primitive(prims[i].mode));
    435 
    436 		for (; start < end; start++) {
    437 			j = prims[i].basevertex +
    438 				extract(&render->ib, 0, start);
    439 
    440 			FOR_EACH_BOUND_ATTR(render, k, attr)
    441 				EMIT_IMM(ctx, &render->attrs[attr], j);
    442 		}
    443 
    444 		BATCH_END();
    445 	}
    446 
    447 	nouveau_pushbuf_bufctx(push, NULL);
    448 }
    449 
    450 /* draw_prims entry point when we're doing hw-tnl. */
    451 
    452 static void
    453 TAG(vbo_render_prims)(struct gl_context *ctx,
    454 		      const struct _mesa_prim *prims, GLuint nr_prims,
    455 		      const struct _mesa_index_buffer *ib,
    456 		      GLboolean index_bounds_valid,
    457 		      GLuint min_index, GLuint max_index,
    458 		      struct gl_transform_feedback_object *tfb_vertcount,
    459                       unsigned stream,
    460 		      struct gl_buffer_object *indirect)
    461 {
    462 	struct nouveau_render_state *render = to_render_state(ctx);
    463 	const struct gl_vertex_array **arrays = ctx->Array._DrawArrays;
    464 
    465 	if (!index_bounds_valid)
    466 		vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
    467 				       nr_prims);
    468 
    469 	vbo_choose_render_mode(ctx, arrays);
    470 	vbo_choose_attrs(ctx, arrays);
    471 
    472 	if (vbo_maybe_split(ctx, arrays, prims, nr_prims, ib, min_index,
    473 			    max_index))
    474 		return;
    475 
    476 	vbo_init_arrays(ctx, ib, arrays);
    477 
    478 	if (render->mode == VBO)
    479 		vbo_draw_vbo(ctx, arrays, prims, nr_prims, ib, min_index,
    480 			     max_index);
    481 	else
    482 		vbo_draw_imm(ctx, arrays, prims, nr_prims, ib, min_index,
    483 			     max_index);
    484 
    485 	vbo_deinit_arrays(ctx, ib, arrays);
    486 }
    487 
    488 /* VBO rendering entry points. */
    489 
    490 static void
    491 TAG(vbo_check_render_prims)(struct gl_context *ctx,
    492 			    const struct _mesa_prim *prims, GLuint nr_prims,
    493 			    const struct _mesa_index_buffer *ib,
    494 			    GLboolean index_bounds_valid,
    495 			    GLuint min_index, GLuint max_index,
    496 			    struct gl_transform_feedback_object *tfb_vertcount,
    497                             unsigned stream,
    498 			    struct gl_buffer_object *indirect)
    499 {
    500 	struct nouveau_context *nctx = to_nouveau_context(ctx);
    501 
    502 	nouveau_validate_framebuffer(ctx);
    503 
    504 	if (nctx->fallback == HWTNL)
    505 		TAG(vbo_render_prims)(ctx, prims, nr_prims, ib,
    506 				      index_bounds_valid, min_index, max_index,
    507 				      tfb_vertcount, stream, indirect);
    508 
    509 	if (nctx->fallback == SWTNL)
    510 		_tnl_draw_prims(ctx, prims, nr_prims, ib,
    511 				index_bounds_valid, min_index, max_index,
    512 				tfb_vertcount, stream, indirect);
    513 }
    514 
    515 void
    516 TAG(vbo_init)(struct gl_context *ctx)
    517 {
    518 	struct nouveau_render_state *render = to_render_state(ctx);
    519 	int i;
    520 
    521 	for (i = 0; i < VERT_ATTRIB_MAX; i++)
    522 		render->map[i] = -1;
    523 
    524 	vbo_set_draw_func(ctx, TAG(vbo_check_render_prims));
    525 	vbo_use_buffer_objects(ctx);
    526 }
    527 
    528 void
    529 TAG(vbo_destroy)(struct gl_context *ctx)
    530 {
    531 }
    532