2
* Copyright © 2014-2015 Broadcom
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 (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26
* Functions for submitting VC4 render jobs to the kernel.
30
#include "vc4_cl_dump.h"
31
#include "vc4_context.h"
32
#include "util/hash_table.h"
35
vc4_job_free(struct vc4_context *vc4, struct vc4_job *job)
37
struct vc4_bo **referenced_bos = job->bo_pointers.base;
38
for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) {
39
vc4_bo_unreference(&referenced_bos[i]);
42
_mesa_hash_table_remove_key(vc4->jobs, &job->key);
44
if (job->color_write) {
45
_mesa_hash_table_remove_key(vc4->write_jobs,
46
job->color_write->texture);
47
pipe_surface_reference(&job->color_write, NULL);
49
if (job->msaa_color_write) {
50
_mesa_hash_table_remove_key(vc4->write_jobs,
51
job->msaa_color_write->texture);
52
pipe_surface_reference(&job->msaa_color_write, NULL);
55
_mesa_hash_table_remove_key(vc4->write_jobs,
56
job->zs_write->texture);
57
pipe_surface_reference(&job->zs_write, NULL);
59
if (job->msaa_zs_write) {
60
_mesa_hash_table_remove_key(vc4->write_jobs,
61
job->msaa_zs_write->texture);
62
pipe_surface_reference(&job->msaa_zs_write, NULL);
65
pipe_surface_reference(&job->color_read, NULL);
66
pipe_surface_reference(&job->zs_read, NULL);
74
static struct vc4_job *
75
vc4_job_create(struct vc4_context *vc4)
77
struct vc4_job *job = rzalloc(vc4, struct vc4_job);
79
vc4_init_cl(job, &job->bcl);
80
vc4_init_cl(job, &job->shader_rec);
81
vc4_init_cl(job, &job->uniforms);
82
vc4_init_cl(job, &job->bo_handles);
83
vc4_init_cl(job, &job->bo_pointers);
90
job->last_gem_handle_hindex = ~0;
93
job->perfmon = vc4->perfmon;
99
vc4_flush_jobs_writing_resource(struct vc4_context *vc4,
100
struct pipe_resource *prsc)
102
struct hash_entry *entry = _mesa_hash_table_search(vc4->write_jobs,
105
struct vc4_job *job = entry->data;
106
vc4_job_submit(vc4, job);
111
vc4_flush_jobs_reading_resource(struct vc4_context *vc4,
112
struct pipe_resource *prsc)
114
struct vc4_resource *rsc = vc4_resource(prsc);
116
vc4_flush_jobs_writing_resource(vc4, prsc);
118
hash_table_foreach(vc4->jobs, entry) {
119
struct vc4_job *job = entry->data;
121
struct vc4_bo **referenced_bos = job->bo_pointers.base;
123
for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) {
124
if (referenced_bos[i] == rsc->bo) {
130
vc4_job_submit(vc4, job);
134
/* Also check for the Z/color buffers, since the references to
135
* those are only added immediately before submit.
137
if (job->color_read && !(job->cleared & PIPE_CLEAR_COLOR)) {
138
struct vc4_resource *ctex =
139
vc4_resource(job->color_read->texture);
140
if (ctex->bo == rsc->bo) {
141
vc4_job_submit(vc4, job);
146
if (job->zs_read && !(job->cleared &
147
(PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
148
struct vc4_resource *ztex =
149
vc4_resource(job->zs_read->texture);
150
if (ztex->bo == rsc->bo) {
151
vc4_job_submit(vc4, job);
159
* Returns a vc4_job struture for tracking V3D rendering to a particular FBO.
161
* If we've already started rendering to this FBO, then return old same job,
162
* otherwise make a new one. If we're beginning rendering to an FBO, make
163
* sure that any previous reads of the FBO (or writes to its color/Z surfaces)
167
vc4_get_job(struct vc4_context *vc4,
168
struct pipe_surface *cbuf, struct pipe_surface *zsbuf)
170
/* Return the existing job for this FBO if we have one */
171
struct vc4_job_key local_key = {.cbuf = cbuf, .zsbuf = zsbuf};
172
struct hash_entry *entry = _mesa_hash_table_search(vc4->jobs,
177
/* Creating a new job. Make sure that any previous jobs reading or
178
* writing these buffers are flushed.
181
vc4_flush_jobs_reading_resource(vc4, cbuf->texture);
183
vc4_flush_jobs_reading_resource(vc4, zsbuf->texture);
185
struct vc4_job *job = vc4_job_create(vc4);
188
if (cbuf->texture->nr_samples > 1) {
190
pipe_surface_reference(&job->msaa_color_write, cbuf);
192
pipe_surface_reference(&job->color_write, cbuf);
197
if (zsbuf->texture->nr_samples > 1) {
199
pipe_surface_reference(&job->msaa_zs_write, zsbuf);
201
pipe_surface_reference(&job->zs_write, zsbuf);
206
job->tile_width = 32;
207
job->tile_height = 32;
209
job->tile_width = 64;
210
job->tile_height = 64;
214
_mesa_hash_table_insert(vc4->write_jobs, cbuf->texture, job);
216
_mesa_hash_table_insert(vc4->write_jobs, zsbuf->texture, job);
218
job->key.cbuf = cbuf;
219
job->key.zsbuf = zsbuf;
220
_mesa_hash_table_insert(vc4->jobs, &job->key, job);
226
vc4_get_job_for_fbo(struct vc4_context *vc4)
231
struct pipe_surface *cbuf = vc4->framebuffer.cbufs[0];
232
struct pipe_surface *zsbuf = vc4->framebuffer.zsbuf;
233
struct vc4_job *job = vc4_get_job(vc4, cbuf, zsbuf);
235
/* The dirty flags are tracking what's been updated while vc4->job has
236
* been bound, so set them all to ~0 when switching between jobs. We
237
* also need to reset all state at the start of rendering.
241
/* Set up the read surfaces in the job. If they aren't actually
242
* getting read (due to a clear starting the frame), job->cleared will
245
pipe_surface_reference(&job->color_read, cbuf);
246
pipe_surface_reference(&job->zs_read, zsbuf);
248
/* If we're binding to uninitialized buffers, no need to load their
249
* contents before drawing.
252
struct vc4_resource *rsc = vc4_resource(cbuf->texture);
254
job->cleared |= PIPE_CLEAR_COLOR0;
258
struct vc4_resource *rsc = vc4_resource(zsbuf->texture);
260
job->cleared |= PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL;
263
job->draw_tiles_x = DIV_ROUND_UP(vc4->framebuffer.width,
265
job->draw_tiles_y = DIV_ROUND_UP(vc4->framebuffer.height,
268
/* Initialize the job with the raster order flags -- each draw will
269
* check that we haven't changed the flags, since that requires a
273
job->flags = vc4->rasterizer->tile_raster_order_flags;
281
vc4_submit_setup_rcl_surface(struct vc4_job *job,
282
struct drm_vc4_submit_rcl_surface *submit_surf,
283
struct pipe_surface *psurf,
284
bool is_depth, bool is_write)
286
struct vc4_surface *surf = vc4_surface(psurf);
291
struct vc4_resource *rsc = vc4_resource(psurf->texture);
292
submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
293
submit_surf->offset = surf->offset;
295
if (psurf->texture->nr_samples <= 1) {
298
VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_ZS,
299
VC4_LOADSTORE_TILE_BUFFER_BUFFER);
303
VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_COLOR,
304
VC4_LOADSTORE_TILE_BUFFER_BUFFER) |
305
VC4_SET_FIELD(vc4_rt_format_is_565(psurf->format) ?
306
VC4_LOADSTORE_TILE_BUFFER_BGR565 :
307
VC4_LOADSTORE_TILE_BUFFER_RGBA8888,
308
VC4_LOADSTORE_TILE_BUFFER_FORMAT);
311
VC4_SET_FIELD(surf->tiling,
312
VC4_LOADSTORE_TILE_BUFFER_TILING);
315
submit_surf->flags |= VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES;
323
vc4_submit_setup_rcl_render_config_surface(struct vc4_job *job,
324
struct drm_vc4_submit_rcl_surface *submit_surf,
325
struct pipe_surface *psurf)
327
struct vc4_surface *surf = vc4_surface(psurf);
332
struct vc4_resource *rsc = vc4_resource(psurf->texture);
333
submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
334
submit_surf->offset = surf->offset;
336
if (psurf->texture->nr_samples <= 1) {
338
VC4_SET_FIELD(vc4_rt_format_is_565(surf->base.format) ?
339
VC4_RENDER_CONFIG_FORMAT_BGR565 :
340
VC4_RENDER_CONFIG_FORMAT_RGBA8888,
341
VC4_RENDER_CONFIG_FORMAT) |
342
VC4_SET_FIELD(surf->tiling,
343
VC4_RENDER_CONFIG_MEMORY_FORMAT);
350
vc4_submit_setup_rcl_msaa_surface(struct vc4_job *job,
351
struct drm_vc4_submit_rcl_surface *submit_surf,
352
struct pipe_surface *psurf)
354
struct vc4_surface *surf = vc4_surface(psurf);
359
struct vc4_resource *rsc = vc4_resource(psurf->texture);
360
submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
361
submit_surf->offset = surf->offset;
362
submit_surf->bits = 0;
367
* Submits the job to the kernel and then reinitializes it.
370
vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job)
372
if (!job->needs_flush)
375
/* The RCL setup would choke if the draw bounds cause no drawing, so
376
* just drop the drawing if that's the case.
378
if (job->draw_max_x <= job->draw_min_x ||
379
job->draw_max_y <= job->draw_min_y) {
383
if (vc4_debug & VC4_DEBUG_CL) {
384
fprintf(stderr, "BCL:\n");
385
vc4_dump_cl(job->bcl.base, cl_offset(&job->bcl), false);
388
if (cl_offset(&job->bcl) > 0) {
389
/* Increment the semaphore indicating that binning is done and
390
* unblocking the render thread. Note that this doesn't act
391
* until the FLUSH completes.
393
cl_ensure_space(&job->bcl, 8);
394
cl_emit(&job->bcl, INCREMENT_SEMAPHORE, incr);
395
/* The FLUSH caps all of our bin lists with a
398
cl_emit(&job->bcl, FLUSH, flush);
400
struct drm_vc4_submit_cl submit = {
401
.color_read.hindex = ~0,
402
.zs_read.hindex = ~0,
403
.color_write.hindex = ~0,
404
.msaa_color_write.hindex = ~0,
405
.zs_write.hindex = ~0,
406
.msaa_zs_write.hindex = ~0,
409
cl_ensure_space(&job->bo_handles, 6 * sizeof(uint32_t));
410
cl_ensure_space(&job->bo_pointers, 6 * sizeof(struct vc4_bo *));
412
if (job->resolve & PIPE_CLEAR_COLOR) {
413
if (!(job->cleared & PIPE_CLEAR_COLOR)) {
414
vc4_submit_setup_rcl_surface(job, &submit.color_read,
418
vc4_submit_setup_rcl_render_config_surface(job,
421
vc4_submit_setup_rcl_msaa_surface(job,
422
&submit.msaa_color_write,
423
job->msaa_color_write);
425
if (job->resolve & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) {
426
if (!(job->cleared & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
427
vc4_submit_setup_rcl_surface(job, &submit.zs_read,
428
job->zs_read, true, false);
430
vc4_submit_setup_rcl_surface(job, &submit.zs_write,
431
job->zs_write, true, true);
432
vc4_submit_setup_rcl_msaa_surface(job, &submit.msaa_zs_write,
437
/* This bit controls how many pixels the general
438
* (i.e. subsampled) loads/stores are iterating over
439
* (multisample loads replicate out to the other samples).
441
submit.color_write.bits |= VC4_RENDER_CONFIG_MS_MODE_4X;
442
/* Controls whether color_write's
443
* VC4_PACKET_STORE_MS_TILE_BUFFER does 4x decimation
445
submit.color_write.bits |= VC4_RENDER_CONFIG_DECIMATE_MODE_4X;
448
submit.bo_handles = (uintptr_t)job->bo_handles.base;
449
submit.bo_handle_count = cl_offset(&job->bo_handles) / 4;
450
submit.bin_cl = (uintptr_t)job->bcl.base;
451
submit.bin_cl_size = cl_offset(&job->bcl);
452
submit.shader_rec = (uintptr_t)job->shader_rec.base;
453
submit.shader_rec_size = cl_offset(&job->shader_rec);
454
submit.shader_rec_count = job->shader_rec_count;
455
submit.uniforms = (uintptr_t)job->uniforms.base;
456
submit.uniforms_size = cl_offset(&job->uniforms);
458
submit.perfmonid = job->perfmon->id;
460
assert(job->draw_min_x != ~0 && job->draw_min_y != ~0);
461
submit.min_x_tile = job->draw_min_x / job->tile_width;
462
submit.min_y_tile = job->draw_min_y / job->tile_height;
463
submit.max_x_tile = (job->draw_max_x - 1) / job->tile_width;
464
submit.max_y_tile = (job->draw_max_y - 1) / job->tile_height;
465
submit.width = job->draw_width;
466
submit.height = job->draw_height;
468
submit.flags |= VC4_SUBMIT_CL_USE_CLEAR_COLOR;
469
submit.clear_color[0] = job->clear_color[0];
470
submit.clear_color[1] = job->clear_color[1];
471
submit.clear_z = job->clear_depth;
472
submit.clear_s = job->clear_stencil;
474
submit.flags |= job->flags;
476
if (vc4->screen->has_syncobj) {
477
submit.out_sync = vc4->job_syncobj;
479
if (vc4->in_fence_fd >= 0) {
480
/* This replaces the fence in the syncobj. */
481
drmSyncobjImportSyncFile(vc4->fd, vc4->in_syncobj,
483
submit.in_sync = vc4->in_syncobj;
484
close(vc4->in_fence_fd);
485
vc4->in_fence_fd = -1;
489
if (!(vc4_debug & VC4_DEBUG_NORAST)) {
492
ret = vc4_ioctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit);
493
static bool warned = false;
494
if (ret && !warned) {
495
fprintf(stderr, "Draw call returned %s. "
496
"Expect corruption.\n", strerror(errno));
499
vc4->last_emit_seqno = submit.seqno;
501
job->perfmon->last_seqno = submit.seqno;
505
if (vc4->last_emit_seqno - vc4->screen->finished_seqno > 5) {
506
if (!vc4_wait_seqno(vc4->screen,
507
vc4->last_emit_seqno - 5,
508
PIPE_TIMEOUT_INFINITE,
510
fprintf(stderr, "Job throttling failed\n");
514
if (vc4_debug & VC4_DEBUG_ALWAYS_SYNC) {
515
if (!vc4_wait_seqno(vc4->screen, vc4->last_emit_seqno,
516
PIPE_TIMEOUT_INFINITE, "sync")) {
517
fprintf(stderr, "Wait failed.\n");
523
vc4_job_free(vc4, job);
527
vc4_job_compare(const void *a, const void *b)
529
return memcmp(a, b, sizeof(struct vc4_job_key)) == 0;
533
vc4_job_hash(const void *key)
535
return _mesa_hash_data(key, sizeof(struct vc4_job_key));
539
vc4_job_init(struct vc4_context *vc4)
541
vc4->jobs = _mesa_hash_table_create(vc4,
544
vc4->write_jobs = _mesa_hash_table_create(vc4,
546
_mesa_key_pointer_equal);
548
if (vc4->screen->has_syncobj) {
549
/* Create the syncobj as signaled since with no job executed
550
* there is nothing to wait on.
552
int ret = drmSyncobjCreate(vc4->fd,
553
DRM_SYNCOBJ_CREATE_SIGNALED,
556
/* If the screen indicated syncobj support, we should
557
* be able to create a signaled syncobj.
558
* At this point it is too late to pretend the screen
559
* has no syncobj support.