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_client_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_client_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_client_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_client_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_client_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_client_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_client_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_client_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_client_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_client_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 
    227 static GLboolean
    228 vbo_maybe_split(struct gl_context *ctx, const struct gl_client_array **arrays,
    229 	    const struct _mesa_prim *prims, GLuint nr_prims,
    230 	    const struct _mesa_index_buffer *ib,
    231 	    GLuint min_index, GLuint max_index)
    232 {
    233 	struct nouveau_context *nctx = to_nouveau_context(ctx);
    234 	struct nouveau_render_state *render = to_render_state(ctx);
    235 	struct nouveau_bufctx *bufctx = nctx->hw.bufctx;
    236 	unsigned pushbuf_avail = PUSHBUF_DWORDS - 2 * (bufctx->relocs +
    237 						       render->attr_count),
    238 		vert_avail = get_max_vertices(ctx, NULL, pushbuf_avail),
    239 		idx_avail = get_max_vertices(ctx, ib, pushbuf_avail);
    240 	int stride;
    241 
    242 	/* Try to keep client buffers smaller than the scratch BOs. */
    243 	if (render->mode == VBO &&
    244 	    (stride = get_max_client_stride(ctx, arrays)))
    245 		    vert_avail = MIN2(vert_avail,
    246 				      NOUVEAU_SCRATCH_SIZE / stride);
    247 
    248 	if (max_index - min_index > vert_avail ||
    249 	    (ib && ib->count > idx_avail)) {
    250 		struct split_limits limits = {
    251 			.max_verts = vert_avail,
    252 			.max_indices = idx_avail,
    253 			.max_vb_size = ~0,
    254 		};
    255 
    256 		vbo_split_prims(ctx, arrays, prims, nr_prims, ib, min_index,
    257 				max_index, TAG(vbo_render_prims), &limits);
    258 		return GL_TRUE;
    259 	}
    260 
    261 	return GL_FALSE;
    262 }
    263 
    264 /* VBO rendering path. */
    265 
    266 static GLboolean
    267 check_update_array(struct nouveau_array *a, unsigned offset,
    268 		   struct nouveau_bo *bo, int *pdelta)
    269 {
    270 	int delta = *pdelta;
    271 	GLboolean dirty;
    272 
    273 	if (a->bo == bo) {
    274 		if (delta < 0)
    275 			delta = ((int)offset - (int)a->offset) / a->stride;
    276 
    277 		dirty = (delta < 0 ||
    278 			 offset != (a->offset + delta * a->stride));
    279 	} else {
    280 		dirty = GL_TRUE;
    281 	}
    282 
    283 	*pdelta = (dirty ? 0 : delta);
    284 	return dirty;
    285 }
    286 
    287 static void
    288 vbo_bind_vertices(struct gl_context *ctx, const struct gl_client_array **arrays,
    289 		  int base, unsigned min_index, unsigned max_index, int *pdelta)
    290 {
    291 	struct nouveau_render_state *render = to_render_state(ctx);
    292 	struct nouveau_pushbuf *push = context_push(ctx);
    293 	struct nouveau_bo *bo[NUM_VERTEX_ATTRS];
    294 	unsigned offset[NUM_VERTEX_ATTRS];
    295 	GLboolean dirty = GL_FALSE;
    296 	int i, j, attr;
    297 	RENDER_LOCALS(ctx);
    298 
    299 	*pdelta = -1;
    300 
    301 	FOR_EACH_BOUND_ATTR(render, i, attr) {
    302 		const struct gl_client_array *array = arrays[attr];
    303 		struct gl_buffer_object *obj = array->BufferObj;
    304 		struct nouveau_array *a = &render->attrs[attr];
    305 		unsigned delta = (base + min_index) * array->StrideB;
    306 
    307 		bo[i] = NULL;
    308 
    309 		if (nouveau_bufferobj_hw(obj)) {
    310 			/* Array in a buffer obj. */
    311 			nouveau_bo_ref(to_nouveau_bufferobj(obj)->bo, &bo[i]);
    312 			offset[i] = delta + (intptr_t)array->Ptr;
    313 
    314 		} else {
    315 			int n = max_index - min_index + 1;
    316 			char *sp = (char *)ADD_POINTERS(
    317 				nouveau_bufferobj_sys(obj), array->Ptr) + delta;
    318 			char *dp  = nouveau_get_scratch(ctx, n * a->stride,
    319 							&bo[i], &offset[i]);
    320 
    321 			/* Array in client memory, move it to a
    322 			 * scratch buffer obj. */
    323 			for (j = 0; j < n; j++)
    324 				memcpy(dp + j * a->stride,
    325 				       sp + j * array->StrideB,
    326 				       a->stride);
    327 		}
    328 
    329 		dirty |= check_update_array(a, offset[i], bo[i], pdelta);
    330 	}
    331 
    332 	*pdelta -= min_index;
    333 
    334 	if (dirty) {
    335 		/* Buffers changed, update the attribute binding. */
    336 		FOR_EACH_BOUND_ATTR(render, i, attr) {
    337 			struct nouveau_array *a = &render->attrs[attr];
    338 
    339 			nouveau_bo_ref(NULL, &a->bo);
    340 			a->offset = offset[i];
    341 			a->bo = bo[i];
    342 		}
    343 
    344 		TAG(render_release_vertices)(ctx);
    345 		TAG(render_bind_vertices)(ctx);
    346 	} else {
    347 		/* Just cleanup. */
    348 		FOR_EACH_BOUND_ATTR(render, i, attr)
    349 			nouveau_bo_ref(NULL, &bo[i]);
    350 	}
    351 
    352 	BATCH_VALIDATE();
    353 }
    354 
    355 static void
    356 vbo_draw_vbo(struct gl_context *ctx, const struct gl_client_array **arrays,
    357 	     const struct _mesa_prim *prims, GLuint nr_prims,
    358 	     const struct _mesa_index_buffer *ib, GLuint min_index,
    359 	     GLuint max_index)
    360 {
    361 	struct nouveau_context *nctx = to_nouveau_context(ctx);
    362 	struct nouveau_pushbuf *push = context_push(ctx);
    363 	dispatch_t dispatch = get_array_dispatch(&to_render_state(ctx)->ib);
    364 	int i, delta = 0, basevertex = 0;
    365 	RENDER_LOCALS(ctx);
    366 
    367 	TAG(render_set_format)(ctx);
    368 
    369 	for (i = 0; i < nr_prims; i++) {
    370 		unsigned start = prims[i].start,
    371 			count = prims[i].count;
    372 
    373 		if (i == 0 || basevertex != prims[i].basevertex) {
    374 			basevertex = prims[i].basevertex;
    375 			vbo_bind_vertices(ctx, arrays, basevertex, min_index,
    376 					  max_index, &delta);
    377 
    378 			nouveau_pushbuf_bufctx(push, nctx->hw.bufctx);
    379 			if (nouveau_pushbuf_validate(push)) {
    380 				nouveau_pushbuf_bufctx(push, NULL);
    381 				return;
    382 			}
    383 		}
    384 
    385 		if (count > get_max_vertices(ctx, ib, PUSH_AVAIL(push)))
    386 			PUSH_SPACE(push, PUSHBUF_DWORDS);
    387 
    388 		BATCH_BEGIN(nvgl_primitive(prims[i].mode));
    389 		dispatch(ctx, start, delta, count);
    390 		BATCH_END();
    391 	}
    392 
    393 	nouveau_pushbuf_bufctx(push, NULL);
    394 	TAG(render_release_vertices)(ctx);
    395 }
    396 
    397 /* Immediate rendering path. */
    398 
    399 static unsigned
    400 extract_id(struct nouveau_array *a, int i, int j)
    401 {
    402 	return j;
    403 }
    404 
    405 static void
    406 vbo_draw_imm(struct gl_context *ctx, const struct gl_client_array **arrays,
    407 	     const struct _mesa_prim *prims, GLuint nr_prims,
    408 	     const struct _mesa_index_buffer *ib, GLuint min_index,
    409 	     GLuint max_index)
    410 {
    411 	struct nouveau_render_state *render = to_render_state(ctx);
    412 	struct nouveau_context *nctx = to_nouveau_context(ctx);
    413 	struct nouveau_pushbuf *push = context_push(ctx);
    414 	extract_u_t extract = ib ? render->ib.extract_u : extract_id;
    415 	int i, j, k, attr;
    416 	RENDER_LOCALS(ctx);
    417 
    418 	nouveau_pushbuf_bufctx(push, nctx->hw.bufctx);
    419 	if (nouveau_pushbuf_validate(push)) {
    420 		nouveau_pushbuf_bufctx(push, NULL);
    421 		return;
    422 	}
    423 
    424 	for (i = 0; i < nr_prims; i++) {
    425 		unsigned start = prims[i].start,
    426 			end = start + prims[i].count;
    427 
    428 		if (prims[i].count > get_max_vertices(ctx, ib,
    429 						      PUSH_AVAIL(push)))
    430 			PUSH_SPACE(push, PUSHBUF_DWORDS);
    431 
    432 		BATCH_BEGIN(nvgl_primitive(prims[i].mode));
    433 
    434 		for (; start < end; start++) {
    435 			j = prims[i].basevertex +
    436 				extract(&render->ib, 0, start);
    437 
    438 			FOR_EACH_BOUND_ATTR(render, k, attr)
    439 				EMIT_IMM(ctx, &render->attrs[attr], j);
    440 		}
    441 
    442 		BATCH_END();
    443 	}
    444 
    445 	nouveau_pushbuf_bufctx(push, NULL);
    446 }
    447 
    448 /* draw_prims entry point when we're doing hw-tnl. */
    449 
    450 static void
    451 TAG(vbo_render_prims)(struct gl_context *ctx,
    452 		      const struct _mesa_prim *prims, GLuint nr_prims,
    453 		      const struct _mesa_index_buffer *ib,
    454 		      GLboolean index_bounds_valid,
    455 		      GLuint min_index, GLuint max_index,
    456 		      struct gl_transform_feedback_object *tfb_vertcount)
    457 {
    458 	struct nouveau_render_state *render = to_render_state(ctx);
    459 	const struct gl_client_array **arrays = ctx->Array._DrawArrays;
    460 
    461 	if (!index_bounds_valid)
    462 		vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index,
    463 				       nr_prims);
    464 
    465 	vbo_choose_render_mode(ctx, arrays);
    466 	vbo_choose_attrs(ctx, arrays);
    467 
    468 	if (vbo_maybe_split(ctx, arrays, prims, nr_prims, ib, min_index,
    469 			    max_index))
    470 		return;
    471 
    472 	vbo_init_arrays(ctx, ib, arrays);
    473 
    474 	if (render->mode == VBO)
    475 		vbo_draw_vbo(ctx, arrays, prims, nr_prims, ib, min_index,
    476 			     max_index);
    477 	else
    478 		vbo_draw_imm(ctx, arrays, prims, nr_prims, ib, min_index,
    479 			     max_index);
    480 
    481 	vbo_deinit_arrays(ctx, ib, arrays);
    482 }
    483 
    484 /* VBO rendering entry points. */
    485 
    486 static void
    487 TAG(vbo_check_render_prims)(struct gl_context *ctx,
    488 			    const struct _mesa_prim *prims, GLuint nr_prims,
    489 			    const struct _mesa_index_buffer *ib,
    490 			    GLboolean index_bounds_valid,
    491 			    GLuint min_index, GLuint max_index,
    492 			    struct gl_transform_feedback_object *tfb_vertcount)
    493 {
    494 	struct nouveau_context *nctx = to_nouveau_context(ctx);
    495 
    496 	nouveau_validate_framebuffer(ctx);
    497 
    498 	if (nctx->fallback == HWTNL)
    499 		TAG(vbo_render_prims)(ctx, prims, nr_prims, ib,
    500 				      index_bounds_valid, min_index, max_index,
    501 				      tfb_vertcount);
    502 
    503 	if (nctx->fallback == SWTNL)
    504 		_tnl_vbo_draw_prims(ctx, prims, nr_prims, ib,
    505 				    index_bounds_valid, min_index, max_index,
    506 				    tfb_vertcount);
    507 }
    508 
    509 void
    510 TAG(vbo_init)(struct gl_context *ctx)
    511 {
    512 	struct nouveau_render_state *render = to_render_state(ctx);
    513 	int i;
    514 
    515 	for (i = 0; i < VERT_ATTRIB_MAX; i++)
    516 		render->map[i] = -1;
    517 
    518 	vbo_set_draw_func(ctx, TAG(vbo_check_render_prims));
    519 	vbo_use_buffer_objects(ctx);
    520 }
    521 
    522 void
    523 TAG(vbo_destroy)(struct gl_context *ctx)
    524 {
    525 }
    526