diff options
Diffstat (limited to 'src/gallium/drivers/vc4/vc4_job.c')
-rw-r--r-- | src/gallium/drivers/vc4/vc4_job.c | 276 |
1 files changed, 245 insertions, 31 deletions
diff --git a/src/gallium/drivers/vc4/vc4_job.c b/src/gallium/drivers/vc4/vc4_job.c index cb20853fa49..d39472ef131 100644 --- a/src/gallium/drivers/vc4/vc4_job.c +++ b/src/gallium/drivers/vc4/vc4_job.c @@ -28,49 +28,239 @@ #include <xf86drm.h> #include "vc4_context.h" +#include "util/hash_table.h" -void -vc4_job_init(struct vc4_job *job) +static void +remove_from_ht(struct hash_table *ht, void *key) { - 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); + struct hash_entry *entry = _mesa_hash_table_search(ht, key); + _mesa_hash_table_remove(ht, entry); } -void -vc4_job_reset(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]); } - 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; + remove_from_ht(vc4->jobs, &job->key); - job->resolve = 0; - job->cleared = 0; + if (job->color_write) { + remove_from_ht(vc4->write_jobs, job->color_write->texture); + pipe_surface_reference(&job->color_write, NULL); + } + if (job->msaa_color_write) { + remove_from_ht(vc4->write_jobs, job->msaa_color_write->texture); + pipe_surface_reference(&job->msaa_color_write, NULL); + } + if (job->zs_write) { + remove_from_ht(vc4->write_jobs, job->zs_write->texture); + pipe_surface_reference(&job->zs_write, NULL); + } + if (job->msaa_zs_write) { + remove_from_ht(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); job->draw_min_x = ~0; job->draw_min_y = ~0; job->draw_max_x = 0; job->draw_max_y = 0; - 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); + return job; +} + +void +vc4_flush_jobs_writing_resource(struct vc4_context *vc4, + struct pipe_resource *prsc) +{ + 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); + } +} + +void +vc4_flush_jobs_reading_resource(struct vc4_context *vc4, + struct pipe_resource *prsc) +{ + struct vc4_resource *rsc = vc4_resource(prsc); + + vc4_flush_jobs_writing_resource(vc4, prsc); + + struct hash_entry *entry; + hash_table_foreach(vc4->jobs, entry) { + struct vc4_job *job = entry->data; + + struct vc4_bo **referenced_bos = job->bo_pointers.base; + for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) { + if (referenced_bos[i] == rsc->bo) { + 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); + + vc4->job = job; + + return job; } static void @@ -166,15 +356,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) { @@ -275,7 +464,7 @@ vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job) #ifndef USE_VC4_SIMULATOR ret = drmIoctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit); #else - ret = vc4_simulator_flush(vc4, &submit); + ret = vc4_simulator_flush(vc4, &submit, job); #endif static bool warned = false; if (ret && !warned) { @@ -304,5 +493,30 @@ 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)); +} + +void +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); } + |