+ job->last_gem_handle_hindex = ~0;
+
+ 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;
+ 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;