nvc0: use tile flags in a way compatible with nouveau
[mesa.git] / src / gallium / drivers / nvc0 / nvc0_vbo.c
1 /*
2 * Copyright 2010 Christoph Bumiller
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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "pipe/p_context.h"
24 #include "pipe/p_state.h"
25 #include "util/u_inlines.h"
26 #include "util/u_format.h"
27 #include "translate/translate.h"
28
29 #include "nvc0_context.h"
30 #include "nvc0_resource.h"
31
32 #include "nvc0_3d.xml.h"
33
34 void
35 nvc0_vertex_state_delete(struct pipe_context *pipe,
36 void *hwcso)
37 {
38 struct nvc0_vertex_stateobj *so = hwcso;
39
40 if (so->translate)
41 so->translate->release(so->translate);
42 FREE(hwcso);
43 }
44
45 void *
46 nvc0_vertex_state_create(struct pipe_context *pipe,
47 unsigned num_elements,
48 const struct pipe_vertex_element *elements)
49 {
50 struct nvc0_vertex_stateobj *so;
51 struct translate_key transkey;
52 unsigned i;
53
54 assert(num_elements);
55
56 so = MALLOC(sizeof(*so) +
57 (num_elements - 1) * sizeof(struct nvc0_vertex_element));
58 if (!so)
59 return NULL;
60 so->num_elements = num_elements;
61 so->instance_bits = 0;
62
63 transkey.nr_elements = 0;
64 transkey.output_stride = 0;
65
66 for (i = 0; i < num_elements; ++i) {
67 const struct pipe_vertex_element *ve = &elements[i];
68 const unsigned vbi = ve->vertex_buffer_index;
69 enum pipe_format fmt = ve->src_format;
70
71 so->element[i].pipe = elements[i];
72 so->element[i].state = nvc0_format_table[fmt].vtx;
73
74 if (!so->element[i].state) {
75 switch (util_format_get_nr_components(fmt)) {
76 case 1: fmt = PIPE_FORMAT_R32_FLOAT; break;
77 case 2: fmt = PIPE_FORMAT_R32G32_FLOAT; break;
78 case 3: fmt = PIPE_FORMAT_R32G32B32_FLOAT; break;
79 case 4: fmt = PIPE_FORMAT_R32G32B32A32_FLOAT; break;
80 default:
81 assert(0);
82 return NULL;
83 }
84 so->element[i].state = nvc0_format_table[fmt].vtx;
85 }
86 so->element[i].state |= i;
87
88 if (likely(!ve->instance_divisor)) {
89 unsigned j = transkey.nr_elements++;
90
91 transkey.element[j].type = TRANSLATE_ELEMENT_NORMAL;
92 transkey.element[j].input_format = ve->src_format;
93 transkey.element[j].input_buffer = vbi;
94 transkey.element[j].input_offset = ve->src_offset;
95 transkey.element[j].instance_divisor = ve->instance_divisor;
96
97 transkey.element[j].output_format = fmt;
98 transkey.element[j].output_offset = transkey.output_stride;
99 transkey.output_stride += (util_format_get_stride(fmt, 1) + 3) & ~3;
100 } else {
101 so->instance_bits |= 1 << i;
102 }
103 }
104
105 so->translate = translate_create(&transkey);
106 so->vtx_size = transkey.output_stride / 4;
107 so->vtx_per_packet_max = NV04_PFIFO_MAX_PACKET_LEN / MAX2(so->vtx_size, 1);
108
109 return so;
110 }
111
112 #define NVC0_3D_VERTEX_ATTRIB_INACTIVE \
113 NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT | \
114 NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32 | NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST
115
116 void
117 nvc0_vertex_arrays_validate(struct nvc0_context *nvc0)
118 {
119 struct nouveau_channel *chan = nvc0->screen->base.channel;
120 struct nvc0_vertex_stateobj *vertex = nvc0->vertex;
121 struct pipe_vertex_buffer *vb;
122 struct nvc0_vertex_element *ve;
123 unsigned i;
124
125 nvc0_bufctx_reset(nvc0, NVC0_BUFCTX_VERTEX);
126
127 nvc0->vbo_fifo = 0;
128
129 BEGIN_RING(chan, RING_3D(VERTEX_ATTRIB_FORMAT(0)), vertex->num_elements);
130 for (i = 0; i < vertex->num_elements; ++i) {
131 ve = &vertex->element[i];
132 vb = &nvc0->vtxbuf[ve->pipe.vertex_buffer_index];
133
134 if (!nvc0_resource_mapped_by_gpu(vb->buffer)) {
135 if (nvc0->vbo_push_hint) {
136 nvc0->vbo_fifo |= 1 << i;
137 } else {
138 nvc0_migrate_vertices(nvc0_resource(vb->buffer),
139 vb->buffer_offset,
140 vb->buffer->width0 - vb->buffer_offset);
141 nvc0->vbo_dirty = TRUE;
142 }
143 }
144
145 if (1 || likely(vb->stride)) {
146 OUT_RING(chan, ve->state);
147 } else {
148 OUT_RING(chan, ve->state | NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST);
149 }
150 }
151
152 for (i = 0; i < vertex->num_elements; ++i) {
153 struct nvc0_resource *res;
154 unsigned size, offset;
155
156 ve = &vertex->element[i];
157 vb = &nvc0->vtxbuf[ve->pipe.vertex_buffer_index];
158
159 if (nvc0->vbo_fifo || (0 && vb->stride == 0)) {
160 #if 0
161 if (!nvc0->vbo_fifo)
162 nvc0_vbo_constant_attrib(nvc0, vb, ve);
163 #endif
164 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_FETCH(i)), 1);
165 OUT_RING (chan, 0);
166 continue;
167 }
168
169 res = nvc0_resource(vb->buffer);
170 size = vb->buffer->width0;
171 offset = ve->pipe.src_offset + vb->buffer_offset;
172
173 if (unlikely(ve->pipe.instance_divisor)) {
174 if (!(nvc0->state.instance_bits & (1 << i))) {
175 INLIN_RING(chan, RING_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 1);
176 }
177 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_DIVISOR(i)), 1);
178 OUT_RING (chan, ve->pipe.instance_divisor);
179 } else
180 if (unlikely(nvc0->state.instance_bits & (1 << i))) {
181 INLIN_RING(chan, RING_3D(VERTEX_ARRAY_PER_INSTANCE(i)), 0);
182 }
183
184 nvc0_bufctx_add_resident(nvc0, NVC0_BUFCTX_VERTEX, res, NOUVEAU_BO_RD);
185
186 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_FETCH(i)), 1);
187 OUT_RING (chan, (1 << 12) | vb->stride);
188 BEGIN_RING_1I(chan, RING_3D(VERTEX_ARRAY_SELECT), 5);
189 OUT_RING (chan, i);
190 OUT_RESRCh(chan, res, size, NOUVEAU_BO_RD);
191 OUT_RESRCl(chan, res, size, NOUVEAU_BO_RD);
192 OUT_RESRCh(chan, res, offset, NOUVEAU_BO_RD);
193 OUT_RESRCl(chan, res, offset, NOUVEAU_BO_RD);
194 }
195 for (; i < nvc0->state.num_vtxelts; ++i) {
196 BEGIN_RING(chan, RING_3D(VERTEX_ATTRIB_FORMAT(i)), 1);
197 OUT_RING (chan, NVC0_3D_VERTEX_ATTRIB_INACTIVE);
198 BEGIN_RING(chan, RING_3D(VERTEX_ARRAY_FETCH(i)), 1);
199 OUT_RING (chan, 0);
200 }
201
202 nvc0->state.num_vtxelts = vertex->num_elements;
203 nvc0->state.instance_bits = vertex->instance_bits;
204 }
205
206 #define NVC0_PRIM_GL_CASE(n) \
207 case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
208
209 static INLINE unsigned
210 nvc0_prim_gl(unsigned prim)
211 {
212 switch (prim) {
213 NVC0_PRIM_GL_CASE(POINTS);
214 NVC0_PRIM_GL_CASE(LINES);
215 NVC0_PRIM_GL_CASE(LINE_LOOP);
216 NVC0_PRIM_GL_CASE(LINE_STRIP);
217 NVC0_PRIM_GL_CASE(TRIANGLES);
218 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);
219 NVC0_PRIM_GL_CASE(TRIANGLE_FAN);
220 NVC0_PRIM_GL_CASE(QUADS);
221 NVC0_PRIM_GL_CASE(QUAD_STRIP);
222 NVC0_PRIM_GL_CASE(POLYGON);
223 NVC0_PRIM_GL_CASE(LINES_ADJACENCY);
224 NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
225 NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
226 NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
227 /*
228 NVC0_PRIM_GL_CASE(PATCHES); */
229 default:
230 return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
231 break;
232 }
233 }
234
235 static void
236 nvc0_draw_vbo_flush_notify(struct nouveau_channel *chan)
237 {
238 struct nvc0_context *nvc0 = chan->user_private;
239
240 nvc0_bufctx_emit_relocs(nvc0);
241 }
242
243 #if 0
244 static struct nouveau_bo *
245 nvc0_tfb_setup(struct nvc0_context *nvc0)
246 {
247 struct nouveau_channel *chan = nvc0->screen->base.channel;
248 struct nouveau_bo *tfb = NULL;
249 int ret, i;
250
251 ret = nouveau_bo_new(nvc0->screen->base.device,
252 NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 4096, &tfb);
253 if (ret)
254 return NULL;
255
256 ret = nouveau_bo_map(tfb, NOUVEAU_BO_WR);
257 if (ret)
258 return NULL;
259 memset(tfb->map, 0xee, 8 * 4 * 3);
260 nouveau_bo_unmap(tfb);
261
262 BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1);
263 OUT_RING (chan, 1);
264 BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(0)), 5);
265 OUT_RING (chan, 1);
266 OUT_RELOCh(chan, tfb, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
267 OUT_RELOCl(chan, tfb, 0, NOUVEAU_BO_GART | NOUVEAU_BO_WR);
268 OUT_RING (chan, tfb->size);
269 OUT_RING (chan, 0); /* TFB_PRIMITIVE_ID(0) */
270 BEGIN_RING(chan, RING_3D(TFB_UNK0700(0)), 3);
271 OUT_RING (chan, 0);
272 OUT_RING (chan, 8); /* TFB_VARYING_COUNT(0) */
273 OUT_RING (chan, 32); /* TFB_BUFFER_STRIDE(0) */
274 BEGIN_RING(chan, RING_3D(TFB_VARYING_LOCS(0)), 2);
275 OUT_RING (chan, 0x1f1e1d1c);
276 OUT_RING (chan, 0xa3a2a1a0);
277 for (i = 1; i < 4; ++i) {
278 BEGIN_RING(chan, RING_3D(TFB_BUFFER_ENABLE(i)), 1);
279 OUT_RING (chan, 0);
280 }
281 BEGIN_RING(chan, RING_3D(TFB_ENABLE), 1);
282 OUT_RING (chan, 1);
283 BEGIN_RING(chan, RING_3D_(0x135c), 1);
284 OUT_RING (chan, 1);
285 BEGIN_RING(chan, RING_3D_(0x135c), 1);
286 OUT_RING (chan, 0);
287
288 return tfb;
289 }
290 #endif
291
292 static void
293 nvc0_draw_arrays(struct nvc0_context *nvc0,
294 unsigned mode, unsigned start, unsigned count,
295 unsigned instance_count)
296 {
297 struct nouveau_channel *chan = nvc0->screen->base.channel;
298 unsigned prim;
299
300 chan->flush_notify = nvc0_draw_vbo_flush_notify;
301 chan->user_private = nvc0;
302
303 prim = nvc0_prim_gl(mode);
304
305 while (instance_count--) {
306 BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
307 OUT_RING (chan, prim);
308 BEGIN_RING(chan, RING_3D(VERTEX_BUFFER_FIRST), 2);
309 OUT_RING (chan, start);
310 OUT_RING (chan, count);
311 INLIN_RING(chan, RING_3D(VERTEX_END_GL), 0);
312
313 prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
314 }
315
316 chan->flush_notify = NULL;
317 }
318
319 static void
320 nvc0_draw_elements_inline_u08(struct nouveau_channel *chan, uint8_t *map,
321 unsigned start, unsigned count)
322 {
323 map += start;
324
325 if (count & 3) {
326 unsigned i;
327 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U32), count & 3);
328 for (i = 0; i < (count & 3); ++i)
329 OUT_RING(chan, *map++);
330 count &= ~3;
331 }
332 while (count) {
333 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 4) / 4;
334
335 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U8), nr);
336 for (i = 0; i < nr; ++i) {
337 OUT_RING(chan,
338 (map[3] << 24) | (map[2] << 16) | (map[1] << 8) | map[0]);
339 map += 4;
340 }
341 count -= nr * 4;
342 }
343 }
344
345 static void
346 nvc0_draw_elements_inline_u16(struct nouveau_channel *chan, uint16_t *map,
347 unsigned start, unsigned count)
348 {
349 map += start;
350
351 if (count & 1) {
352 count &= ~1;
353 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U32), 1);
354 OUT_RING (chan, *map++);
355 }
356 while (count) {
357 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;
358
359 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U16), nr);
360 for (i = 0; i < nr; ++i) {
361 OUT_RING(chan, (map[1] << 16) | map[0]);
362 map += 2;
363 }
364 count -= nr * 2;
365 }
366 }
367
368 static void
369 nvc0_draw_elements_inline_u32(struct nouveau_channel *chan, uint32_t *map,
370 unsigned start, unsigned count)
371 {
372 map += start;
373
374 while (count) {
375 const unsigned nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN);
376
377 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U32), nr);
378 OUT_RINGp (chan, map, nr);
379
380 map += nr;
381 count -= nr;
382 }
383 }
384
385 static void
386 nvc0_draw_elements_inline_u32_short(struct nouveau_channel *chan, uint32_t *map,
387 unsigned start, unsigned count)
388 {
389 map += start;
390
391 if (count & 1) {
392 count--;
393 BEGIN_RING(chan, RING_3D(VB_ELEMENT_U32), 1);
394 OUT_RING (chan, *map++);
395 }
396 while (count) {
397 unsigned i, nr = MIN2(count, NV04_PFIFO_MAX_PACKET_LEN * 2) / 2;
398
399 BEGIN_RING_NI(chan, RING_3D(VB_ELEMENT_U16), nr);
400 for (i = 0; i < nr; ++i) {
401 OUT_RING(chan, (map[1] << 16) | map[0]);
402 map += 2;
403 }
404 count -= nr * 2;
405 }
406 }
407
408 static void
409 nvc0_draw_elements(struct nvc0_context *nvc0, boolean shorten,
410 unsigned mode, unsigned start, unsigned count,
411 unsigned instance_count, int32_t index_bias)
412 {
413 struct nouveau_channel *chan = nvc0->screen->base.channel;
414 void *data;
415 struct pipe_transfer *transfer;
416 unsigned prim;
417 unsigned index_size = nvc0->idxbuf.index_size;
418
419 chan->flush_notify = nvc0_draw_vbo_flush_notify;
420 chan->user_private = nvc0;
421
422 prim = nvc0_prim_gl(mode);
423
424 if (index_bias != nvc0->state.index_bias) {
425 BEGIN_RING(chan, RING_3D(VB_ELEMENT_BASE), 1);
426 OUT_RING (chan, index_bias);
427 nvc0->state.index_bias = index_bias;
428 }
429
430 if (nvc0_resource_mapped_by_gpu(nvc0->idxbuf.buffer)) {
431 struct nvc0_resource *res = nvc0_resource(nvc0->idxbuf.buffer);
432 unsigned offset = nvc0->idxbuf.offset;
433 unsigned limit = nvc0->idxbuf.buffer->width0 - 1;
434
435 if (index_size == 4)
436 index_size = 2;
437 else
438 if (index_size == 2)
439 index_size = 1;
440
441 while (instance_count--) {
442 MARK_RING (chan, 11, 4);
443 BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
444 OUT_RING (chan, mode);
445 BEGIN_RING(chan, RING_3D(INDEX_ARRAY_START_HIGH), 7);
446 OUT_RESRCh(chan, res, offset, NOUVEAU_BO_RD);
447 OUT_RESRCl(chan, res, offset, NOUVEAU_BO_RD);
448 OUT_RESRCh(chan, res, limit, NOUVEAU_BO_RD);
449 OUT_RESRCl(chan, res, limit, NOUVEAU_BO_RD);
450 OUT_RING (chan, index_size);
451 OUT_RING (chan, start);
452 OUT_RING (chan, count);
453 INLIN_RING(chan, RING_3D(VERTEX_END_GL), 0);
454
455 mode |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
456 }
457 } else {
458 data = pipe_buffer_map(&nvc0->pipe, nvc0->idxbuf.buffer,
459 PIPE_TRANSFER_READ, &transfer);
460 if (!data)
461 return;
462
463 while (instance_count--) {
464 BEGIN_RING(chan, RING_3D(VERTEX_BEGIN_GL), 1);
465 OUT_RING (chan, prim);
466 switch (index_size) {
467 case 1:
468 nvc0_draw_elements_inline_u08(chan, data, start, count);
469 break;
470 case 2:
471 nvc0_draw_elements_inline_u16(chan, data, start, count);
472 break;
473 case 4:
474 if (shorten)
475 nvc0_draw_elements_inline_u32_short(chan, data, start, count);
476 else
477 nvc0_draw_elements_inline_u32(chan, data, start, count);
478 break;
479 default:
480 assert(0);
481 return;
482 }
483 INLIN_RING(chan, RING_3D(VERTEX_END_GL), 0);
484
485 prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
486 }
487 }
488
489 chan->flush_notify = NULL;
490 }
491
492 void
493 nvc0_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
494 {
495 struct nvc0_context *nvc0 = nvc0_context(pipe);
496 struct nouveau_channel *chan = nvc0->screen->base.channel;
497
498 /* For picking only a few vertices from a large user buffer, push is better,
499 * if index count is larger and we expect repeated vertices, suggest upload.
500 */
501 nvc0->vbo_push_hint = /* the 64 is heuristic */
502 !(info->indexed &&
503 ((info->max_index - info->min_index + 64) < info->count));
504
505 nvc0_state_validate(nvc0);
506
507 if (nvc0->state.instance_base != info->start_instance) {
508 nvc0->state.instance_base = info->start_instance;
509 BEGIN_RING(chan, RING_3D(VB_INSTANCE_BASE), 1);
510 OUT_RING (chan, info->start_instance);
511 }
512
513 if (nvc0->vbo_fifo) {
514 nvc0_push_vbo(nvc0, info);
515 return;
516 }
517
518 if (nvc0->vbo_dirty) {
519 BEGIN_RING(chan, RING_3D_(0x142c), 1);
520 OUT_RING (chan, 0);
521 nvc0->vbo_dirty = FALSE;
522 }
523
524 if (!info->indexed) {
525 nvc0_draw_arrays(nvc0,
526 info->mode, info->start, info->count,
527 info->instance_count);
528 } else {
529 boolean shorten = info->max_index <= 65535;
530
531 assert(nvc0->idxbuf.buffer);
532
533 if (info->primitive_restart != nvc0->state.prim_restart) {
534 if (info->primitive_restart) {
535 BEGIN_RING(chan, RING_3D(PRIM_RESTART_ENABLE), 2);
536 OUT_RING (chan, 1);
537 OUT_RING (chan, info->restart_index);
538
539 if (info->restart_index > 65535)
540 shorten = FALSE;
541 } else {
542 INLIN_RING(chan, RING_3D(PRIM_RESTART_ENABLE), 0);
543 }
544 nvc0->state.prim_restart = info->primitive_restart;
545 } else
546 if (info->primitive_restart) {
547 BEGIN_RING(chan, RING_3D(PRIM_RESTART_INDEX), 1);
548 OUT_RING (chan, info->restart_index);
549 }
550
551 nvc0_draw_elements(nvc0, shorten,
552 info->mode, info->start, info->count,
553 info->instance_count, info->index_bias);
554 }
555 }