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 && !_mesa_is_bufferobj(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 == 4) 70 ib_type = GL_UNSIGNED_INT; 71 else if (ib->index_size == 2) 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 (!_mesa_is_bufferobj(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 struct gl_transform_feedback_object *tfb_vertcount, 248 unsigned stream, 249 struct gl_buffer_object *indirect); 250 251static GLboolean 252vbo_maybe_split(struct gl_context *ctx, const struct tnl_vertex_array *arrays, 253 const struct _mesa_prim *prims, GLuint nr_prims, 254 const struct _mesa_index_buffer *ib, 255 GLuint min_index, GLuint max_index) 256{ 257 struct nouveau_context *nctx = to_nouveau_context(ctx); 258 struct nouveau_render_state *render = to_render_state(ctx); 259 struct nouveau_bufctx *bufctx = nctx->hw.bufctx; 260 unsigned pushbuf_avail = PUSHBUF_DWORDS - 2 * (bufctx->relocs + 261 render->attr_count), 262 vert_avail = get_max_vertices(ctx, NULL, pushbuf_avail), 263 idx_avail = get_max_vertices(ctx, ib, pushbuf_avail); 264 int stride; 265 266 /* Try to keep client buffers smaller than the scratch BOs. */ 267 if (render->mode == VBO && 268 (stride = get_max_client_stride(ctx, arrays))) 269 vert_avail = MIN2(vert_avail, 270 NOUVEAU_SCRATCH_SIZE / stride); 271 272 if (max_index - min_index > vert_avail || 273 (ib && ib->count > idx_avail)) { 274 struct split_limits limits = { 275 .max_verts = vert_avail, 276 .max_indices = idx_avail, 277 .max_vb_size = ~0, 278 }; 279 280 _tnl_split_prims(ctx, arrays, prims, nr_prims, ib, min_index, 281 max_index, 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 char *sp = (char *)ADD_POINTERS( 345 nouveau_bufferobj_sys(obj), p) + delta; 346 char *dp = nouveau_get_scratch(ctx, n * a->stride, 347 &bo[i], &offset[i]); 348 349 /* Array in client memory, move it to a 350 * scratch buffer obj. */ 351 for (j = 0; j < n; j++) 352 memcpy(dp + j * a->stride, 353 sp + j * binding->Stride, 354 a->stride); 355 } 356 357 dirty |= check_update_array(a, offset[i], bo[i], pdelta); 358 } 359 360 *pdelta -= min_index; 361 362 if (dirty) { 363 /* Buffers changed, update the attribute binding. */ 364 FOR_EACH_BOUND_ATTR(render, i, attr) { 365 struct nouveau_array *a = &render->attrs[attr]; 366 367 nouveau_bo_ref(NULL, &a->bo); 368 a->offset = offset[i]; 369 a->bo = bo[i]; 370 } 371 372 TAG(render_release_vertices)(ctx); 373 TAG(render_bind_vertices)(ctx); 374 } else { 375 /* Just cleanup. */ 376 FOR_EACH_BOUND_ATTR(render, i, attr) 377 nouveau_bo_ref(NULL, &bo[i]); 378 } 379 380 BATCH_VALIDATE(); 381} 382 383static void 384vbo_draw_vbo(struct gl_context *ctx, const struct tnl_vertex_array *arrays, 385 const struct _mesa_prim *prims, GLuint nr_prims, 386 const struct _mesa_index_buffer *ib, GLuint min_index, 387 GLuint max_index) 388{ 389 struct nouveau_context *nctx = to_nouveau_context(ctx); 390 struct nouveau_pushbuf *push = context_push(ctx); 391 dispatch_t dispatch = get_array_dispatch(&to_render_state(ctx)->ib); 392 int i, delta = 0, basevertex = 0; 393 RENDER_LOCALS(ctx); 394 395 TAG(render_set_format)(ctx); 396 397 for (i = 0; i < nr_prims; i++) { 398 unsigned start = prims[i].start, 399 count = prims[i].count; 400 401 if (i == 0 || basevertex != prims[i].basevertex) { 402 basevertex = prims[i].basevertex; 403 vbo_bind_vertices(ctx, arrays, basevertex, min_index, 404 max_index, &delta); 405 406 nouveau_pushbuf_bufctx(push, nctx->hw.bufctx); 407 if (nouveau_pushbuf_validate(push)) { 408 nouveau_pushbuf_bufctx(push, NULL); 409 return; 410 } 411 } 412 413 if (count > get_max_vertices(ctx, ib, PUSH_AVAIL(push))) 414 PUSH_SPACE(push, PUSHBUF_DWORDS); 415 416 BATCH_BEGIN(nvgl_primitive(prims[i].mode)); 417 dispatch(ctx, start, delta, count); 418 BATCH_END(); 419 } 420 421 nouveau_pushbuf_bufctx(push, NULL); 422 TAG(render_release_vertices)(ctx); 423} 424 425/* Immediate rendering path. */ 426 427static unsigned 428extract_id(struct nouveau_array *a, int i, int j) 429{ 430 return j; 431} 432 433static void 434vbo_draw_imm(struct gl_context *ctx, const struct tnl_vertex_array *arrays, 435 const struct _mesa_prim *prims, GLuint nr_prims, 436 const struct _mesa_index_buffer *ib, GLuint min_index, 437 GLuint max_index) 438{ 439 struct nouveau_render_state *render = to_render_state(ctx); 440 struct nouveau_context *nctx = to_nouveau_context(ctx); 441 struct nouveau_pushbuf *push = context_push(ctx); 442 extract_u_t extract = ib ? render->ib.extract_u : extract_id; 443 int i, j, k, attr; 444 RENDER_LOCALS(ctx); 445 446 nouveau_pushbuf_bufctx(push, nctx->hw.bufctx); 447 if (nouveau_pushbuf_validate(push)) { 448 nouveau_pushbuf_bufctx(push, NULL); 449 return; 450 } 451 452 for (i = 0; i < nr_prims; i++) { 453 unsigned start = prims[i].start, 454 end = start + prims[i].count; 455 456 if (prims[i].count > get_max_vertices(ctx, ib, 457 PUSH_AVAIL(push))) 458 PUSH_SPACE(push, PUSHBUF_DWORDS); 459 460 BATCH_BEGIN(nvgl_primitive(prims[i].mode)); 461 462 for (; start < end; start++) { 463 j = prims[i].basevertex + 464 extract(&render->ib, 0, start); 465 466 FOR_EACH_BOUND_ATTR(render, k, attr) 467 EMIT_IMM(ctx, &render->attrs[attr], j); 468 } 469 470 BATCH_END(); 471 } 472 473 nouveau_pushbuf_bufctx(push, NULL); 474} 475 476/* draw_prims entry point when we're doing hw-tnl. */ 477 478static void 479TAG(vbo_render_prims)(struct gl_context *ctx, 480 const struct tnl_vertex_array *arrays, 481 const struct _mesa_prim *prims, GLuint nr_prims, 482 const struct _mesa_index_buffer *ib, 483 GLboolean index_bounds_valid, 484 GLuint min_index, GLuint max_index, 485 struct gl_transform_feedback_object *tfb_vertcount, 486 unsigned stream, 487 struct gl_buffer_object *indirect) 488{ 489 struct nouveau_render_state *render = to_render_state(ctx); 490 491 if (!index_bounds_valid) 492 vbo_get_minmax_indices(ctx, prims, ib, &min_index, &max_index, 493 nr_prims); 494 495 vbo_choose_render_mode(ctx, arrays); 496 vbo_choose_attrs(ctx, arrays); 497 498 if (vbo_maybe_split(ctx, arrays, prims, nr_prims, ib, min_index, 499 max_index)) 500 return; 501 502 vbo_init_arrays(ctx, ib, arrays); 503 504 if (render->mode == VBO) 505 vbo_draw_vbo(ctx, arrays, prims, nr_prims, ib, min_index, 506 max_index); 507 else 508 vbo_draw_imm(ctx, arrays, prims, nr_prims, ib, min_index, 509 max_index); 510 511 vbo_deinit_arrays(ctx, ib, arrays); 512} 513 514/* VBO rendering entry points. */ 515 516static void 517TAG(vbo_check_render_prims)(struct gl_context *ctx, 518 const struct tnl_vertex_array *arrays, 519 const struct _mesa_prim *prims, GLuint nr_prims, 520 const struct _mesa_index_buffer *ib, 521 GLboolean index_bounds_valid, 522 GLuint min_index, GLuint max_index, 523 struct gl_transform_feedback_object *tfb_vertcount, 524 unsigned stream, 525 struct gl_buffer_object *indirect) 526{ 527 struct nouveau_context *nctx = to_nouveau_context(ctx); 528 529 nouveau_validate_framebuffer(ctx); 530 531 if (nctx->fallback == HWTNL) 532 TAG(vbo_render_prims)(ctx, arrays, prims, nr_prims, ib, 533 index_bounds_valid, min_index, max_index, 534 tfb_vertcount, stream, indirect); 535 536 if (nctx->fallback == SWTNL) 537 _tnl_draw_prims(ctx, arrays, prims, nr_prims, ib, 538 index_bounds_valid, min_index, max_index, 539 tfb_vertcount, stream, indirect); 540} 541 542static void 543TAG(vbo_draw)(struct gl_context *ctx, 544 const struct _mesa_prim *prims, GLuint nr_prims, 545 const struct _mesa_index_buffer *ib, 546 GLboolean index_bounds_valid, 547 GLuint min_index, GLuint max_index, 548 struct gl_transform_feedback_object *tfb_vertcount, 549 unsigned stream, 550 struct gl_buffer_object *indirect) 551{ 552 /* Borrow and update the inputs list from the tnl context */ 553 const struct tnl_vertex_array* arrays = _tnl_bind_inputs(ctx); 554 555 TAG(vbo_check_render_prims)(ctx, arrays, 556 prims, nr_prims, ib, 557 index_bounds_valid, min_index, max_index, 558 tfb_vertcount, stream, indirect); 559} 560 561void 562TAG(vbo_init)(struct gl_context *ctx) 563{ 564 struct nouveau_render_state *render = to_render_state(ctx); 565 int i; 566 567 for (i = 0; i < VERT_ATTRIB_MAX; i++) 568 render->map[i] = -1; 569 570 /* Overwrite our draw function */ 571 ctx->Driver.Draw = TAG(vbo_draw); 572 vbo_use_buffer_objects(ctx); 573} 574 575void 576TAG(vbo_destroy)(struct gl_context *ctx) 577{ 578} 579