Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/crocus/crocus_draw.c
4570 views
1
/*
2
* Copyright © 2017 Intel Corporation
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
12
* in all copies or substantial portions of the Software.
13
*
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
* OR 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 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
* DEALINGS IN THE SOFTWARE.
21
*/
22
23
/**
24
* @file crocus_draw.c
25
*
26
* The main driver hooks for drawing and launching compute shaders.
27
*/
28
29
#include <stdio.h>
30
#include <errno.h>
31
#include "pipe/p_defines.h"
32
#include "pipe/p_state.h"
33
#include "pipe/p_context.h"
34
#include "pipe/p_screen.h"
35
#include "util/u_draw.h"
36
#include "util/u_inlines.h"
37
#include "util/u_transfer.h"
38
#include "util/u_upload_mgr.h"
39
#include "intel/compiler/brw_compiler.h"
40
#include "intel/compiler/brw_eu_defines.h"
41
#include "crocus_context.h"
42
#include "crocus_defines.h"
43
#include "util/u_prim_restart.h"
44
#include "indices/u_primconvert.h"
45
#include "util/u_prim.h"
46
47
static bool
48
prim_is_points_or_lines(enum pipe_prim_type mode)
49
{
50
/* We don't need to worry about adjacency - it can only be used with
51
* geometry shaders, and we don't care about this info when GS is on.
52
*/
53
return mode == PIPE_PRIM_POINTS ||
54
mode == PIPE_PRIM_LINES ||
55
mode == PIPE_PRIM_LINE_LOOP ||
56
mode == PIPE_PRIM_LINE_STRIP;
57
}
58
59
static bool
60
can_cut_index_handle_restart_index(struct crocus_context *ice,
61
const struct pipe_draw_info *draw)
62
{
63
switch (draw->index_size) {
64
case 1:
65
return draw->restart_index == 0xff;
66
case 2:
67
return draw->restart_index == 0xffff;
68
case 4:
69
return draw->restart_index == 0xffffffff;
70
default:
71
unreachable("illegal index size\n");
72
}
73
74
return false;
75
}
76
77
static bool
78
can_cut_index_handle_prim(struct crocus_context *ice,
79
const struct pipe_draw_info *draw)
80
{
81
struct crocus_screen *screen = (struct crocus_screen*)ice->ctx.screen;
82
const struct intel_device_info *devinfo = &screen->devinfo;
83
84
/* Haswell can do it all. */
85
if (devinfo->verx10 >= 75)
86
return true;
87
88
if (!can_cut_index_handle_restart_index(ice, draw))
89
return false;
90
91
switch (draw->mode) {
92
case PIPE_PRIM_POINTS:
93
case PIPE_PRIM_LINES:
94
case PIPE_PRIM_LINE_STRIP:
95
case PIPE_PRIM_TRIANGLES:
96
case PIPE_PRIM_TRIANGLE_STRIP:
97
case PIPE_PRIM_LINES_ADJACENCY:
98
case PIPE_PRIM_LINE_STRIP_ADJACENCY:
99
case PIPE_PRIM_TRIANGLES_ADJACENCY:
100
case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
101
return true;
102
default:
103
break;
104
}
105
return false;
106
}
107
108
/**
109
* Record the current primitive mode and restart information, flagging
110
* related packets as dirty if necessary.
111
*
112
* This must be called before updating compiled shaders, because the patch
113
* information informs the TCS key.
114
*/
115
static void
116
crocus_update_draw_info(struct crocus_context *ice,
117
const struct pipe_draw_info *info,
118
const struct pipe_draw_start_count_bias *draw)
119
{
120
struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
121
enum pipe_prim_type mode = info->mode;
122
123
if (screen->devinfo.ver < 6) {
124
/* Slight optimization to avoid the GS program when not needed:
125
*/
126
struct pipe_rasterizer_state *rs_state = crocus_get_rast_state(ice);
127
if (mode == PIPE_PRIM_QUAD_STRIP && !rs_state->flatshade &&
128
rs_state->fill_front == PIPE_POLYGON_MODE_FILL &&
129
rs_state->fill_back == PIPE_POLYGON_MODE_FILL)
130
mode = PIPE_PRIM_TRIANGLE_STRIP;
131
if (mode == PIPE_PRIM_QUADS &&
132
draw->count == 4 &&
133
!rs_state->flatshade &&
134
rs_state->fill_front == PIPE_POLYGON_MODE_FILL &&
135
rs_state->fill_back == PIPE_POLYGON_MODE_FILL)
136
mode = PIPE_PRIM_TRIANGLE_FAN;
137
}
138
139
if (ice->state.prim_mode != mode) {
140
ice->state.prim_mode = mode;
141
142
if (screen->devinfo.ver == 8)
143
ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_TOPOLOGY;
144
145
if (screen->devinfo.ver < 6)
146
ice->state.dirty |= CROCUS_DIRTY_GEN4_CLIP_PROG | CROCUS_DIRTY_GEN4_SF_PROG;
147
if (screen->devinfo.ver <= 6)
148
ice->state.dirty |= CROCUS_DIRTY_GEN4_FF_GS_PROG;
149
150
if (screen->devinfo.ver >= 7)
151
ice->state.dirty |= CROCUS_DIRTY_GEN7_SBE;
152
153
/* For XY Clip enables */
154
bool points_or_lines = prim_is_points_or_lines(mode);
155
if (points_or_lines != ice->state.prim_is_points_or_lines) {
156
ice->state.prim_is_points_or_lines = points_or_lines;
157
ice->state.dirty |= CROCUS_DIRTY_CLIP;
158
}
159
}
160
161
if (info->mode == PIPE_PRIM_PATCHES &&
162
ice->state.vertices_per_patch != info->vertices_per_patch) {
163
ice->state.vertices_per_patch = info->vertices_per_patch;
164
165
if (screen->devinfo.ver == 8)
166
ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_TOPOLOGY;
167
/* This is needed for key->input_vertices */
168
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_UNCOMPILED_TCS;
169
170
/* Flag constants dirty for gl_PatchVerticesIn if needed. */
171
const struct shader_info *tcs_info =
172
crocus_get_shader_info(ice, MESA_SHADER_TESS_CTRL);
173
if (tcs_info &&
174
BITSET_TEST(tcs_info->system_values_read, SYSTEM_VALUE_VERTICES_IN)) {
175
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_CONSTANTS_TCS;
176
ice->state.shaders[MESA_SHADER_TESS_CTRL].sysvals_need_upload = true;
177
}
178
}
179
180
const unsigned cut_index = info->primitive_restart ? info->restart_index :
181
ice->state.cut_index;
182
if (ice->state.primitive_restart != info->primitive_restart ||
183
ice->state.cut_index != cut_index) {
184
if (screen->devinfo.verx10 >= 75)
185
ice->state.dirty |= CROCUS_DIRTY_GEN75_VF;
186
ice->state.primitive_restart = info->primitive_restart;
187
ice->state.cut_index = info->restart_index;
188
}
189
}
190
191
/**
192
* Update shader draw parameters, flagging VF packets as dirty if necessary.
193
*/
194
static void
195
crocus_update_draw_parameters(struct crocus_context *ice,
196
const struct pipe_draw_info *info,
197
unsigned drawid_offset,
198
const struct pipe_draw_indirect_info *indirect,
199
const struct pipe_draw_start_count_bias *draw)
200
{
201
bool changed = false;
202
203
if (ice->state.vs_uses_draw_params) {
204
struct crocus_state_ref *draw_params = &ice->draw.draw_params;
205
206
if (indirect && indirect->buffer) {
207
pipe_resource_reference(&draw_params->res, indirect->buffer);
208
draw_params->offset =
209
indirect->offset + (info->index_size ? 12 : 8);
210
211
changed = true;
212
ice->draw.params_valid = false;
213
} else {
214
int firstvertex = info->index_size ? draw->index_bias : draw->start;
215
216
if (!ice->draw.params_valid ||
217
ice->draw.params.firstvertex != firstvertex ||
218
ice->draw.params.baseinstance != info->start_instance) {
219
220
changed = true;
221
ice->draw.params.firstvertex = firstvertex;
222
ice->draw.params.baseinstance = info->start_instance;
223
ice->draw.params_valid = true;
224
225
u_upload_data(ice->ctx.stream_uploader, 0,
226
sizeof(ice->draw.params), 4, &ice->draw.params,
227
&draw_params->offset, &draw_params->res);
228
}
229
}
230
}
231
232
if (ice->state.vs_uses_derived_draw_params) {
233
struct crocus_state_ref *derived_params = &ice->draw.derived_draw_params;
234
int is_indexed_draw = info->index_size ? -1 : 0;
235
236
if (ice->draw.derived_params.drawid != drawid_offset ||
237
ice->draw.derived_params.is_indexed_draw != is_indexed_draw) {
238
239
changed = true;
240
ice->draw.derived_params.drawid = drawid_offset;
241
ice->draw.derived_params.is_indexed_draw = is_indexed_draw;
242
243
u_upload_data(ice->ctx.stream_uploader, 0,
244
sizeof(ice->draw.derived_params), 4,
245
&ice->draw.derived_params, &derived_params->offset,
246
&derived_params->res);
247
}
248
}
249
250
if (changed) {
251
struct crocus_screen *screen = (struct crocus_screen *)ice->ctx.screen;
252
ice->state.dirty |= CROCUS_DIRTY_VERTEX_BUFFERS |
253
CROCUS_DIRTY_VERTEX_ELEMENTS;
254
if (screen->devinfo.ver == 8)
255
ice->state.dirty |= CROCUS_DIRTY_GEN8_VF_SGVS;
256
}
257
}
258
259
static void
260
crocus_indirect_draw_vbo(struct crocus_context *ice,
261
const struct pipe_draw_info *dinfo,
262
unsigned drawid_offset,
263
const struct pipe_draw_indirect_info *dindirect,
264
const struct pipe_draw_start_count_bias *draws)
265
{
266
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
267
struct crocus_screen *screen = batch->screen;
268
struct pipe_draw_info info = *dinfo;
269
struct pipe_draw_indirect_info indirect = *dindirect;
270
const struct intel_device_info *devinfo = &batch->screen->devinfo;
271
272
if (devinfo->verx10 >= 75 && indirect.indirect_draw_count &&
273
ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
274
/* Upload MI_PREDICATE_RESULT to GPR15.*/
275
screen->vtbl.load_register_reg64(batch, CS_GPR(15), MI_PREDICATE_RESULT);
276
}
277
278
uint64_t orig_dirty = ice->state.dirty;
279
uint64_t orig_stage_dirty = ice->state.stage_dirty;
280
281
for (int i = 0; i < indirect.draw_count; i++) {
282
crocus_batch_maybe_flush(batch, 1500);
283
crocus_require_statebuffer_space(batch, 2400);
284
285
if (ice->state.vs_uses_draw_params ||
286
ice->state.vs_uses_derived_draw_params)
287
crocus_update_draw_parameters(ice, &info, drawid_offset + i, &indirect, draws);
288
289
screen->vtbl.upload_render_state(ice, batch, &info, drawid_offset + i, &indirect, draws);
290
291
ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_RENDER;
292
ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
293
294
indirect.offset += indirect.stride;
295
}
296
297
if (devinfo->verx10 >= 75 && indirect.indirect_draw_count &&
298
ice->state.predicate == CROCUS_PREDICATE_STATE_USE_BIT) {
299
/* Restore MI_PREDICATE_RESULT. */
300
screen->vtbl.load_register_reg64(batch, MI_PREDICATE_RESULT, CS_GPR(15));
301
}
302
303
/* Put this back for post-draw resolves, we'll clear it again after. */
304
ice->state.dirty = orig_dirty;
305
ice->state.stage_dirty = orig_stage_dirty;
306
}
307
308
static void
309
crocus_simple_draw_vbo(struct crocus_context *ice,
310
const struct pipe_draw_info *draw,
311
unsigned drawid_offset,
312
const struct pipe_draw_indirect_info *indirect,
313
const struct pipe_draw_start_count_bias *sc)
314
{
315
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
316
struct crocus_screen *screen = batch->screen;
317
318
crocus_batch_maybe_flush(batch, 1500);
319
crocus_require_statebuffer_space(batch, 2400);
320
321
if (ice->state.vs_uses_draw_params ||
322
ice->state.vs_uses_derived_draw_params)
323
crocus_update_draw_parameters(ice, draw, drawid_offset, indirect, sc);
324
325
screen->vtbl.upload_render_state(ice, batch, draw, drawid_offset, indirect, sc);
326
}
327
328
static void
329
crocus_draw_vbo_get_vertex_count(struct pipe_context *ctx,
330
const struct pipe_draw_info *info_in,
331
unsigned drawid_offset,
332
const struct pipe_draw_indirect_info *indirect)
333
{
334
struct crocus_screen *screen = (struct crocus_screen *)ctx->screen;
335
struct pipe_draw_info info = *info_in;
336
struct pipe_draw_start_count_bias draw;
337
338
uint32_t val = screen->vtbl.get_so_offset(indirect->count_from_stream_output);
339
340
draw.start = 0;
341
draw.count = val;
342
ctx->draw_vbo(ctx, &info, drawid_offset, NULL, &draw, 1);
343
}
344
345
/**
346
* The pipe->draw_vbo() driver hook. Performs a draw on the GPU.
347
*/
348
void
349
crocus_draw_vbo(struct pipe_context *ctx,
350
const struct pipe_draw_info *info,
351
unsigned drawid_offset,
352
const struct pipe_draw_indirect_info *indirect,
353
const struct pipe_draw_start_count_bias *draws,
354
unsigned num_draws)
355
{
356
if (num_draws > 1) {
357
util_draw_multi(ctx, info, drawid_offset, indirect, draws, num_draws);
358
return;
359
}
360
361
if (!indirect && (!draws[0].count || !info->instance_count))
362
return;
363
364
struct crocus_context *ice = (struct crocus_context *) ctx;
365
struct crocus_screen *screen = (struct crocus_screen*)ice->ctx.screen;
366
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
367
368
if (!crocus_check_conditional_render(ice))
369
return;
370
371
if (info->primitive_restart && !can_cut_index_handle_prim(ice, info)) {
372
util_draw_vbo_without_prim_restart(ctx, info, drawid_offset,
373
indirect, draws);
374
return;
375
}
376
377
if (screen->devinfo.verx10 < 75 &&
378
indirect && indirect->count_from_stream_output) {
379
crocus_draw_vbo_get_vertex_count(ctx, info, drawid_offset, indirect);
380
return;
381
}
382
383
/**
384
* The hardware is capable of removing dangling vertices on its own; however,
385
* prior to Gen6, we sometimes convert quads into trifans (and quad strips
386
* into tristrips), since pre-Gen6 hardware requires a GS to render quads.
387
* This function manually trims dangling vertices from a draw call involving
388
* quads so that those dangling vertices won't get drawn when we convert to
389
* trifans/tristrips.
390
*/
391
if (screen->devinfo.ver < 6) {
392
if (info->mode == PIPE_PRIM_QUADS || info->mode == PIPE_PRIM_QUAD_STRIP) {
393
bool trim = u_trim_pipe_prim(info->mode, (unsigned *)&draws[0].count);
394
if (!trim)
395
return;
396
}
397
}
398
399
/* We can't safely re-emit 3DSTATE_SO_BUFFERS because it may zero the
400
* write offsets, changing the behavior.
401
*/
402
if (unlikely(INTEL_DEBUG & DEBUG_REEMIT)) {
403
ice->state.dirty |= CROCUS_ALL_DIRTY_FOR_RENDER & ~CROCUS_DIRTY_GEN7_SO_BUFFERS;
404
ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
405
}
406
407
/* Emit Sandybridge workaround flushes on every primitive, for safety. */
408
if (screen->devinfo.ver == 6)
409
crocus_emit_post_sync_nonzero_flush(batch);
410
411
crocus_update_draw_info(ice, info, draws);
412
413
if (!crocus_update_compiled_shaders(ice))
414
return;
415
416
if (ice->state.dirty & CROCUS_DIRTY_RENDER_RESOLVES_AND_FLUSHES) {
417
bool draw_aux_buffer_disabled[BRW_MAX_DRAW_BUFFERS] = { };
418
for (gl_shader_stage stage = 0; stage < MESA_SHADER_COMPUTE; stage++) {
419
if (ice->shaders.prog[stage])
420
crocus_predraw_resolve_inputs(ice, batch, draw_aux_buffer_disabled,
421
stage, true);
422
}
423
crocus_predraw_resolve_framebuffer(ice, batch, draw_aux_buffer_disabled);
424
}
425
426
crocus_handle_always_flush_cache(batch);
427
428
if (indirect && indirect->buffer)
429
crocus_indirect_draw_vbo(ice, info, drawid_offset, indirect, draws);
430
else
431
crocus_simple_draw_vbo(ice, info, drawid_offset, indirect, draws);
432
433
crocus_handle_always_flush_cache(batch);
434
435
crocus_postdraw_update_resolve_tracking(ice, batch);
436
437
ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_RENDER;
438
ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_RENDER;
439
}
440
441
static void
442
crocus_update_grid_size_resource(struct crocus_context *ice,
443
const struct pipe_grid_info *grid)
444
{
445
struct crocus_state_ref *grid_ref = &ice->state.grid_size;
446
const struct crocus_compiled_shader *shader = ice->shaders.prog[MESA_SHADER_COMPUTE];
447
bool grid_needs_surface = shader->bt.used_mask[CROCUS_SURFACE_GROUP_CS_WORK_GROUPS];
448
449
if (grid->indirect) {
450
pipe_resource_reference(&grid_ref->res, grid->indirect);
451
grid_ref->offset = grid->indirect_offset;
452
453
/* Zero out the grid size so that the next non-indirect grid launch will
454
* re-upload it properly.
455
*/
456
memset(ice->state.last_grid, 0, sizeof(ice->state.last_grid));
457
} else if (memcmp(ice->state.last_grid, grid->grid, sizeof(grid->grid)) != 0) {
458
memcpy(ice->state.last_grid, grid->grid, sizeof(grid->grid));
459
u_upload_data(ice->ctx.const_uploader, 0, sizeof(grid->grid), 4,
460
grid->grid, &grid_ref->offset, &grid_ref->res);
461
}
462
463
/* Skip surface upload if we don't need it or we already have one */
464
if (!grid_needs_surface)
465
return;
466
467
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_BINDINGS_CS;
468
}
469
470
471
void
472
crocus_launch_grid(struct pipe_context *ctx, const struct pipe_grid_info *grid)
473
{
474
struct crocus_context *ice = (struct crocus_context *) ctx;
475
struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_COMPUTE];
476
struct crocus_screen *screen = batch->screen;
477
478
if (!crocus_check_conditional_render(ice))
479
return;
480
481
if (unlikely(INTEL_DEBUG & DEBUG_REEMIT)) {
482
ice->state.dirty |= CROCUS_ALL_DIRTY_FOR_COMPUTE;
483
ice->state.stage_dirty |= CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE;
484
}
485
486
/* We can't do resolves on the compute engine, so awkwardly, we have to
487
* do them on the render batch...
488
*/
489
if (ice->state.dirty & CROCUS_DIRTY_COMPUTE_RESOLVES_AND_FLUSHES) {
490
crocus_predraw_resolve_inputs(ice, &ice->batches[CROCUS_BATCH_RENDER], NULL,
491
MESA_SHADER_COMPUTE, false);
492
}
493
494
crocus_batch_maybe_flush(batch, 1500);
495
crocus_require_statebuffer_space(batch, 2500);
496
crocus_update_compiled_compute_shader(ice);
497
498
if (memcmp(ice->state.last_block, grid->block, sizeof(grid->block)) != 0) {
499
memcpy(ice->state.last_block, grid->block, sizeof(grid->block));
500
ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_CONSTANTS_CS;
501
ice->state.shaders[MESA_SHADER_COMPUTE].sysvals_need_upload = true;
502
}
503
504
crocus_update_grid_size_resource(ice, grid);
505
506
if (ice->state.compute_predicate) {
507
screen->vtbl.emit_compute_predicate(batch);
508
ice->state.compute_predicate = NULL;
509
}
510
511
crocus_handle_always_flush_cache(batch);
512
513
screen->vtbl.upload_compute_state(ice, batch, grid);
514
515
crocus_handle_always_flush_cache(batch);
516
517
ice->state.dirty &= ~CROCUS_ALL_DIRTY_FOR_COMPUTE;
518
ice->state.stage_dirty &= ~CROCUS_ALL_STAGE_DIRTY_FOR_COMPUTE;
519
520
/* Note: since compute shaders can't access the framebuffer, there's
521
* no need to call crocus_postdraw_update_resolve_tracking.
522
*/
523
}
524
525