Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/nouveau/nv50/nv50_push.c
4574 views
1
2
#include "pipe/p_context.h"
3
#include "pipe/p_state.h"
4
#include "util/u_inlines.h"
5
#include "util/format/u_format.h"
6
#include "translate/translate.h"
7
8
#include "nv50/nv50_context.h"
9
#include "nv50/nv50_resource.h"
10
11
#include "nv50/nv50_3d.xml.h"
12
13
struct push_context {
14
struct nouveau_pushbuf *push;
15
16
const void *idxbuf;
17
18
float edgeflag;
19
int edgeflag_attr;
20
21
uint32_t vertex_words;
22
uint32_t packet_vertex_limit;
23
24
struct translate *translate;
25
26
bool primitive_restart;
27
28
bool need_vertex_id;
29
int32_t index_bias;
30
31
uint32_t prim;
32
uint32_t restart_index;
33
uint32_t start_instance;
34
uint32_t instance_id;
35
};
36
37
static inline unsigned
38
prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
39
{
40
unsigned i;
41
for (i = 0; i < push; ++i)
42
if (elts[i] == index)
43
break;
44
return i;
45
}
46
47
static inline unsigned
48
prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
49
{
50
unsigned i;
51
for (i = 0; i < push; ++i)
52
if (elts[i] == index)
53
break;
54
return i;
55
}
56
57
static inline unsigned
58
prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
59
{
60
unsigned i;
61
for (i = 0; i < push; ++i)
62
if (elts[i] == index)
63
break;
64
return i;
65
}
66
67
static void
68
emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
69
{
70
uint8_t *elts = (uint8_t *)ctx->idxbuf + start;
71
72
while (count) {
73
unsigned push = MIN2(count, ctx->packet_vertex_limit);
74
unsigned size, nr;
75
76
nr = push;
77
if (ctx->primitive_restart)
78
nr = prim_restart_search_i08(elts, push, ctx->restart_index);
79
80
size = ctx->vertex_words * nr;
81
82
if (unlikely(ctx->need_vertex_id)) {
83
BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1);
84
PUSH_DATA (ctx->push, *elts + ctx->index_bias);
85
}
86
87
BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
88
89
ctx->translate->run_elts8(ctx->translate, elts, nr,
90
ctx->start_instance, ctx->instance_id,
91
ctx->push->cur);
92
93
ctx->push->cur += size;
94
count -= nr;
95
elts += nr;
96
97
if (nr != push) {
98
count--;
99
elts++;
100
BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
101
PUSH_DATA (ctx->push, ctx->restart_index);
102
}
103
}
104
}
105
106
static void
107
emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
108
{
109
uint16_t *elts = (uint16_t *)ctx->idxbuf + start;
110
111
while (count) {
112
unsigned push = MIN2(count, ctx->packet_vertex_limit);
113
unsigned size, nr;
114
115
nr = push;
116
if (ctx->primitive_restart)
117
nr = prim_restart_search_i16(elts, push, ctx->restart_index);
118
119
size = ctx->vertex_words * nr;
120
121
if (unlikely(ctx->need_vertex_id)) {
122
BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1);
123
PUSH_DATA (ctx->push, *elts + ctx->index_bias);
124
}
125
126
BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
127
128
ctx->translate->run_elts16(ctx->translate, elts, nr,
129
ctx->start_instance, ctx->instance_id,
130
ctx->push->cur);
131
132
ctx->push->cur += size;
133
count -= nr;
134
elts += nr;
135
136
if (nr != push) {
137
count--;
138
elts++;
139
BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
140
PUSH_DATA (ctx->push, ctx->restart_index);
141
}
142
}
143
}
144
145
static void
146
emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
147
{
148
uint32_t *elts = (uint32_t *)ctx->idxbuf + start;
149
150
while (count) {
151
unsigned push = MIN2(count, ctx->packet_vertex_limit);
152
unsigned size, nr;
153
154
nr = push;
155
if (ctx->primitive_restart)
156
nr = prim_restart_search_i32(elts, push, ctx->restart_index);
157
158
size = ctx->vertex_words * nr;
159
160
if (unlikely(ctx->need_vertex_id)) {
161
BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1);
162
PUSH_DATA (ctx->push, *elts + ctx->index_bias);
163
}
164
165
BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
166
167
ctx->translate->run_elts(ctx->translate, elts, nr,
168
ctx->start_instance, ctx->instance_id,
169
ctx->push->cur);
170
171
ctx->push->cur += size;
172
count -= nr;
173
elts += nr;
174
175
if (nr != push) {
176
count--;
177
elts++;
178
BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
179
PUSH_DATA (ctx->push, ctx->restart_index);
180
}
181
}
182
}
183
184
static void
185
emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
186
{
187
uint32_t elts = 0;
188
189
while (count) {
190
unsigned push = MIN2(count, ctx->packet_vertex_limit);
191
unsigned size = ctx->vertex_words * push;
192
193
if (unlikely(ctx->need_vertex_id)) {
194
/* For non-indexed draws, gl_VertexID goes up after each vertex. */
195
BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1);
196
PUSH_DATA (ctx->push, elts++);
197
}
198
199
BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
200
201
ctx->translate->run(ctx->translate, start, push,
202
ctx->start_instance, ctx->instance_id,
203
ctx->push->cur);
204
ctx->push->cur += size;
205
count -= push;
206
start += push;
207
}
208
}
209
210
211
#define NV50_PRIM_GL_CASE(n) \
212
case PIPE_PRIM_##n: return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
213
214
static inline unsigned
215
nv50_prim_gl(unsigned prim)
216
{
217
switch (prim) {
218
NV50_PRIM_GL_CASE(POINTS);
219
NV50_PRIM_GL_CASE(LINES);
220
NV50_PRIM_GL_CASE(LINE_LOOP);
221
NV50_PRIM_GL_CASE(LINE_STRIP);
222
NV50_PRIM_GL_CASE(TRIANGLES);
223
NV50_PRIM_GL_CASE(TRIANGLE_STRIP);
224
NV50_PRIM_GL_CASE(TRIANGLE_FAN);
225
NV50_PRIM_GL_CASE(QUADS);
226
NV50_PRIM_GL_CASE(QUAD_STRIP);
227
NV50_PRIM_GL_CASE(POLYGON);
228
NV50_PRIM_GL_CASE(LINES_ADJACENCY);
229
NV50_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
230
NV50_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
231
NV50_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
232
/*
233
NV50_PRIM_GL_CASE(PATCHES); */
234
default:
235
return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
236
break;
237
}
238
}
239
240
void
241
nv50_push_vbo(struct nv50_context *nv50, const struct pipe_draw_info *info,
242
const struct pipe_draw_indirect_info *indirect,
243
const struct pipe_draw_start_count_bias *draw)
244
{
245
struct push_context ctx;
246
unsigned i, index_size;
247
unsigned inst_count = info->instance_count;
248
unsigned vert_count = draw->count;
249
bool apply_bias = info->index_size && draw->index_bias;
250
251
ctx.push = nv50->base.pushbuf;
252
ctx.translate = nv50->vertex->translate;
253
254
ctx.need_vertex_id = nv50->screen->base.class_3d >= NV84_3D_CLASS &&
255
nv50->vertprog->vp.need_vertex_id && (nv50->vertex->num_elements < 32);
256
ctx.index_bias = info->index_size ? draw->index_bias : 0;
257
ctx.instance_id = 0;
258
259
/* For indexed draws, gl_VertexID must be emitted for every vertex. */
260
ctx.packet_vertex_limit =
261
ctx.need_vertex_id ? 1 : nv50->vertex->packet_vertex_limit;
262
ctx.vertex_words = nv50->vertex->vertex_size;
263
264
assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
265
for (i = 0; i < nv50->num_vtxbufs; ++i) {
266
const struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i];
267
const uint8_t *data;
268
269
if (unlikely(!vb->is_user_buffer)) {
270
if (!vb->buffer.resource)
271
continue;
272
273
data = nouveau_resource_map_offset(&nv50->base,
274
nv04_resource(vb->buffer.resource), vb->buffer_offset, NOUVEAU_BO_RD);
275
} else
276
data = vb->buffer.user;
277
278
if (apply_bias && likely(!(nv50->vertex->instance_bufs & (1 << i))))
279
data += (ptrdiff_t)(info->index_size ? draw->index_bias : 0) * vb->stride;
280
281
ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
282
}
283
284
if (info->index_size) {
285
if (!info->has_user_indices) {
286
ctx.idxbuf = nouveau_resource_map_offset(&nv50->base,
287
nv04_resource(info->index.resource), 0, NOUVEAU_BO_RD);
288
} else {
289
ctx.idxbuf = info->index.user;
290
}
291
if (!ctx.idxbuf)
292
return;
293
index_size = info->index_size;
294
ctx.primitive_restart = info->primitive_restart;
295
ctx.restart_index = info->restart_index;
296
} else {
297
if (unlikely(indirect && indirect->count_from_stream_output)) {
298
struct pipe_context *pipe = &nv50->base.pipe;
299
struct nv50_so_target *targ;
300
targ = nv50_so_target(indirect->count_from_stream_output);
301
if (!targ->pq) {
302
NOUVEAU_ERR("draw_stream_output not supported on pre-NVA0 cards\n");
303
return;
304
}
305
pipe->get_query_result(pipe, targ->pq, true, (void *)&vert_count);
306
vert_count /= targ->stride;
307
}
308
ctx.idxbuf = NULL;
309
index_size = 0;
310
ctx.primitive_restart = false;
311
ctx.restart_index = 0;
312
}
313
314
ctx.start_instance = info->start_instance;
315
ctx.prim = nv50_prim_gl(info->mode);
316
317
if (info->primitive_restart) {
318
BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 2);
319
PUSH_DATA (ctx.push, 1);
320
PUSH_DATA (ctx.push, info->restart_index);
321
} else
322
if (nv50->state.prim_restart) {
323
BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 1);
324
PUSH_DATA (ctx.push, 0);
325
}
326
nv50->state.prim_restart = info->primitive_restart;
327
328
while (inst_count--) {
329
BEGIN_NV04(ctx.push, NV50_3D(VERTEX_BEGIN_GL), 1);
330
PUSH_DATA (ctx.push, ctx.prim);
331
switch (index_size) {
332
case 0:
333
emit_vertices_seq(&ctx, draw->start, vert_count);
334
break;
335
case 1:
336
emit_vertices_i08(&ctx, draw->start, vert_count);
337
break;
338
case 2:
339
emit_vertices_i16(&ctx, draw->start, vert_count);
340
break;
341
case 4:
342
emit_vertices_i32(&ctx, draw->start, vert_count);
343
break;
344
default:
345
assert(0);
346
break;
347
}
348
BEGIN_NV04(ctx.push, NV50_3D(VERTEX_END_GL), 1);
349
PUSH_DATA (ctx.push, 0);
350
351
ctx.instance_id++;
352
ctx.prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
353
}
354
355
if (unlikely(ctx.need_vertex_id)) {
356
/* Reset gl_VertexID to prevent future indexed draws to be confused. */
357
BEGIN_NV04(ctx.push, NV84_3D(VERTEX_ID_BASE), 1);
358
PUSH_DATA (ctx.push, nv50->state.index_bias);
359
}
360
}
361
362