Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/svga/svga_pipe_draw.c
4570 views
1
/**********************************************************
2
* Copyright 2008-2009 VMware, Inc. All rights reserved.
3
*
4
* Permission is hereby granted, free of charge, to any person
5
* obtaining a copy of this software and associated documentation
6
* files (the "Software"), to deal in the Software without
7
* restriction, including without limitation the rights to use, copy,
8
* modify, merge, publish, distribute, sublicense, and/or sell copies
9
* of the Software, and to permit persons to whom the Software is
10
* furnished to do so, subject to the following conditions:
11
*
12
* The above copyright notice and this permission notice shall be
13
* included in all copies or substantial portions of the Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* SOFTWARE.
23
*
24
**********************************************************/
25
26
27
#include "util/u_draw.h"
28
#include "util/format/u_format.h"
29
#include "util/u_helpers.h"
30
#include "util/u_inlines.h"
31
#include "util/u_prim.h"
32
#include "util/u_prim_restart.h"
33
34
#include "svga_context.h"
35
#include "svga_draw_private.h"
36
#include "svga_screen.h"
37
#include "svga_draw.h"
38
#include "svga_shader.h"
39
#include "svga_surface.h"
40
#include "svga_swtnl.h"
41
#include "svga_debug.h"
42
#include "svga_resource_buffer.h"
43
44
45
static enum pipe_error
46
retry_draw_range_elements(struct svga_context *svga,
47
const struct pipe_draw_info *info,
48
const struct pipe_draw_start_count_bias *draw,
49
unsigned count)
50
{
51
SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWELEMENTS);
52
53
SVGA_RETRY(svga, svga_hwtnl_draw_range_elements(svga->hwtnl, info, draw, count));
54
55
SVGA_STATS_TIME_POP(svga_sws(svga));
56
return PIPE_OK;
57
}
58
59
60
static enum pipe_error
61
retry_draw_arrays( struct svga_context *svga,
62
enum pipe_prim_type prim, unsigned start, unsigned count,
63
unsigned start_instance, unsigned instance_count,
64
ubyte vertices_per_patch)
65
{
66
enum pipe_error ret;
67
68
SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWARRAYS);
69
70
SVGA_RETRY_OOM(svga, ret, svga_hwtnl_draw_arrays(svga->hwtnl, prim, start,
71
count, start_instance,
72
instance_count,
73
vertices_per_patch));
74
SVGA_STATS_TIME_POP(svga_sws(svga));
75
return ret;
76
}
77
78
79
/**
80
* Auto draw (get vertex count from a transform feedback result).
81
*/
82
static enum pipe_error
83
retry_draw_auto(struct svga_context *svga,
84
const struct pipe_draw_info *info,
85
const struct pipe_draw_indirect_info *indirect)
86
{
87
assert(svga_have_sm5(svga));
88
assert(indirect->count_from_stream_output);
89
assert(info->instance_count == 1);
90
/* SO drawing implies core profile and none of these prim types */
91
assert(info->mode != PIPE_PRIM_QUADS &&
92
info->mode != PIPE_PRIM_QUAD_STRIP &&
93
info->mode != PIPE_PRIM_POLYGON);
94
95
if (info->mode == PIPE_PRIM_LINE_LOOP) {
96
/* XXX need to do a fallback */
97
assert(!"draw auto fallback not supported yet");
98
return PIPE_OK;
99
}
100
else {
101
SVGA3dPrimitiveRange range;
102
unsigned hw_count;
103
104
range.primType = svga_translate_prim(info->mode, 12, &hw_count,
105
info->vertices_per_patch);
106
range.primitiveCount = 0;
107
range.indexArray.surfaceId = SVGA3D_INVALID_ID;
108
range.indexArray.offset = 0;
109
range.indexArray.stride = 0;
110
range.indexWidth = 0;
111
range.indexBias = 0;
112
113
SVGA_RETRY(svga, svga_hwtnl_prim
114
(svga->hwtnl, &range,
115
0, /* vertex count comes from SO buffer */
116
0, /* don't know min index */
117
~0u, /* don't know max index */
118
NULL, /* no index buffer */
119
0, /* start instance */
120
1, /* only 1 instance supported */
121
NULL, /* indirect drawing info */
122
indirect->count_from_stream_output));
123
124
return PIPE_OK;
125
}
126
}
127
128
129
/**
130
* Indirect draw (get vertex count, start index, etc. from a buffer object.
131
*/
132
static enum pipe_error
133
retry_draw_indirect(struct svga_context *svga,
134
const struct pipe_draw_info *info,
135
const struct pipe_draw_indirect_info *indirect)
136
{
137
assert(svga_have_sm5(svga));
138
assert(indirect && indirect->buffer);
139
/* indirect drawing implies core profile and none of these prim types */
140
assert(info->mode != PIPE_PRIM_QUADS &&
141
info->mode != PIPE_PRIM_QUAD_STRIP &&
142
info->mode != PIPE_PRIM_POLYGON);
143
144
if (info->mode == PIPE_PRIM_LINE_LOOP) {
145
/* need to do a fallback */
146
util_draw_indirect(&svga->pipe, info, indirect);
147
return PIPE_OK;
148
}
149
else {
150
SVGA3dPrimitiveRange range;
151
unsigned hw_count;
152
153
range.primType = svga_translate_prim(info->mode, 12, &hw_count,
154
info->vertices_per_patch);
155
range.primitiveCount = 0; /* specified in indirect buffer */
156
range.indexArray.surfaceId = SVGA3D_INVALID_ID;
157
range.indexArray.offset = 0;
158
range.indexArray.stride = 0;
159
range.indexWidth = info->index_size;
160
range.indexBias = 0; /* specified in indirect buffer */
161
162
SVGA_RETRY(svga, svga_hwtnl_prim
163
(svga->hwtnl, &range,
164
0, /* vertex count is in indirect buffer */
165
0, /* don't know min index */
166
~0u, /* don't know max index */
167
info->index.resource,
168
info->start_instance,
169
0, /* don't know instance count */
170
indirect,
171
NULL)); /* SO vertex count */
172
173
return PIPE_OK;
174
}
175
}
176
177
178
/**
179
* Determine if we need to implement primitive restart with a fallback
180
* path which breaks the original primitive into sub-primitive at the
181
* restart indexes.
182
*/
183
static boolean
184
need_fallback_prim_restart(const struct svga_context *svga,
185
const struct pipe_draw_info *info)
186
{
187
if (info->primitive_restart && info->index_size) {
188
if (!svga_have_vgpu10(svga))
189
return TRUE;
190
else if (!svga->state.sw.need_swtnl) {
191
if (info->index_size == 1)
192
return TRUE; /* no device support for 1-byte indexes */
193
else if (info->index_size == 2)
194
return info->restart_index != 0xffff;
195
else
196
return info->restart_index != 0xffffffff;
197
}
198
}
199
200
return FALSE;
201
}
202
203
204
/**
205
* A helper function to return the vertex count from the primitive count
206
* returned from the stream output statistics query for the specified stream.
207
*/
208
static unsigned
209
get_vcount_from_stream_output(struct svga_context *svga,
210
const struct pipe_draw_info *info,
211
unsigned stream)
212
{
213
unsigned primcount;
214
primcount = svga_get_primcount_from_stream_output(svga, stream);
215
return u_vertices_for_prims(info->mode, primcount);
216
}
217
218
219
static void
220
svga_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info,
221
unsigned drawid_offset,
222
const struct pipe_draw_indirect_info *indirect,
223
const struct pipe_draw_start_count_bias *draws,
224
unsigned num_draws)
225
{
226
if (num_draws > 1) {
227
util_draw_multi(pipe, info, drawid_offset, indirect, draws, num_draws);
228
return;
229
}
230
231
if (!indirect && (!draws[0].count || !info->instance_count))
232
return;
233
234
struct svga_context *svga = svga_context(pipe);
235
enum pipe_prim_type reduced_prim = u_reduced_prim(info->mode);
236
unsigned count = draws[0].count;
237
enum pipe_error ret = 0;
238
boolean needed_swtnl;
239
240
SVGA_STATS_TIME_PUSH(svga_sws(svga), SVGA_STATS_TIME_DRAWVBO);
241
242
svga->hud.num_draw_calls++; /* for SVGA_QUERY_NUM_DRAW_CALLS */
243
244
if (u_reduced_prim(info->mode) == PIPE_PRIM_TRIANGLES &&
245
svga->curr.rast->templ.cull_face == PIPE_FACE_FRONT_AND_BACK)
246
goto done;
247
248
/*
249
* Mark currently bound target surfaces as dirty
250
* doesn't really matter if it is done before drawing.
251
*
252
* TODO If we ever normaly return something other then
253
* true we should not mark it as dirty then.
254
*/
255
svga_mark_surfaces_dirty(svga_context(pipe));
256
257
if (svga->curr.reduced_prim != reduced_prim) {
258
svga->curr.reduced_prim = reduced_prim;
259
svga->dirty |= SVGA_NEW_REDUCED_PRIMITIVE;
260
}
261
262
/* We need to adjust the vertexID in the vertex shader since SV_VertexID
263
* always start from 0 for DrawArrays and does not include baseVertex for
264
* DrawIndexed.
265
*/
266
unsigned index_bias = info->index_size ? draws->index_bias : 0;
267
if (svga->curr.vertex_id_bias != (draws[0].start + index_bias)) {
268
svga->curr.vertex_id_bias = draws[0].start + index_bias;
269
svga->dirty |= SVGA_NEW_VS_CONSTS;
270
}
271
272
if (svga->curr.vertices_per_patch != info->vertices_per_patch) {
273
svga->curr.vertices_per_patch = info->vertices_per_patch;
274
275
/* If input patch size changes, we need to notifiy the TCS
276
* code to reevaluate the shader variant since the
277
* vertices per patch count is a constant in the control
278
* point count declaration.
279
*/
280
if (svga->curr.tcs || svga->curr.tes)
281
svga->dirty |= SVGA_NEW_TCS_PARAM;
282
}
283
284
if (need_fallback_prim_restart(svga, info)) {
285
enum pipe_error r;
286
r = util_draw_vbo_without_prim_restart(pipe, info, drawid_offset, indirect, &draws[0]);
287
assert(r == PIPE_OK);
288
(void) r;
289
goto done;
290
}
291
292
if (!indirect && !u_trim_pipe_prim(info->mode, &count))
293
goto done;
294
295
needed_swtnl = svga->state.sw.need_swtnl;
296
297
svga_update_state_retry(svga, SVGA_STATE_NEED_SWTNL);
298
299
if (svga->state.sw.need_swtnl) {
300
svga->hud.num_fallbacks++; /* for SVGA_QUERY_NUM_FALLBACKS */
301
if (!needed_swtnl) {
302
/*
303
* We're switching from HW to SW TNL. SW TNL will require mapping all
304
* currently bound vertex buffers, some of which may already be
305
* referenced in the current command buffer as result of previous HW
306
* TNL. So flush now, to prevent the context to flush while a referred
307
* vertex buffer is mapped.
308
*/
309
310
svga_context_flush(svga, NULL);
311
}
312
313
/* Avoid leaking the previous hwtnl bias to swtnl */
314
svga_hwtnl_set_index_bias(svga->hwtnl, 0);
315
ret = svga_swtnl_draw_vbo(svga, info, drawid_offset, indirect, &draws[0]);
316
}
317
else {
318
if (!svga_update_state_retry(svga, SVGA_STATE_HW_DRAW)) {
319
static const char *msg = "State update failed, skipping draw call";
320
debug_printf("%s\n", msg);
321
pipe_debug_message(&svga->debug.callback, INFO, "%s", msg);
322
goto done;
323
}
324
svga_hwtnl_set_fillmode(svga->hwtnl, svga->curr.rast->hw_fillmode);
325
326
svga_update_state_retry(svga, SVGA_STATE_HW_DRAW);
327
328
/** determine if flatshade is to be used after svga_update_state()
329
* in case the fragment shader is changed.
330
*/
331
svga_hwtnl_set_flatshade(svga->hwtnl,
332
svga->curr.rast->templ.flatshade ||
333
svga_is_using_flat_shading(svga),
334
svga->curr.rast->templ.flatshade_first);
335
336
if (indirect && indirect->count_from_stream_output) {
337
unsigned stream = 0;
338
assert(count == 0);
339
340
/* If the vertex count is from the stream output of a non-zero stream
341
* or the draw info specifies instancing, we will need a workaround
342
* since the draw_auto command does not support stream instancing.
343
* The workaround requires querying the vertex count from the
344
* stream output statistics query for the specified stream and then
345
* fallback to the regular draw function.
346
*/
347
348
/* Check the stream index of the specified stream output target */
349
for (unsigned i = 0; i < ARRAY_SIZE(svga->so_targets); i++) {
350
if (svga->vcount_so_targets[i] == indirect->count_from_stream_output) {
351
stream = (svga->vcount_buffer_stream >> (i * 4)) & 0xf;
352
break;
353
}
354
}
355
if (info->instance_count > 1 || stream > 0) {
356
count = get_vcount_from_stream_output(svga, info, stream);
357
}
358
}
359
360
if (indirect && indirect->count_from_stream_output && count == 0) {
361
ret = retry_draw_auto(svga, info, indirect);
362
}
363
else if (indirect && indirect->buffer) {
364
ret = retry_draw_indirect(svga, info, indirect);
365
}
366
else if (info->index_size) {
367
ret = retry_draw_range_elements(svga, info, &draws[0], count);
368
}
369
else {
370
ret = retry_draw_arrays(svga, info->mode, draws[0].start, count,
371
info->start_instance, info->instance_count,
372
info->vertices_per_patch);
373
}
374
}
375
376
/* XXX: Silence warnings, do something sensible here? */
377
(void)ret;
378
379
if (SVGA_DEBUG & DEBUG_FLUSH) {
380
svga_hwtnl_flush_retry(svga);
381
svga_context_flush(svga, NULL);
382
}
383
384
done:
385
SVGA_STATS_TIME_POP(svga_sws(svga));
386
}
387
388
389
void
390
svga_init_draw_functions(struct svga_context *svga)
391
{
392
svga->pipe.draw_vbo = svga_draw_vbo;
393
}
394
395