X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fdrivers%2Fvc4%2Fvc4_job.c;h=30dfebdb8c21a5c72d7b0e3408f54bff676a7418;hb=1c8bcad81a7ce106b37f1ee4a75b817651d6545e;hp=cb20853fa497abbac0b8b4fd06a4dfbed8dce8a6;hpb=f473348468ae1c68e7ef8eaf29f2cc51d17fbec7;p=mesa.git diff --git a/src/gallium/drivers/vc4/vc4_job.c b/src/gallium/drivers/vc4/vc4_job.c index cb20853fa49..30dfebdb8c2 100644 --- a/src/gallium/drivers/vc4/vc4_job.c +++ b/src/gallium/drivers/vc4/vc4_job.c @@ -27,50 +27,254 @@ */ #include +#include "vc4_cl_dump.h" #include "vc4_context.h" +#include "util/hash_table.h" -void -vc4_job_init(struct vc4_job *job) +static void +vc4_job_free(struct vc4_context *vc4, struct vc4_job *job) { + struct vc4_bo **referenced_bos = job->bo_pointers.base; + for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) { + vc4_bo_unreference(&referenced_bos[i]); + } + + _mesa_hash_table_remove_key(vc4->jobs, &job->key); + + if (job->color_write) { + _mesa_hash_table_remove_key(vc4->write_jobs, + job->color_write->texture); + pipe_surface_reference(&job->color_write, NULL); + } + if (job->msaa_color_write) { + _mesa_hash_table_remove_key(vc4->write_jobs, + job->msaa_color_write->texture); + pipe_surface_reference(&job->msaa_color_write, NULL); + } + if (job->zs_write) { + _mesa_hash_table_remove_key(vc4->write_jobs, + job->zs_write->texture); + pipe_surface_reference(&job->zs_write, NULL); + } + if (job->msaa_zs_write) { + _mesa_hash_table_remove_key(vc4->write_jobs, + job->msaa_zs_write->texture); + pipe_surface_reference(&job->msaa_zs_write, NULL); + } + + pipe_surface_reference(&job->color_read, NULL); + pipe_surface_reference(&job->zs_read, NULL); + + if (vc4->job == job) + vc4->job = NULL; + + ralloc_free(job); +} + +static struct vc4_job * +vc4_job_create(struct vc4_context *vc4) +{ + struct vc4_job *job = rzalloc(vc4, struct vc4_job); + vc4_init_cl(job, &job->bcl); vc4_init_cl(job, &job->shader_rec); vc4_init_cl(job, &job->uniforms); vc4_init_cl(job, &job->bo_handles); vc4_init_cl(job, &job->bo_pointers); - vc4_job_reset(job); + + job->draw_min_x = ~0; + job->draw_min_y = ~0; + job->draw_max_x = 0; + job->draw_max_y = 0; + + job->last_gem_handle_hindex = ~0; + + if (vc4->perfmon) + job->perfmon = vc4->perfmon; + + return job; } void -vc4_job_reset(struct vc4_job *job) +vc4_flush_jobs_writing_resource(struct vc4_context *vc4, + struct pipe_resource *prsc) { - struct vc4_bo **referenced_bos = job->bo_pointers.base; - for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) { - vc4_bo_unreference(&referenced_bos[i]); + struct hash_entry *entry = _mesa_hash_table_search(vc4->write_jobs, + prsc); + if (entry) { + struct vc4_job *job = entry->data; + vc4_job_submit(vc4, job); } - vc4_reset_cl(&job->bcl); - vc4_reset_cl(&job->shader_rec); - vc4_reset_cl(&job->uniforms); - vc4_reset_cl(&job->bo_handles); - vc4_reset_cl(&job->bo_pointers); - job->shader_rec_count = 0; +} - job->needs_flush = false; - job->draw_calls_queued = 0; +void +vc4_flush_jobs_reading_resource(struct vc4_context *vc4, + struct pipe_resource *prsc) +{ + struct vc4_resource *rsc = vc4_resource(prsc); - job->resolve = 0; - job->cleared = 0; + vc4_flush_jobs_writing_resource(vc4, prsc); - job->draw_min_x = ~0; - job->draw_min_y = ~0; - job->draw_max_x = 0; - job->draw_max_y = 0; + hash_table_foreach(vc4->jobs, entry) { + struct vc4_job *job = entry->data; - pipe_surface_reference(&job->color_write, NULL); - pipe_surface_reference(&job->color_read, NULL); - pipe_surface_reference(&job->msaa_color_write, NULL); - pipe_surface_reference(&job->zs_write, NULL); - pipe_surface_reference(&job->zs_read, NULL); - pipe_surface_reference(&job->msaa_zs_write, NULL); + struct vc4_bo **referenced_bos = job->bo_pointers.base; + bool found = false; + for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) { + if (referenced_bos[i] == rsc->bo) { + found = true; + break; + } + } + if (found) { + vc4_job_submit(vc4, job); + continue; + } + + /* Also check for the Z/color buffers, since the references to + * those are only added immediately before submit. + */ + if (job->color_read && !(job->cleared & PIPE_CLEAR_COLOR)) { + struct vc4_resource *ctex = + vc4_resource(job->color_read->texture); + if (ctex->bo == rsc->bo) { + vc4_job_submit(vc4, job); + continue; + } + } + + if (job->zs_read && !(job->cleared & + (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) { + struct vc4_resource *ztex = + vc4_resource(job->zs_read->texture); + if (ztex->bo == rsc->bo) { + vc4_job_submit(vc4, job); + continue; + } + } + } +} + +/** + * Returns a vc4_job struture for tracking V3D rendering to a particular FBO. + * + * If we've already started rendering to this FBO, then return old same job, + * otherwise make a new one. If we're beginning rendering to an FBO, make + * sure that any previous reads of the FBO (or writes to its color/Z surfaces) + * have been flushed. + */ +struct vc4_job * +vc4_get_job(struct vc4_context *vc4, + struct pipe_surface *cbuf, struct pipe_surface *zsbuf) +{ + /* Return the existing job for this FBO if we have one */ + struct vc4_job_key local_key = {.cbuf = cbuf, .zsbuf = zsbuf}; + struct hash_entry *entry = _mesa_hash_table_search(vc4->jobs, + &local_key); + if (entry) + return entry->data; + + /* Creating a new job. Make sure that any previous jobs reading or + * writing these buffers are flushed. + */ + if (cbuf) + vc4_flush_jobs_reading_resource(vc4, cbuf->texture); + if (zsbuf) + vc4_flush_jobs_reading_resource(vc4, zsbuf->texture); + + struct vc4_job *job = vc4_job_create(vc4); + + if (cbuf) { + if (cbuf->texture->nr_samples > 1) { + job->msaa = true; + pipe_surface_reference(&job->msaa_color_write, cbuf); + } else { + pipe_surface_reference(&job->color_write, cbuf); + } + } + + if (zsbuf) { + if (zsbuf->texture->nr_samples > 1) { + job->msaa = true; + pipe_surface_reference(&job->msaa_zs_write, zsbuf); + } else { + pipe_surface_reference(&job->zs_write, zsbuf); + } + } + + if (job->msaa) { + job->tile_width = 32; + job->tile_height = 32; + } else { + job->tile_width = 64; + job->tile_height = 64; + } + + if (cbuf) + _mesa_hash_table_insert(vc4->write_jobs, cbuf->texture, job); + if (zsbuf) + _mesa_hash_table_insert(vc4->write_jobs, zsbuf->texture, job); + + job->key.cbuf = cbuf; + job->key.zsbuf = zsbuf; + _mesa_hash_table_insert(vc4->jobs, &job->key, job); + + return job; +} + +struct vc4_job * +vc4_get_job_for_fbo(struct vc4_context *vc4) +{ + if (vc4->job) + return vc4->job; + + struct pipe_surface *cbuf = vc4->framebuffer.cbufs[0]; + struct pipe_surface *zsbuf = vc4->framebuffer.zsbuf; + struct vc4_job *job = vc4_get_job(vc4, cbuf, zsbuf); + + /* The dirty flags are tracking what's been updated while vc4->job has + * been bound, so set them all to ~0 when switching between jobs. We + * also need to reset all state at the start of rendering. + */ + vc4->dirty = ~0; + + /* Set up the read surfaces in the job. If they aren't actually + * getting read (due to a clear starting the frame), job->cleared will + * mask out the read. + */ + pipe_surface_reference(&job->color_read, cbuf); + pipe_surface_reference(&job->zs_read, zsbuf); + + /* If we're binding to uninitialized buffers, no need to load their + * contents before drawing. + */ + if (cbuf) { + struct vc4_resource *rsc = vc4_resource(cbuf->texture); + if (!rsc->writes) + job->cleared |= PIPE_CLEAR_COLOR0; + } + + if (zsbuf) { + struct vc4_resource *rsc = vc4_resource(zsbuf->texture); + if (!rsc->writes) + job->cleared |= PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL; + } + + job->draw_tiles_x = DIV_ROUND_UP(vc4->framebuffer.width, + job->tile_width); + job->draw_tiles_y = DIV_ROUND_UP(vc4->framebuffer.height, + job->tile_height); + + /* Initialize the job with the raster order flags -- each draw will + * check that we haven't changed the flags, since that requires a + * flush. + */ + if (vc4->rasterizer) + job->flags = vc4->rasterizer->tile_raster_order_flags; + + vc4->job = job; + + return job; } static void @@ -166,15 +370,14 @@ void vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) { if (!job->needs_flush) - return; + goto done; /* The RCL setup would choke if the draw bounds cause no drawing, so * just drop the drawing if that's the case. */ if (job->draw_max_x <= job->draw_min_x || job->draw_max_y <= job->draw_min_y) { - vc4_job_reset(job); - return; + goto done; } if (vc4_debug & VC4_DEBUG_CL) { @@ -188,13 +391,11 @@ vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) * until the FLUSH completes. */ cl_ensure_space(&job->bcl, 8); - struct vc4_cl_out *bcl = cl_start(&job->bcl); - cl_u8(&bcl, VC4_PACKET_INCREMENT_SEMAPHORE); + cl_emit(&job->bcl, INCREMENT_SEMAPHORE, incr); /* The FLUSH caps all of our bin lists with a * VC4_PACKET_RETURN. */ - cl_u8(&bcl, VC4_PACKET_FLUSH); - cl_end(&job->bcl, bcl); + cl_emit(&job->bcl, FLUSH, flush); } struct drm_vc4_submit_cl submit = { .color_read.hindex = ~0, @@ -253,6 +454,8 @@ vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) submit.shader_rec_count = job->shader_rec_count; submit.uniforms = (uintptr_t)job->uniforms.base; submit.uniforms_size = cl_offset(&job->uniforms); + if (job->perfmon) + submit.perfmonid = job->perfmon->id; assert(job->draw_min_x != ~0 && job->draw_min_y != ~0); submit.min_x_tile = job->draw_min_x / job->tile_width; @@ -268,15 +471,25 @@ vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) submit.clear_z = job->clear_depth; submit.clear_s = job->clear_stencil; } + submit.flags |= job->flags; + + if (vc4->screen->has_syncobj) { + submit.out_sync = vc4->job_syncobj; + + if (vc4->in_fence_fd >= 0) { + /* This replaces the fence in the syncobj. */ + drmSyncobjImportSyncFile(vc4->fd, vc4->in_syncobj, + vc4->in_fence_fd); + submit.in_sync = vc4->in_syncobj; + close(vc4->in_fence_fd); + vc4->in_fence_fd = -1; + } + } if (!(vc4_debug & VC4_DEBUG_NORAST)) { int ret; -#ifndef USE_VC4_SIMULATOR - ret = drmIoctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit); -#else - ret = vc4_simulator_flush(vc4, &submit); -#endif + ret = vc4_ioctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit); static bool warned = false; if (ret && !warned) { fprintf(stderr, "Draw call returned %s. " @@ -284,6 +497,8 @@ vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) warned = true; } else if (!ret) { vc4->last_emit_seqno = submit.seqno; + if (job->perfmon) + job->perfmon->last_seqno = submit.seqno; } } @@ -304,5 +519,49 @@ vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) } } - vc4_job_reset(vc4->job); +done: + vc4_job_free(vc4, job); } + +static bool +vc4_job_compare(const void *a, const void *b) +{ + return memcmp(a, b, sizeof(struct vc4_job_key)) == 0; +} + +static uint32_t +vc4_job_hash(const void *key) +{ + return _mesa_hash_data(key, sizeof(struct vc4_job_key)); +} + +int +vc4_job_init(struct vc4_context *vc4) +{ + vc4->jobs = _mesa_hash_table_create(vc4, + vc4_job_hash, + vc4_job_compare); + vc4->write_jobs = _mesa_hash_table_create(vc4, + _mesa_hash_pointer, + _mesa_key_pointer_equal); + + if (vc4->screen->has_syncobj) { + /* Create the syncobj as signaled since with no job executed + * there is nothing to wait on. + */ + int ret = drmSyncobjCreate(vc4->fd, + DRM_SYNCOBJ_CREATE_SIGNALED, + &vc4->job_syncobj); + if (ret) { + /* If the screen indicated syncobj support, we should + * be able to create a signaled syncobj. + * At this point it is too late to pretend the screen + * has no syncobj support. + */ + return ret; + } + } + + return 0; +} +