gallium: remove TGSI opcode XPD
[mesa.git] / src / gallium / drivers / nouveau / nv30 / nv30_draw.c
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
37 struct 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
55 static inline struct nv30_render *
56 nv30_render(struct vbuf_render *render)
57 {
58 return (struct nv30_render *)render;
59 }
60
61 static const struct vertex_info *
62 nv30_render_get_vertex_info(struct vbuf_render *render)
63 {
64 return &nv30_render(render)->vertex_info;
65 }
66
67 static boolean
68 nv30_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 = (uint32_t)vertex_size * (uint32_t)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, PIPE_USAGE_STREAM,
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
90 static void *
91 nv30_render_map_vertices(struct vbuf_render *render)
92 {
93 struct nv30_render *r = nv30_render(render);
94 char *map = pipe_buffer_map_range(
95 &r->nv30->base.pipe, r->buffer,
96 r->offset, r->length,
97 PIPE_TRANSFER_WRITE |
98 PIPE_TRANSFER_DISCARD_RANGE,
99 &r->transfer);
100 assert(map);
101 return map;
102 }
103
104 static void
105 nv30_render_unmap_vertices(struct vbuf_render *render,
106 ushort min_index, ushort max_index)
107 {
108 struct nv30_render *r = nv30_render(render);
109 pipe_buffer_unmap(&r->nv30->base.pipe, r->transfer);
110 r->transfer = NULL;
111 }
112
113 static void
114 nv30_render_set_primitive(struct vbuf_render *render, unsigned prim)
115 {
116 struct nv30_render *r = nv30_render(render);
117
118 r->prim = nv30_prim_gl(prim);
119 }
120
121 static void
122 nv30_render_draw_elements(struct vbuf_render *render,
123 const ushort *indices, uint count)
124 {
125 struct nv30_render *r = nv30_render(render);
126 struct nv30_context *nv30 = r->nv30;
127 struct nouveau_pushbuf *push = nv30->screen->base.pushbuf;
128 unsigned i;
129
130 BEGIN_NV04(push, NV30_3D(VTXBUF(0)), r->vertex_info.num_attribs);
131 for (i = 0; i < r->vertex_info.num_attribs; i++) {
132 PUSH_RESRC(push, NV30_3D(VTXBUF(i)), BUFCTX_VTXTMP,
133 nv04_resource(r->buffer), r->offset + r->vtxptr[i],
134 NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, NV30_3D_VTXBUF_DMA1);
135 }
136
137 if (!nv30_state_validate(nv30, ~0, false))
138 return;
139
140 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
141 PUSH_DATA (push, r->prim);
142
143 if (count & 1) {
144 BEGIN_NV04(push, NV30_3D(VB_ELEMENT_U32), 1);
145 PUSH_DATA (push, *indices++);
146 }
147
148 count >>= 1;
149 while (count) {
150 unsigned npush = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
151 count -= npush;
152
153 BEGIN_NI04(push, NV30_3D(VB_ELEMENT_U16), npush);
154 while (npush--) {
155 PUSH_DATA(push, (indices[1] << 16) | indices[0]);
156 indices += 2;
157 }
158 }
159
160 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
161 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP);
162 PUSH_RESET(push, BUFCTX_VTXTMP);
163 }
164
165 static void
166 nv30_render_draw_arrays(struct vbuf_render *render, unsigned start, uint nr)
167 {
168 struct nv30_render *r = nv30_render(render);
169 struct nv30_context *nv30 = r->nv30;
170 struct nouveau_pushbuf *push = nv30->base.pushbuf;
171 unsigned fn = nr >> 8, pn = nr & 0xff;
172 unsigned ps = fn + (pn ? 1 : 0);
173 unsigned i;
174
175 BEGIN_NV04(push, NV30_3D(VTXBUF(0)), r->vertex_info.num_attribs);
176 for (i = 0; i < r->vertex_info.num_attribs; i++) {
177 PUSH_RESRC(push, NV30_3D(VTXBUF(i)), BUFCTX_VTXTMP,
178 nv04_resource(r->buffer), r->offset + r->vtxptr[i],
179 NOUVEAU_BO_LOW | NOUVEAU_BO_RD, 0, NV30_3D_VTXBUF_DMA1);
180 }
181
182 if (!nv30_state_validate(nv30, ~0, false))
183 return;
184
185 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
186 PUSH_DATA (push, r->prim);
187
188 BEGIN_NI04(push, NV30_3D(VB_VERTEX_BATCH), ps);
189 while (fn--) {
190 PUSH_DATA (push, 0xff000000 | start);
191 start += 256;
192 }
193
194 if (pn)
195 PUSH_DATA (push, ((pn - 1) << 24) | start);
196
197 BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
198 PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP);
199 PUSH_RESET(push, BUFCTX_VTXTMP);
200 }
201
202 static void
203 nv30_render_release_vertices(struct vbuf_render *render)
204 {
205 struct nv30_render *r = nv30_render(render);
206 r->offset += r->length;
207 }
208
209 static const struct {
210 unsigned emit;
211 unsigned vp30;
212 unsigned vp40;
213 unsigned ow40;
214 } vroute [] = {
215 [TGSI_SEMANTIC_POSITION] = { EMIT_4F, 0, 0, 0x00000000 },
216 [TGSI_SEMANTIC_COLOR ] = { EMIT_4F, 3, 1, 0x00000001 },
217 [TGSI_SEMANTIC_BCOLOR ] = { EMIT_4F, 1, 3, 0x00000004 },
218 [TGSI_SEMANTIC_FOG ] = { EMIT_4F, 5, 5, 0x00000010 },
219 [TGSI_SEMANTIC_PSIZE ] = { EMIT_1F_PSIZE, 6, 6, 0x00000020 },
220 [TGSI_SEMANTIC_TEXCOORD] = { EMIT_4F, 8, 7, 0x00004000 },
221 };
222
223 static bool
224 vroute_add(struct nv30_render *r, uint attrib, uint sem, uint *idx)
225 {
226 struct nv30_screen *screen = r->nv30->screen;
227 struct nv30_fragprog *fp = r->nv30->fragprog.program;
228 struct vertex_info *vinfo = &r->vertex_info;
229 enum pipe_format format;
230 uint emit = EMIT_OMIT;
231 uint result = *idx;
232
233 if (sem == TGSI_SEMANTIC_GENERIC) {
234 uint num_texcoords = (screen->eng3d->oclass < NV40_3D_CLASS) ? 8 : 10;
235 for (result = 0; result < num_texcoords; result++) {
236 if (fp->texcoord[result] == *idx + 8) {
237 sem = TGSI_SEMANTIC_TEXCOORD;
238 emit = vroute[sem].emit;
239 break;
240 }
241 }
242 } else {
243 emit = vroute[sem].emit;
244 }
245
246 if (emit == EMIT_OMIT)
247 return false;
248
249 draw_emit_vertex_attr(vinfo, emit, attrib);
250 format = draw_translate_vinfo_format(emit);
251
252 r->vtxfmt[attrib] = nv30_vtxfmt(&screen->base.base, format)->hw;
253 r->vtxptr[attrib] = vinfo->size;
254 vinfo->size += draw_translate_vinfo_size(emit);
255
256 if (screen->eng3d->oclass < NV40_3D_CLASS) {
257 r->vtxprog[attrib][0] = 0x001f38d8;
258 r->vtxprog[attrib][1] = 0x0080001b | (attrib << 9);
259 r->vtxprog[attrib][2] = 0x0836106c;
260 r->vtxprog[attrib][3] = 0x2000f800 | (result + vroute[sem].vp30) << 2;
261 } else {
262 r->vtxprog[attrib][0] = 0x401f9c6c;
263 r->vtxprog[attrib][1] = 0x0040000d | (attrib << 8);
264 r->vtxprog[attrib][2] = 0x8106c083;
265 r->vtxprog[attrib][3] = 0x6041ff80 | (result + vroute[sem].vp40) << 2;
266 }
267
268 if (result < 8)
269 *idx = vroute[sem].ow40 << result;
270 else {
271 assert(sem == TGSI_SEMANTIC_TEXCOORD);
272 *idx = 0x00001000 << (result - 8);
273 }
274 return true;
275 }
276
277 static bool
278 nv30_render_validate(struct nv30_context *nv30)
279 {
280 struct nv30_render *r = nv30_render(nv30->draw->render);
281 struct nv30_rasterizer_stateobj *rast = nv30->rast;
282 struct pipe_screen *pscreen = &nv30->screen->base.base;
283 struct nouveau_pushbuf *push = nv30->screen->base.pushbuf;
284 struct nouveau_object *eng3d = nv30->screen->eng3d;
285 struct nv30_vertprog *vp = nv30->vertprog.program;
286 struct vertex_info *vinfo = &r->vertex_info;
287 unsigned vp_attribs = 0;
288 unsigned vp_results = 0;
289 unsigned attrib = 0;
290 unsigned pntc;
291 int i;
292
293 if (!r->vertprog) {
294 struct nouveau_heap *heap = nv30_screen(pscreen)->vp_exec_heap;
295 if (nouveau_heap_alloc(heap, 16, &r->vertprog, &r->vertprog)) {
296 while (heap->next && heap->size < 16) {
297 struct nouveau_heap **evict = heap->next->priv;
298 nouveau_heap_free(evict);
299 }
300
301 if (nouveau_heap_alloc(heap, 16, &r->vertprog, &r->vertprog))
302 return false;
303 }
304 }
305
306 vinfo->num_attribs = 0;
307 vinfo->size = 0;
308
309 /* setup routing for all necessary vp outputs */
310 for (i = 0; i < vp->info.num_outputs && attrib < 16; i++) {
311 uint semantic = vp->info.output_semantic_name[i];
312 uint index = vp->info.output_semantic_index[i];
313 if (vroute_add(r, attrib, semantic, &index)) {
314 vp_attribs |= (1 << attrib++);
315 vp_results |= index;
316 }
317 }
318
319 /* setup routing for replaced point coords not written by vp */
320 if (rast && rast->pipe.point_quad_rasterization)
321 pntc = rast->pipe.sprite_coord_enable & 0x000002ff;
322 else
323 pntc = 0;
324
325 while (pntc && attrib < 16) {
326 uint index = ffs(pntc) - 1; pntc &= ~(1 << index);
327 if (vroute_add(r, attrib, TGSI_SEMANTIC_TEXCOORD, &index)) {
328 vp_attribs |= (1 << attrib++);
329 vp_results |= index;
330 }
331 }
332
333 /* modify vertex format for correct stride, and stub out unused ones */
334 BEGIN_NV04(push, NV30_3D(VP_UPLOAD_FROM_ID), 1);
335 PUSH_DATA (push, r->vertprog->start);
336 r->vtxprog[attrib - 1][3] |= 1;
337 for (i = 0; i < attrib; i++) {
338 BEGIN_NV04(push, NV30_3D(VP_UPLOAD_INST(0)), 4);
339 PUSH_DATAp(push, r->vtxprog[i], 4);
340 r->vtxfmt[i] |= vinfo->size << 8;
341 }
342 for (; i < 16; i++)
343 r->vtxfmt[i] = NV30_3D_VTXFMT_TYPE_V32_FLOAT;
344
345 BEGIN_NV04(push, NV30_3D(VIEWPORT_TRANSLATE_X), 8);
346 PUSH_DATAf(push, 0.0);
347 PUSH_DATAf(push, 0.0);
348 PUSH_DATAf(push, 0.0);
349 PUSH_DATAf(push, 0.0);
350 PUSH_DATAf(push, 1.0);
351 PUSH_DATAf(push, 1.0);
352 PUSH_DATAf(push, 1.0);
353 PUSH_DATAf(push, 1.0);
354 BEGIN_NV04(push, NV30_3D(DEPTH_RANGE_NEAR), 2);
355 PUSH_DATAf(push, 0.0);
356 PUSH_DATAf(push, 1.0);
357 BEGIN_NV04(push, NV30_3D(VIEWPORT_HORIZ), 2);
358 PUSH_DATA (push, nv30->framebuffer.width << 16);
359 PUSH_DATA (push, nv30->framebuffer.height << 16);
360
361 BEGIN_NV04(push, NV30_3D(VTXFMT(0)), 16);
362 PUSH_DATAp(push, r->vtxfmt, 16);
363
364 BEGIN_NV04(push, NV30_3D(VP_START_FROM_ID), 1);
365 PUSH_DATA (push, r->vertprog->start);
366 BEGIN_NV04(push, NV30_3D(ENGINE), 1);
367 PUSH_DATA (push, 0x00000103);
368 if (eng3d->oclass >= NV40_3D_CLASS) {
369 BEGIN_NV04(push, NV40_3D(VP_ATTRIB_EN), 2);
370 PUSH_DATA (push, vp_attribs);
371 PUSH_DATA (push, vp_results);
372 }
373
374 vinfo->size /= 4;
375 return true;
376 }
377
378 void
379 nv30_render_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
380 {
381 struct nv30_context *nv30 = nv30_context(pipe);
382 struct draw_context *draw = nv30->draw;
383 struct pipe_transfer *transfer[PIPE_MAX_ATTRIBS] = {NULL};
384 struct pipe_transfer *transferi = NULL;
385 int i;
386
387 nv30_render_validate(nv30);
388
389 if (nv30->draw_dirty & NV30_NEW_VIEWPORT)
390 draw_set_viewport_states(draw, 0, 1, &nv30->viewport);
391 if (nv30->draw_dirty & NV30_NEW_RASTERIZER)
392 draw_set_rasterizer_state(draw, &nv30->rast->pipe, NULL);
393 if (nv30->draw_dirty & NV30_NEW_CLIP)
394 draw_set_clip_state(draw, &nv30->clip);
395 if (nv30->draw_dirty & NV30_NEW_ARRAYS) {
396 draw_set_vertex_buffers(draw, 0, nv30->num_vtxbufs, nv30->vtxbuf);
397 draw_set_vertex_elements(draw, nv30->vertex->num_elements, nv30->vertex->pipe);
398 }
399 if (nv30->draw_dirty & NV30_NEW_FRAGPROG) {
400 struct nv30_fragprog *fp = nv30->fragprog.program;
401 if (!fp->draw)
402 fp->draw = draw_create_fragment_shader(draw, &fp->pipe);
403 draw_bind_fragment_shader(draw, fp->draw);
404 }
405 if (nv30->draw_dirty & NV30_NEW_VERTPROG) {
406 struct nv30_vertprog *vp = nv30->vertprog.program;
407 if (!vp->draw)
408 vp->draw = draw_create_vertex_shader(draw, &vp->pipe);
409 draw_bind_vertex_shader(draw, vp->draw);
410 }
411 if (nv30->draw_dirty & NV30_NEW_VERTCONST) {
412 if (nv30->vertprog.constbuf) {
413 void *map = nv04_resource(nv30->vertprog.constbuf)->data;
414 draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0,
415 map, nv30->vertprog.constbuf_nr * 16);
416 } else {
417 draw_set_mapped_constant_buffer(draw, PIPE_SHADER_VERTEX, 0, NULL, 0);
418 }
419 }
420
421 for (i = 0; i < nv30->num_vtxbufs; i++) {
422 const void *map = nv30->vtxbuf[i].is_user_buffer ?
423 nv30->vtxbuf[i].buffer.user : NULL;
424 if (!map) {
425 if (nv30->vtxbuf[i].buffer.resource)
426 map = pipe_buffer_map(pipe, nv30->vtxbuf[i].buffer.resource,
427 PIPE_TRANSFER_UNSYNCHRONIZED |
428 PIPE_TRANSFER_READ, &transfer[i]);
429 }
430 draw_set_mapped_vertex_buffer(draw, i, map, ~0);
431 }
432
433 if (info->index_size) {
434 const void *map = info->has_user_indices ? info->index.user : NULL;
435 if (!map)
436 map = pipe_buffer_map(pipe, info->index.resource,
437 PIPE_TRANSFER_UNSYNCHRONIZED |
438 PIPE_TRANSFER_READ, &transferi);
439 draw_set_indexes(draw,
440 (ubyte *) map,
441 info->index_size, ~0);
442 } else {
443 draw_set_indexes(draw, NULL, 0, 0);
444 }
445
446 draw_vbo(draw, info);
447 draw_flush(draw);
448
449 if (info->index_size && transferi)
450 pipe_buffer_unmap(pipe, transferi);
451 for (i = 0; i < nv30->num_vtxbufs; i++)
452 if (transfer[i])
453 pipe_buffer_unmap(pipe, transfer[i]);
454
455 nv30->draw_dirty = 0;
456 nv30_state_release(nv30);
457 }
458
459 static void
460 nv30_render_destroy(struct vbuf_render *render)
461 {
462 struct nv30_render *r = nv30_render(render);
463
464 if (r->transfer)
465 pipe_buffer_unmap(&r->nv30->base.pipe, r->transfer);
466 pipe_resource_reference(&r->buffer, NULL);
467 nouveau_heap_free(&r->vertprog);
468 FREE(render);
469 }
470
471 static struct vbuf_render *
472 nv30_render_create(struct nv30_context *nv30)
473 {
474 struct nv30_render *r = CALLOC_STRUCT(nv30_render);
475 if (!r)
476 return NULL;
477
478 r->nv30 = nv30;
479 r->offset = 1 * 1024 * 1024;
480
481 r->base.max_indices = 16 * 1024;
482 r->base.max_vertex_buffer_bytes = r->offset;
483
484 r->base.get_vertex_info = nv30_render_get_vertex_info;
485 r->base.allocate_vertices = nv30_render_allocate_vertices;
486 r->base.map_vertices = nv30_render_map_vertices;
487 r->base.unmap_vertices = nv30_render_unmap_vertices;
488 r->base.set_primitive = nv30_render_set_primitive;
489 r->base.draw_elements = nv30_render_draw_elements;
490 r->base.draw_arrays = nv30_render_draw_arrays;
491 r->base.release_vertices = nv30_render_release_vertices;
492 r->base.destroy = nv30_render_destroy;
493 return &r->base;
494 }
495
496 void
497 nv30_draw_init(struct pipe_context *pipe)
498 {
499 struct nv30_context *nv30 = nv30_context(pipe);
500 struct vbuf_render *render;
501 struct draw_context *draw;
502 struct draw_stage *stage;
503
504 draw = draw_create(pipe);
505 if (!draw)
506 return;
507
508 render = nv30_render_create(nv30);
509 if (!render) {
510 draw_destroy(draw);
511 return;
512 }
513
514 stage = draw_vbuf_stage(draw, render);
515 if (!stage) {
516 render->destroy(render);
517 draw_destroy(draw);
518 return;
519 }
520
521 draw_set_render(draw, render);
522 draw_set_rasterize_stage(draw, stage);
523 draw_wide_line_threshold(draw, 10000000.f);
524 draw_wide_point_threshold(draw, 10000000.f);
525 draw_wide_point_sprites(draw, true);
526 nv30->draw = draw;
527 }