nv30_draw.c revision 89585edf3c01c94b62d163adf0209568efa68568
1/* 2 * Copyright 2012 Red Hat Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: Ben Skeggs 23 * 24 */ 25 26#include "draw/draw_context.h" 27#include "draw/draw_vertex.h" 28#include "draw/draw_pipe.h" 29#include "draw/draw_vbuf.h" 30#include "draw/draw_private.h" 31 32#include "nv_object.xml.h" 33#include "nv30/nv30-40_3d.xml.h" 34#include "nv30/nv30_context.h" 35#include "nv30/nv30_format.h" 36 37struct nv30_render { 38 struct vbuf_render base; 39 struct nv30_context *nv30; 40 41 struct pipe_transfer *transfer; 42 struct pipe_resource *buffer; 43 unsigned offset; 44 unsigned length; 45 46 struct vertex_info vertex_info; 47 48 struct nouveau_heap *vertprog; 49 uint32_t vtxprog[16][4]; 50 uint32_t vtxfmt[16]; 51 uint32_t vtxptr[16]; 52 uint32_t prim; 53}; 54 55static INLINE struct nv30_render * 56nv30_render(struct vbuf_render *render) 57{ 58 return (struct nv30_render *)render; 59} 60 61static const struct vertex_info * 62nv30_render_get_vertex_info(struct vbuf_render *render) 63{ 64 return &nv30_render(render)->vertex_info; 65} 66 67static boolean 68nv30_render_allocate_vertices(struct vbuf_render *render, 69 ushort vertex_size, ushort nr_vertices) 70{ 71 struct nv30_render *r = nv30_render(render); 72 struct nv30_context *nv30 = r->nv30; 73 74 r->length = vertex_size * nr_vertices; 75 76 if (r->offset + r->length >= render->max_vertex_buffer_bytes) { 77 pipe_resource_reference(&r->buffer, NULL); 78 r->buffer = pipe_buffer_create(&nv30->screen->base.base, 79 PIPE_BIND_VERTEX_BUFFER, 0, 80 render->max_vertex_buffer_bytes); 81 if (!r->buffer) 82 return FALSE; 83 84 r->offset = 0; 85 } 86 87 return TRUE; 88} 89 90static void * 91nv30_render_map_vertices(struct vbuf_render *render) 92{ 93 struct nv30_render *r = nv30_render(render); 94 char *map = pipe_buffer_map(&r->nv30->base.pipe, r->buffer, 95 PIPE_TRANSFER_WRITE | 96 PIPE_TRANSFER_UNSYNCHRONIZED, &r->transfer); 97 return map + r->offset; 98} 99 100static void 101nv30_render_unmap_vertices(struct vbuf_render *render, 102 ushort min_index, ushort max_index) 103{ 104 struct nv30_render *r = nv30_render(render); 105 pipe_buffer_unmap(&r->nv30->base.pipe, r->transfer); 106 r->transfer = NULL; 107} 108 109static void 110nv30_render_set_primitive(struct vbuf_render *render, unsigned prim) 111{ 112 struct nv30_render *r = nv30_render(render); 113 114 r->prim = nv30_prim_gl(prim); 115} 116 117static void 118nv30_render_draw_elements(struct vbuf_render *render, 119 const ushort *indices, uint count) 120{ 121 struct nv30_render *r = nv30_render(render); 122 struct nv30_context *nv30 = r->nv30; 123 struct nouveau_pushbuf *push = nv30->screen->base.pushbuf; 124 unsigned i; 125 126 BEGIN_NV04(push, NV30_3D(VTXBUF(0)), r->vertex_info.num_attribs); 127 for (i = 0; i < r->vertex_info.num_attribs; i++) { 128 PUSH_RESRC(push, NV30_3D(VTXBUF(i)), BUFCTX_VTXTMP, 129 nv04_resource(r->buffer), r->offset + r->vtxptr[i], 130 NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, 0); 131 } 132 133 if (!nv30_state_validate(nv30, ~0, FALSE)) 134 return; 135 136 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 137 PUSH_DATA (push, r->prim); 138 139 if (count & 1) { 140 BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1); 141 PUSH_DATA (push, *indices++); 142 } 143 144 count >>= 1; 145 while (count) { 146 unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN); 147 count -= npush; 148 149 BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush); 150 while (npush--) { 151 PUSH_DATA(push, (indices[1] << 16) | indices[0]); 152 indices += 2; 153 } 154 } 155 156 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 157 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 158 PUSH_RESET(push, BUFCTX_VTXTMP); 159} 160 161static void 162nv30_render_draw_arrays(struct vbuf_render *render, unsigned start, uint nr) 163{ 164 struct nv30_render *r = nv30_render(render); 165 struct nv30_context *nv30 = r->nv30; 166 struct nouveau_pushbuf *push = nv30->base.pushbuf; 167 unsigned fn = nr >> 8, pn = nr & 0xff; 168 unsigned ps = fn + (pn ? 1 : 0); 169 unsigned i; 170 171 BEGIN_NV04(push, NV30_3D(VTXBUF(0)), r->vertex_info.num_attribs); 172 for (i = 0; i < r->vertex_info.num_attribs; i++) { 173 PUSH_RESRC(push, NV30_3D(VTXBUF(i)), BUFCTX_VTXTMP, 174 nv04_resource(r->buffer), r->offset + r->vtxptr[i], 175 NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, 0); 176 } 177 178 if (!nv30_state_validate(nv30, ~0, FALSE)) 179 return; 180 181 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 182 PUSH_DATA (push, r->prim); 183 184 BEGIN_NI04(push, NV30_3D(VB_VERTEX_BATCH), ps); 185 while (fn--) { 186 PUSH_DATA (push, 0xff000000 | start); 187 start += 256; 188 } 189 190 if (pn) 191 PUSH_DATA (push, ((pn - 1) << 24) | start); 192 193 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1); 194 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP); 195 PUSH_RESET(push, BUFCTX_VTXTMP); 196} 197 198static void 199nv30_render_release_vertices(struct vbuf_render *render) 200{ 201 struct nv30_render *r = nv30_render(render); 202 r->offset += r->length; 203} 204 205static const struct { 206 unsigned emit; 207 unsigned interp; 208 unsigned vp30; 209 unsigned vp40; 210 unsigned ow40; 211} vroute [] = { 212 [TGSI_SEMANTIC_POSITION] = { EMIT_4F, INTERP_PERSPECTIVE, 0, 0, 0x00000000 }, 213 [TGSI_SEMANTIC_COLOR ] = { EMIT_4F, INTERP_LINEAR , 3, 1, 0x00000001 }, 214 [TGSI_SEMANTIC_BCOLOR ] = { EMIT_4F, INTERP_LINEAR , 1, 3, 0x00000004 }, 215 [TGSI_SEMANTIC_FOG ] = { EMIT_4F, INTERP_PERSPECTIVE, 5, 5, 0x00000010 }, 216 [TGSI_SEMANTIC_PSIZE ] = { EMIT_1F_PSIZE, INTERP_POS , 6, 6, 0x00000020 }, 217 [TGSI_SEMANTIC_GENERIC ] = { EMIT_4F, INTERP_PERSPECTIVE, 8, 7, 0x00004000 } 218}; 219 220static boolean 221vroute_add(struct nv30_render *r, uint attrib, uint sem, uint *idx) 222{ 223 struct pipe_screen *pscreen = &r->nv30->screen->base.base; 224 struct nv30_fragprog *fp = r->nv30->fragprog.program; 225 struct vertex_info *vinfo = &r->vertex_info; 226 enum pipe_format format; 227 uint emit = EMIT_OMIT; 228 uint result = *idx; 229 230 if (sem == TGSI_SEMANTIC_GENERIC && result >= 8) { 231 for (result = 0; result < 8; result++) { 232 if (fp->texcoord[result] == *idx) { 233 emit = vroute[sem].emit; 234 break; 235 } 236 } 237 } else { 238 emit = vroute[sem].emit; 239 } 240 241 if (emit == EMIT_OMIT) 242 return FALSE; 243 244 draw_emit_vertex_attr(vinfo, emit, vroute[sem].interp, attrib); 245 format = draw_translate_vinfo_format(emit); 246 247 r->vtxfmt[attrib] = nv30_vtxfmt(pscreen, format)->hw; 248 r->vtxptr[attrib] = vinfo->size | NV30_3D_VTXBUF_DMA1; 249 vinfo->size += draw_translate_vinfo_size(emit); 250 251 if (nv30_screen(pscreen)->eng3d->oclass < NV40_3D_CLASS) { 252 r->vtxprog[attrib][0] = 0x001f38d8; 253 r->vtxprog[attrib][1] = 0x0080001b | (attrib << 9); 254 r->vtxprog[attrib][2] = 0x0836106c; 255 r->vtxprog[attrib][3] = 0x2000f800 | (result + vroute[sem].vp30) << 2; 256 } else { 257 r->vtxprog[attrib][0] = 0x401f9c6c; 258 r->vtxprog[attrib][1] = 0x0040000d | (attrib << 8); 259 r->vtxprog[attrib][2] = 0x8106c083; 260 r->vtxprog[attrib][3] = 0x6041ff80 | (result + vroute[sem].vp40) << 2; 261 } 262 263 *idx = vroute[sem].ow40 << result; 264 return TRUE; 265} 266 267static boolean 268nv30_render_validate(struct nv30_context *nv30) 269{ 270 struct nv30_render *r = nv30_render(nv30->draw->render); 271 struct nv30_rasterizer_stateobj *rast = nv30->rast; 272 struct pipe_screen *pscreen = &nv30->screen->base.base; 273 struct nouveau_pushbuf *push = nv30->screen->base.pushbuf; 274 struct nouveau_object *eng3d = nv30->screen->eng3d; 275 struct nv30_vertprog *vp = nv30->vertprog.program; 276 struct vertex_info *vinfo = &r->vertex_info; 277 unsigned vp_attribs = 0; 278 unsigned vp_results = 0; 279 unsigned attrib = 0; 280 unsigned pntc; 281 int i; 282 283 if (!r->vertprog) { 284 struct nouveau_heap *heap = nv30_screen(pscreen)->vp_exec_heap; 285 if (nouveau_heap_alloc(heap, 16, &r->vertprog, &r->vertprog)) { 286 while (heap->next && heap->size < 16) { 287 struct nouveau_heap **evict = heap->next->priv; 288 nouveau_heap_free(evict); 289 } 290 291 if (nouveau_heap_alloc(heap, 16, &r->vertprog, &r->vertprog)) 292 return FALSE; 293 } 294 } 295 296 vinfo->num_attribs = 0; 297 vinfo->size = 0; 298 299 /* setup routing for all necessary vp outputs */ 300 for (i = 0; i < vp->info.num_outputs && attrib < 16; i++) { 301 uint semantic = vp->info.output_semantic_name[i]; 302 uint index = vp->info.output_semantic_index[i]; 303 if (vroute_add(r, attrib, semantic, &index)) { 304 vp_attribs |= (1 << attrib++); 305 vp_results |= index; 306 } 307 } 308 309 /* setup routing for replaced point coords not written by vp */ 310 if (rast && rast->pipe.point_quad_rasterization) 311 pntc = rast->pipe.sprite_coord_enable & 0x000002ff; 312 else 313 pntc = 0; 314 315 while (pntc && attrib < 16) { 316 uint index = ffs(pntc) - 1; pntc &= ~(1 << index); 317 if (vroute_add(r, attrib, TGSI_SEMANTIC_GENERIC, &index)) { 318 vp_attribs |= (1 << attrib++); 319 vp_results |= index; 320 } 321 } 322 323 /* modify vertex format for correct stride, and stub out unused ones */ 324 BEGIN_NV04(push, NV30_3D(VP_UPLOAD_FROM_ID), 1); 325 PUSH_DATA (push, r->vertprog->start); 326 r->vtxprog[attrib - 1][3] |= 1; 327 for (i = 0; i < attrib; i++) { 328 BEGIN_NV04(push, NV30_3D(VP_UPLOAD_INST(0)), 4); 329 PUSH_DATAp(push, r->vtxprog[i], 4); 330 r->vtxfmt[i] |= vinfo->size << 8; 331 } 332 for (; i < 16; i++) 333 r->vtxfmt[i] = NV30_3D_VTXFMT_TYPE_V32_FLOAT; 334 335 BEGIN_NV04(push, NV30_3D(VIEWPORT_TRANSLATE_X), 8); 336 PUSH_DATAf(push, 0.0); 337 PUSH_DATAf(push, 0.0); 338 PUSH_DATAf(push, 0.0); 339 PUSH_DATAf(push, 0.0); 340 PUSH_DATAf(push, 1.0); 341 PUSH_DATAf(push, 1.0); 342 PUSH_DATAf(push, 1.0); 343 PUSH_DATAf(push, 1.0); 344 BEGIN_NV04(push, NV30_3D(DEPTH_RANGE_NEAR), 2); 345 PUSH_DATAf(push, 0.0); 346 PUSH_DATAf(push, 1.0); 347 348 BEGIN_NV04(push, NV30_3D(VTXFMT(0)), 16); 349 PUSH_DATAp(push, r->vtxfmt, 16); 350 351 BEGIN_NV04(push, NV30_3D(VP_START_FROM_ID), 1); 352 PUSH_DATA (push, r->vertprog->start); 353 BEGIN_NV04(push, NV30_3D(ENGINE), 1); 354 PUSH_DATA (push, 0x00000103); 355 if (eng3d->oclass >= NV40_3D_CLASS) { 356 BEGIN_NV04(push, NV40_3D(VP_ATTRIB_EN), 2); 357 PUSH_DATA (push, vp_attribs); 358 PUSH_DATA (push, vp_results); 359 } 360 361 vinfo->size /= 4; 362 return TRUE; 363} 364 365void 366nv30_render_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info) 367{ 368 struct nv30_context *nv30 = nv30_context(pipe); 369 struct draw_context *draw = nv30->draw; 370 struct pipe_transfer *transfer[PIPE_MAX_ATTRIBS] = {NULL}; 371 struct pipe_transfer *transferi = NULL; 372 int i; 373 374 nv30_render_validate(nv30); 375 376 if (nv30->draw_dirty & NV30_NEW_VIEWPORT) 377 draw_set_viewport_states(draw, 0, 1, &nv30->viewport); 378 if (nv30->draw_dirty & NV30_NEW_RASTERIZER) 379 draw_set_rasterizer_state(draw, &nv30->rast->pipe, NULL); 380 if (nv30->draw_dirty & NV30_NEW_CLIP) 381 draw_set_clip_state(draw, &nv30->clip); 382 if (nv30->draw_dirty & NV30_NEW_ARRAYS) { 383 draw_set_vertex_buffers(draw, 0, nv30->num_vtxbufs, nv30->vtxbuf); 384 draw_set_vertex_elements(draw, nv30->vertex->num_elements, nv30->vertex->pipe); 385 } 386 if (nv30->draw_dirty & NV30_NEW_FRAGPROG) { 387 struct nv30_fragprog *fp = nv30->fragprog.program; 388 if (!fp->draw) 389 fp->draw = draw_create_fragment_shader(draw, &fp->pipe); 390 draw_bind_fragment_shader(draw, fp->draw); 391 } 392 if (nv30->draw_dirty & NV30_NEW_VERTPROG) { 393 struct nv30_vertprog *vp = nv30->vertprog.program; 394 if (!vp->draw) 395 vp->draw = draw_create_vertex_shader(draw, &vp->pipe); 396 draw_bind_vertex_shader(draw, vp->draw); 397 } 398 if (nv30->draw_dirty & NV30_NEW_VERTCONST) { 399 if (nv30->vertprog.constbuf) { 400 void *map = nv04_resource(nv30->vertprog.constbuf)->data; 401 draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, 402 map, nv30->vertprog.constbuf_nr); 403 } else { 404 draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, NULL, 0); 405 } 406 } 407 408 for (i = 0; i < nv30->num_vtxbufs; i++) { 409 const void *map = nv30->vtxbuf[i].user_buffer; 410 if (!map) { 411 if (nv30->vtxbuf[i].buffer) 412 map = pipe_buffer_map(pipe, nv30->vtxbuf[i].buffer, 413 PIPE_TRANSFER_UNSYNCHRONIZED | 414 PIPE_TRANSFER_READ, &transfer[i]); 415 } 416 draw_set_mapped_vertex_buffer(draw, i, map, ~0); 417 } 418 419 if (info->indexed) { 420 const void *map = nv30->idxbuf.user_buffer; 421 if (!map) 422 pipe_buffer_map(pipe, nv30->idxbuf.buffer, 423 PIPE_TRANSFER_UNSYNCHRONIZED | 424 PIPE_TRANSFER_READ, &transferi); 425 draw_set_indexes(draw, 426 (ubyte *) map + nv30->idxbuf.offset, 427 nv30->idxbuf.index_size, ~0); 428 } else { 429 draw_set_indexes(draw, NULL, 0, 0); 430 } 431 432 draw_vbo(draw, info); 433 draw_flush(draw); 434 435 if (info->indexed && transferi) 436 pipe_buffer_unmap(pipe, transferi); 437 for (i = 0; i < nv30->num_vtxbufs; i++) 438 if (transfer[i]) 439 pipe_buffer_unmap(pipe, transfer[i]); 440 441 nv30->draw_dirty = 0; 442 nv30_state_release(nv30); 443} 444 445static void 446nv30_render_destroy(struct vbuf_render *render) 447{ 448 struct nv30_render *r = nv30_render(render); 449 450 if (r->transfer) 451 pipe_buffer_unmap(&r->nv30->base.pipe, r->transfer); 452 pipe_resource_reference(&r->buffer, NULL); 453 nouveau_heap_free(&r->vertprog); 454 FREE(render); 455} 456 457static struct vbuf_render * 458nv30_render_create(struct nv30_context *nv30) 459{ 460 struct nv30_render *r = CALLOC_STRUCT(nv30_render); 461 if (!r) 462 return NULL; 463 464 r->nv30 = nv30; 465 r->offset = 1 * 1024 * 1024; 466 467 r->base.max_indices = 16 * 1024; 468 r->base.max_vertex_buffer_bytes = r->offset; 469 470 r->base.get_vertex_info = nv30_render_get_vertex_info; 471 r->base.allocate_vertices = nv30_render_allocate_vertices; 472 r->base.map_vertices = nv30_render_map_vertices; 473 r->base.unmap_vertices = nv30_render_unmap_vertices; 474 r->base.set_primitive = nv30_render_set_primitive; 475 r->base.draw_elements = nv30_render_draw_elements; 476 r->base.draw_arrays = nv30_render_draw_arrays; 477 r->base.release_vertices = nv30_render_release_vertices; 478 r->base.destroy = nv30_render_destroy; 479 return &r->base; 480} 481 482void 483nv30_draw_init(struct pipe_context *pipe) 484{ 485 struct nv30_context *nv30 = nv30_context(pipe); 486 struct vbuf_render *render; 487 struct draw_context *draw; 488 struct draw_stage *stage; 489 490 draw = draw_create(pipe); 491 if (!draw) 492 return; 493 494 render = nv30_render_create(nv30); 495 if (!render) { 496 draw_destroy(draw); 497 return; 498 } 499 500 stage = draw_vbuf_stage(draw, render); 501 if (!stage) { 502 render->destroy(render); 503 draw_destroy(draw); 504 return; 505 } 506 507 draw_set_render(draw, render); 508 draw_set_rasterize_stage(draw, stage); 509 draw_wide_line_threshold(draw, 10000000.f); 510 draw_wide_point_threshold(draw, 10000000.f); 511 draw_wide_point_sprites(draw, TRUE); 512 nv30->draw = draw; 513} 514