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 43static int 44get_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 58static void 59vbo_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 95static void 96vbo_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 120static void 121vbo_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 138static void 139vbo_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 181static void 182vbo_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 224static int 225get_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 240static void 241TAG(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 249static GLboolean 250vbo_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 290static GLboolean 291check_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 311static void 312vbo_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 388static void 389vbo_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 432static unsigned 433extract_id(struct nouveau_array *a, int i, int j) 434{ 435 return j; 436} 437 438static void 439vbo_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 483static void 484TAG(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 519static void 520TAG(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 543static void 544TAG(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 562void 563TAG(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 575void 576TAG(vbo_destroy)(struct gl_context *ctx) 577{ 578} 579