1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "util/u_inlines.h"
4 #include "util/u_format.h"
5 #include "util/u_split_prim.h"
6 #include "translate/translate.h"
8 #include "nvfx_context.h"
9 #include "nvfx_resource.h"
12 struct nouveau_channel
* chan
;
13 struct nouveau_grobj
*eng3d
;
21 unsigned vertex_length
;
22 unsigned max_vertices_per_packet
;
24 struct translate
* translate
;
28 emit_edgeflag(void *priv
, boolean enabled
)
30 struct push_context
* ctx
= priv
;
31 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
32 struct nouveau_channel
*chan
= ctx
->chan
;
34 BEGIN_RING(chan
, eng3d
, NV30_3D_EDGEFLAG
, 1);
35 OUT_RING(chan
, enabled
? 1 : 0);
39 emit_vertices_lookup8(void *priv
, unsigned start
, unsigned count
)
41 struct push_context
*ctx
= priv
;
42 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
43 uint8_t* elts
= (uint8_t*)ctx
->idxbuf
+ start
;
47 unsigned push
= MIN2(count
, ctx
->max_vertices_per_packet
);
48 unsigned length
= push
* ctx
->vertex_length
;
50 BEGIN_RING_NI(ctx
->chan
, eng3d
, NV30_3D_VERTEX_DATA
, length
);
51 ctx
->translate
->run_elts8(ctx
->translate
, elts
, push
, 0, ctx
->chan
->cur
);
52 ctx
->chan
->cur
+= length
;
60 emit_vertices_lookup16(void *priv
, unsigned start
, unsigned count
)
62 struct push_context
*ctx
= priv
;
63 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
64 uint16_t* elts
= (uint16_t*)ctx
->idxbuf
+ start
;
68 unsigned push
= MIN2(count
, ctx
->max_vertices_per_packet
);
69 unsigned length
= push
* ctx
->vertex_length
;
71 BEGIN_RING_NI(ctx
->chan
, eng3d
, NV30_3D_VERTEX_DATA
, length
);
72 ctx
->translate
->run_elts16(ctx
->translate
, elts
, push
, 0, ctx
->chan
->cur
);
73 ctx
->chan
->cur
+= length
;
81 emit_vertices_lookup32(void *priv
, unsigned start
, unsigned count
)
83 struct push_context
*ctx
= priv
;
84 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
85 uint32_t* elts
= (uint32_t*)ctx
->idxbuf
+ start
;
89 unsigned push
= MIN2(count
, ctx
->max_vertices_per_packet
);
90 unsigned length
= push
* ctx
->vertex_length
;
92 BEGIN_RING_NI(ctx
->chan
, eng3d
, NV30_3D_VERTEX_DATA
, length
);
93 ctx
->translate
->run_elts(ctx
->translate
, elts
, push
, 0, ctx
->chan
->cur
);
94 ctx
->chan
->cur
+= length
;
102 emit_vertices(void *priv
, unsigned start
, unsigned count
)
104 struct push_context
*ctx
= priv
;
105 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
109 unsigned push
= MIN2(count
, ctx
->max_vertices_per_packet
);
110 unsigned length
= push
* ctx
->vertex_length
;
112 BEGIN_RING_NI(ctx
->chan
, eng3d
, NV30_3D_VERTEX_DATA
, length
);
113 ctx
->translate
->run(ctx
->translate
, start
, push
, 0, ctx
->chan
->cur
);
114 ctx
->chan
->cur
+= length
;
122 emit_ranges(void* priv
, unsigned start
, unsigned vc
, unsigned reg
)
124 struct push_context
* ctx
= priv
;
125 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
126 struct nouveau_channel
*chan
= ctx
->chan
;
127 unsigned nr
= (vc
& 0xff);
129 BEGIN_RING(chan
, eng3d
, reg
, 1);
130 OUT_RING (chan
, ((nr
- 1) << 24) | start
);
136 unsigned push
= nr
> 2047 ? 2047 : nr
;
140 BEGIN_RING_NI(chan
, eng3d
, reg
, push
);
142 OUT_RING(chan
, ((0x100 - 1) << 24) | start
);
149 emit_ib_ranges(void* priv
, unsigned start
, unsigned vc
)
151 emit_ranges(priv
, start
, vc
, NV30_3D_VB_INDEX_BATCH
);
155 emit_vb_ranges(void* priv
, unsigned start
, unsigned vc
)
157 emit_ranges(priv
, start
, vc
, NV30_3D_VB_VERTEX_BATCH
);
161 emit_elt8(void* priv
, unsigned start
, unsigned vc
)
163 struct push_context
* ctx
= priv
;
164 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
165 struct nouveau_channel
*chan
= ctx
->chan
;
166 uint8_t *elts
= (uint8_t *)ctx
->idxbuf
+ start
;
167 int idxbias
= ctx
->idxbias
;
170 BEGIN_RING(chan
, eng3d
, NV30_3D_VB_ELEMENT_U32
, 1);
171 OUT_RING (chan
, elts
[0]);
177 unsigned push
= MIN2(vc
, 2047 * 2);
179 BEGIN_RING_NI(chan
, eng3d
, NV30_3D_VB_ELEMENT_U16
, push
>> 1);
180 for (i
= 0; i
< push
; i
+=2)
181 OUT_RING(chan
, ((elts
[i
+1] + idxbias
) << 16) | (elts
[i
] + idxbias
));
189 emit_elt16(void* priv
, unsigned start
, unsigned vc
)
191 struct push_context
* ctx
= priv
;
192 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
193 struct nouveau_channel
*chan
= ctx
->chan
;
194 uint16_t *elts
= (uint16_t *)ctx
->idxbuf
+ start
;
195 int idxbias
= ctx
->idxbias
;
198 BEGIN_RING(chan
, eng3d
, NV30_3D_VB_ELEMENT_U32
, 1);
199 OUT_RING (chan
, elts
[0]);
205 unsigned push
= MIN2(vc
, 2047 * 2);
207 BEGIN_RING_NI(chan
, eng3d
, NV30_3D_VB_ELEMENT_U16
, push
>> 1);
208 for (i
= 0; i
< push
; i
+=2)
209 OUT_RING(chan
, ((elts
[i
+1] + idxbias
) << 16) | (elts
[i
] + idxbias
));
217 emit_elt32(void* priv
, unsigned start
, unsigned vc
)
219 struct push_context
* ctx
= priv
;
220 struct nouveau_grobj
*eng3d
= ctx
->eng3d
;
221 struct nouveau_channel
*chan
= ctx
->chan
;
222 uint32_t *elts
= (uint32_t *)ctx
->idxbuf
+ start
;
223 int idxbias
= ctx
->idxbias
;
226 unsigned push
= MIN2(vc
, 2047);
228 BEGIN_RING_NI(chan
, eng3d
, NV30_3D_VB_ELEMENT_U32
, push
);
231 for(unsigned i
= 0; i
< push
; ++i
)
232 OUT_RING(chan
, elts
[i
] + idxbias
);
235 OUT_RINGp(chan
, elts
, push
);
243 nvfx_push_vbo(struct pipe_context
*pipe
, const struct pipe_draw_info
*info
)
245 struct nvfx_context
*nvfx
= nvfx_context(pipe
);
246 struct nouveau_channel
*chan
= nvfx
->screen
->base
.channel
;
247 struct nouveau_grobj
*eng3d
= nvfx
->screen
->eng3d
;
248 struct push_context ctx
;
249 struct util_split_prim s
;
250 unsigned instances_left
= info
->instance_count
;
252 unsigned hw_mode
= nvgl_primitive(info
->mode
);
259 unsigned p_overhead
= 64 /* magic fix */
261 + 4; /* potential edgeflag enable/disable */
263 ctx
.chan
= nvfx
->screen
->base
.channel
;
264 ctx
.eng3d
= nvfx
->screen
->eng3d
;
265 ctx
.translate
= nvfx
->vtxelt
->translate
;
267 ctx
.vertex_length
= nvfx
->vtxelt
->vertex_length
;
268 ctx
.max_vertices_per_packet
= nvfx
->vtxelt
->max_vertices_per_packet
;
270 // TODO: figure out if we really want to handle this, and do so in that case
271 ctx
.edgeflag_attr
= 0xff; // nvfx->vertprog->cfg.edgeflag_in;
273 if(!nvfx
->use_vertex_buffers
)
275 for(i
= 0; i
< nvfx
->vtxelt
->num_per_vertex_buffer_infos
; ++i
)
277 struct nvfx_per_vertex_buffer_info
* vbi
= &nvfx
->vtxelt
->per_vertex_buffer_info
[i
];
278 struct pipe_vertex_buffer
*vb
= &nvfx
->vtxbuf
[vbi
->vertex_buffer_index
];
279 uint8_t* data
= nvfx_buffer(vb
->buffer
)->data
+ vb
->buffer_offset
;
281 data
+= info
->index_bias
* vb
->stride
;
282 ctx
.translate
->set_buffer(ctx
.translate
, i
, data
, vb
->stride
, ~0);
285 if(ctx
.edgeflag_attr
< 16)
286 vtx_value
= -(ctx
.vertex_length
+ 3); /* vertex data and edgeflag header and value */
289 p_overhead
+= 1; /* initial vertex_data header */
290 vtx_value
= -ctx
.vertex_length
; /* vertex data and edgeflag header and value */
294 // XXX: this case and is broken and probably need a new VTX_ATTR push path
295 if (nvfx
->idxbuf
.index_size
== 1)
296 s
.emit
= emit_vertices_lookup8
;
297 else if (nvfx
->idxbuf
.index_size
== 2)
298 s
.emit
= emit_vertices_lookup16
;
300 s
.emit
= emit_vertices_lookup32
;
302 s
.emit
= emit_vertices
;
306 if(!info
->indexed
|| nvfx
->use_index_buffer
)
308 s
.emit
= info
->indexed
? emit_ib_ranges
: emit_vb_ranges
;
312 else if (nvfx
->idxbuf
.index_size
== 4)
320 s
.emit
= (nvfx
->idxbuf
.index_size
== 2) ? emit_elt16
: emit_elt8
;
326 ctx
.idxbias
= info
->index_bias
;
327 if(nvfx
->use_vertex_buffers
)
328 ctx
.idxbias
-= nvfx
->base_vertex
;
330 /* map index buffer, if present */
331 if (info
->indexed
&& !nvfx
->use_index_buffer
)
332 ctx
.idxbuf
= nvfx_buffer(nvfx
->idxbuf
.buffer
)->data
+ nvfx
->idxbuf
.offset
;
335 s
.edge
= emit_edgeflag
;
337 for (i
= 0; i
< nvfx
->vtxelt
->num_per_instance
; ++i
)
339 struct nvfx_per_instance_element
*ve
= &nvfx
->vtxelt
->per_instance
[i
];
340 struct pipe_vertex_buffer
*vb
= &nvfx
->vtxbuf
[ve
->base
.vertex_buffer_index
];
342 per_instance
[i
].step
= info
->start_instance
% ve
->instance_divisor
;
343 per_instance
[i
].map
= nvfx_buffer(vb
->buffer
)->data
+ vb
->buffer_offset
+ ve
->base
.src_offset
;
345 nvfx
->vtxelt
->per_instance
[i
].base
.fetch_rgba_float(v
, per_instance
[i
].map
, 0, 0);
347 nvfx_emit_vtx_attr(chan
, eng3d
,
348 nvfx
->vtxelt
->per_instance
[i
].base
.idx
, v
,
349 nvfx
->vtxelt
->per_instance
[i
].base
.ncomp
);
352 /* per-instance loop */
353 while (instances_left
--) {
357 util_split_prim_init(&s
, info
->mode
, info
->start
, info
->count
);
358 nvfx_state_emit(nvfx
);
360 max_verts
= AVAIL_RING(chan
);
361 max_verts
-= p_overhead
;
363 /* if vtx_value < 0, each vertex is -vtx_value words long
364 * otherwise, each vertex is 2^(vtx_value) / 255 words long (this is an approximation)
368 max_verts
/= -vtx_value
;
369 max_verts
-= (max_verts
>> 10); /* vertex data headers */
373 if(max_verts
>= (1 << 23)) /* avoid overflow here */
374 max_verts
= (1 << 23);
375 max_verts
= (max_verts
* 255) >> vtx_value
;
378 //printf("avail %u max_verts %u\n", AVAIL_RING(chan), max_verts);
382 /* XXX: any command a lot of times seems to (mostly) fix corruption that would otherwise happen */
383 /* this seems to cause issues on nv3x, and also be unneeded there */
387 for(i
= 0; i
< 32; ++i
)
389 BEGIN_RING(chan
, eng3d
,
395 BEGIN_RING(chan
, eng3d
,
396 NV30_3D_VERTEX_BEGIN_END
, 1);
397 OUT_RING(chan
, hw_mode
);
398 done
= util_split_prim_next(&s
, max_verts
);
399 BEGIN_RING(chan
, eng3d
,
400 NV30_3D_VERTEX_BEGIN_END
, 1);
408 nvfx_state_emit(nvfx
);
411 /* set data for the next instance, if any changed */
412 for (i
= 0; i
< nvfx
->vtxelt
->num_per_instance
; ++i
)
414 struct nvfx_per_instance_element
*ve
= &nvfx
->vtxelt
->per_instance
[i
];
415 struct pipe_vertex_buffer
*vb
= &nvfx
->vtxbuf
[ve
->base
.vertex_buffer_index
];
417 if(++per_instance
[i
].step
== ve
->instance_divisor
)
420 per_instance
[i
].map
+= vb
->stride
;
421 per_instance
[i
].step
= 0;
423 nvfx
->vtxelt
->per_instance
[i
].base
.fetch_rgba_float(v
, per_instance
[i
].map
, 0, 0);
424 nvfx_emit_vtx_attr(chan
, eng3d
,
425 nvfx
->vtxelt
->per_instance
[i
].base
.idx
,
427 nvfx
->vtxelt
->per_instance
[i
].base
.ncomp
);