2 * Copyright 2010 Christoph Bumiller
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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
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"
29 #include "nvc0_context.h"
30 #include "nvc0_resource.h"
32 #include "nvc0_3d.xml.h"
35 nvc0_vertex_state_delete(struct pipe_context
*pipe
,
38 struct nvc0_vertex_stateobj
*so
= hwcso
;
41 so
->translate
->release(so
->translate
);
46 nvc0_vertex_state_create(struct pipe_context
*pipe
,
47 unsigned num_elements
,
48 const struct pipe_vertex_element
*elements
)
50 struct nvc0_vertex_stateobj
*so
;
51 struct translate_key transkey
;
56 so
= MALLOC(sizeof(*so
) +
57 (num_elements
- 1) * sizeof(struct nvc0_vertex_element
));
60 so
->num_elements
= num_elements
;
61 so
->instance_bits
= 0;
63 transkey
.nr_elements
= 0;
64 transkey
.output_stride
= 0;
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
;
71 so
->element
[i
].pipe
= elements
[i
];
72 so
->element
[i
].state
= nvc0_format_table
[fmt
].vtx
;
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;
84 so
->element
[i
].state
= nvc0_format_table
[fmt
].vtx
;
86 so
->element
[i
].state
|= i
;
88 if (likely(!ve
->instance_divisor
)) {
89 unsigned j
= transkey
.nr_elements
++;
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
;
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;
101 so
->instance_bits
|= 1 << i
;
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);
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
117 nvc0_vertex_arrays_validate(struct nvc0_context
*nvc0
)
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
;
125 nvc0_bufctx_reset(nvc0
, NVC0_BUFCTX_VERTEX
);
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
];
134 if (!nvc0_resource_mapped_by_gpu(vb
->buffer
)) {
135 if (nvc0
->vbo_push_hint
) {
136 nvc0
->vbo_fifo
|= 1 << i
;
138 nvc0_migrate_vertices(nvc0_resource(vb
->buffer
),
140 vb
->buffer
->width0
- vb
->buffer_offset
);
141 nvc0
->vbo_dirty
= TRUE
;
145 if (1 || likely(vb
->stride
)) {
146 OUT_RING(chan
, ve
->state
);
148 OUT_RING(chan
, ve
->state
| NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST
);
152 for (i
= 0; i
< vertex
->num_elements
; ++i
) {
153 struct nvc0_resource
*res
;
154 unsigned size
, offset
;
156 ve
= &vertex
->element
[i
];
157 vb
= &nvc0
->vtxbuf
[ve
->pipe
.vertex_buffer_index
];
159 if (nvc0
->vbo_fifo
|| (0 && vb
->stride
== 0)) {
162 nvc0_vbo_constant_attrib(nvc0
, vb
, ve
);
164 BEGIN_RING(chan
, RING_3D(VERTEX_ARRAY_FETCH(i
)), 1);
169 res
= nvc0_resource(vb
->buffer
);
170 size
= vb
->buffer
->width0
;
171 offset
= ve
->pipe
.src_offset
+ vb
->buffer_offset
;
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);
177 BEGIN_RING(chan
, RING_3D(VERTEX_ARRAY_DIVISOR(i
)), 1);
178 OUT_RING (chan
, ve
->pipe
.instance_divisor
);
180 if (unlikely(nvc0
->state
.instance_bits
& (1 << i
))) {
181 INLIN_RING(chan
, RING_3D(VERTEX_ARRAY_PER_INSTANCE(i
)), 0);
184 nvc0_bufctx_add_resident(nvc0
, NVC0_BUFCTX_VERTEX
, res
, NOUVEAU_BO_RD
);
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);
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
);
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);
202 nvc0
->state
.num_vtxelts
= vertex
->num_elements
;
203 nvc0
->state
.instance_bits
= vertex
->instance_bits
;
206 #define NVC0_PRIM_GL_CASE(n) \
207 case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
209 static INLINE
unsigned
210 nvc0_prim_gl(unsigned 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
);
228 NVC0_PRIM_GL_CASE(PATCHES); */
230 return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS
;
236 nvc0_draw_vbo_flush_notify(struct nouveau_channel
*chan
)
238 struct nvc0_context
*nvc0
= chan
->user_private
;
240 nvc0_bufctx_emit_relocs(nvc0
);
244 static struct nouveau_bo
*
245 nvc0_tfb_setup(struct nvc0_context
*nvc0
)
247 struct nouveau_channel
*chan
= nvc0
->screen
->base
.channel
;
248 struct nouveau_bo
*tfb
= NULL
;
251 ret
= nouveau_bo_new(nvc0
->screen
->base
.device
,
252 NOUVEAU_BO_GART
| NOUVEAU_BO_MAP
, 0, 4096, &tfb
);
256 ret
= nouveau_bo_map(tfb
, NOUVEAU_BO_WR
);
259 memset(tfb
->map
, 0xee, 8 * 4 * 3);
260 nouveau_bo_unmap(tfb
);
262 BEGIN_RING(chan
, RING_3D(TFB_ENABLE
), 1);
264 BEGIN_RING(chan
, RING_3D(TFB_BUFFER_ENABLE(0)), 5);
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);
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);
281 BEGIN_RING(chan
, RING_3D(TFB_ENABLE
), 1);
283 BEGIN_RING(chan
, RING_3D_(0x135c), 1);
285 BEGIN_RING(chan
, RING_3D_(0x135c), 1);
293 nvc0_draw_arrays(struct nvc0_context
*nvc0
,
294 unsigned mode
, unsigned start
, unsigned count
,
295 unsigned instance_count
)
297 struct nouveau_channel
*chan
= nvc0
->screen
->base
.channel
;
300 chan
->flush_notify
= nvc0_draw_vbo_flush_notify
;
301 chan
->user_private
= nvc0
;
303 prim
= nvc0_prim_gl(mode
);
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);
313 prim
|= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT
;
316 chan
->flush_notify
= NULL
;
320 nvc0_draw_elements_inline_u08(struct nouveau_channel
*chan
, uint8_t *map
,
321 unsigned start
, unsigned count
)
327 BEGIN_RING(chan
, RING_3D(VB_ELEMENT_U32
), count
& 3);
328 for (i
= 0; i
< (count
& 3); ++i
)
329 OUT_RING(chan
, *map
++);
333 unsigned i
, nr
= MIN2(count
, NV04_PFIFO_MAX_PACKET_LEN
* 4) / 4;
335 BEGIN_RING_NI(chan
, RING_3D(VB_ELEMENT_U8
), nr
);
336 for (i
= 0; i
< nr
; ++i
) {
338 (map
[3] << 24) | (map
[2] << 16) | (map
[1] << 8) | map
[0]);
346 nvc0_draw_elements_inline_u16(struct nouveau_channel
*chan
, uint16_t *map
,
347 unsigned start
, unsigned count
)
353 BEGIN_RING(chan
, RING_3D(VB_ELEMENT_U32
), 1);
354 OUT_RING (chan
, *map
++);
357 unsigned i
, nr
= MIN2(count
, NV04_PFIFO_MAX_PACKET_LEN
* 2) / 2;
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]);
369 nvc0_draw_elements_inline_u32(struct nouveau_channel
*chan
, uint32_t *map
,
370 unsigned start
, unsigned count
)
375 const unsigned nr
= MIN2(count
, NV04_PFIFO_MAX_PACKET_LEN
);
377 BEGIN_RING_NI(chan
, RING_3D(VB_ELEMENT_U32
), nr
);
378 OUT_RINGp (chan
, map
, nr
);
386 nvc0_draw_elements_inline_u32_short(struct nouveau_channel
*chan
, uint32_t *map
,
387 unsigned start
, unsigned count
)
393 BEGIN_RING(chan
, RING_3D(VB_ELEMENT_U32
), 1);
394 OUT_RING (chan
, *map
++);
397 unsigned i
, nr
= MIN2(count
, NV04_PFIFO_MAX_PACKET_LEN
* 2) / 2;
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]);
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
)
413 struct nouveau_channel
*chan
= nvc0
->screen
->base
.channel
;
415 struct pipe_transfer
*transfer
;
417 unsigned index_size
= nvc0
->idxbuf
.index_size
;
419 chan
->flush_notify
= nvc0_draw_vbo_flush_notify
;
420 chan
->user_private
= nvc0
;
422 prim
= nvc0_prim_gl(mode
);
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
;
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;
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);
455 mode
|= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT
;
458 data
= pipe_buffer_map(&nvc0
->pipe
, nvc0
->idxbuf
.buffer
,
459 PIPE_TRANSFER_READ
, &transfer
);
463 while (instance_count
--) {
464 BEGIN_RING(chan
, RING_3D(VERTEX_BEGIN_GL
), 1);
465 OUT_RING (chan
, prim
);
466 switch (index_size
) {
468 nvc0_draw_elements_inline_u08(chan
, data
, start
, count
);
471 nvc0_draw_elements_inline_u16(chan
, data
, start
, count
);
475 nvc0_draw_elements_inline_u32_short(chan
, data
, start
, count
);
477 nvc0_draw_elements_inline_u32(chan
, data
, start
, count
);
483 INLIN_RING(chan
, RING_3D(VERTEX_END_GL
), 0);
485 prim
|= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT
;
489 chan
->flush_notify
= NULL
;
493 nvc0_draw_vbo(struct pipe_context
*pipe
, const struct pipe_draw_info
*info
)
495 struct nvc0_context
*nvc0
= nvc0_context(pipe
);
496 struct nouveau_channel
*chan
= nvc0
->screen
->base
.channel
;
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.
501 nvc0
->vbo_push_hint
= /* the 64 is heuristic */
503 ((info
->max_index
- info
->min_index
+ 64) < info
->count
));
505 nvc0_state_validate(nvc0
);
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
);
513 if (nvc0
->vbo_fifo
) {
514 nvc0_push_vbo(nvc0
, info
);
518 if (nvc0
->vbo_dirty
) {
519 BEGIN_RING(chan
, RING_3D_(0x142c), 1);
521 nvc0
->vbo_dirty
= FALSE
;
524 if (!info
->indexed
) {
525 nvc0_draw_arrays(nvc0
,
526 info
->mode
, info
->start
, info
->count
,
527 info
->instance_count
);
529 boolean shorten
= info
->max_index
<= 65535;
531 assert(nvc0
->idxbuf
.buffer
);
533 if (info
->primitive_restart
!= nvc0
->state
.prim_restart
) {
534 if (info
->primitive_restart
) {
535 BEGIN_RING(chan
, RING_3D(PRIM_RESTART_ENABLE
), 2);
537 OUT_RING (chan
, info
->restart_index
);
539 if (info
->restart_index
> 65535)
542 INLIN_RING(chan
, RING_3D(PRIM_RESTART_ENABLE
), 0);
544 nvc0
->state
.prim_restart
= info
->primitive_restart
;
546 if (info
->primitive_restart
) {
547 BEGIN_RING(chan
, RING_3D(PRIM_RESTART_INDEX
), 1);
548 OUT_RING (chan
, info
->restart_index
);
551 nvc0_draw_elements(nvc0
, shorten
,
552 info
->mode
, info
->start
, info
->count
,
553 info
->instance_count
, info
->index_bias
);