101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2014-2015 Broadcom
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2101e04c3fSmrg * IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg/** @file vc4_job.c
2501e04c3fSmrg *
2601e04c3fSmrg * Functions for submitting VC4 render jobs to the kernel.
2701e04c3fSmrg */
2801e04c3fSmrg
2901e04c3fSmrg#include <xf86drm.h>
3001e04c3fSmrg#include "vc4_cl_dump.h"
3101e04c3fSmrg#include "vc4_context.h"
3201e04c3fSmrg#include "util/hash_table.h"
3301e04c3fSmrg
3401e04c3fSmrgstatic void
3501e04c3fSmrgvc4_job_free(struct vc4_context *vc4, struct vc4_job *job)
3601e04c3fSmrg{
3701e04c3fSmrg        struct vc4_bo **referenced_bos = job->bo_pointers.base;
3801e04c3fSmrg        for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) {
3901e04c3fSmrg                vc4_bo_unreference(&referenced_bos[i]);
4001e04c3fSmrg        }
4101e04c3fSmrg
429f464c52Smaya        _mesa_hash_table_remove_key(vc4->jobs, &job->key);
4301e04c3fSmrg
4401e04c3fSmrg        if (job->color_write) {
459f464c52Smaya                _mesa_hash_table_remove_key(vc4->write_jobs,
469f464c52Smaya                                            job->color_write->texture);
4701e04c3fSmrg                pipe_surface_reference(&job->color_write, NULL);
4801e04c3fSmrg        }
4901e04c3fSmrg        if (job->msaa_color_write) {
509f464c52Smaya                _mesa_hash_table_remove_key(vc4->write_jobs,
519f464c52Smaya                                            job->msaa_color_write->texture);
5201e04c3fSmrg                pipe_surface_reference(&job->msaa_color_write, NULL);
5301e04c3fSmrg        }
5401e04c3fSmrg        if (job->zs_write) {
559f464c52Smaya                _mesa_hash_table_remove_key(vc4->write_jobs,
569f464c52Smaya                                            job->zs_write->texture);
5701e04c3fSmrg                pipe_surface_reference(&job->zs_write, NULL);
5801e04c3fSmrg        }
5901e04c3fSmrg        if (job->msaa_zs_write) {
609f464c52Smaya                _mesa_hash_table_remove_key(vc4->write_jobs,
619f464c52Smaya                                            job->msaa_zs_write->texture);
6201e04c3fSmrg                pipe_surface_reference(&job->msaa_zs_write, NULL);
6301e04c3fSmrg        }
6401e04c3fSmrg
6501e04c3fSmrg        pipe_surface_reference(&job->color_read, NULL);
6601e04c3fSmrg        pipe_surface_reference(&job->zs_read, NULL);
6701e04c3fSmrg
6801e04c3fSmrg        if (vc4->job == job)
6901e04c3fSmrg                vc4->job = NULL;
7001e04c3fSmrg
7101e04c3fSmrg        ralloc_free(job);
7201e04c3fSmrg}
7301e04c3fSmrg
7401e04c3fSmrgstatic struct vc4_job *
7501e04c3fSmrgvc4_job_create(struct vc4_context *vc4)
7601e04c3fSmrg{
7701e04c3fSmrg        struct vc4_job *job = rzalloc(vc4, struct vc4_job);
7801e04c3fSmrg
7901e04c3fSmrg        vc4_init_cl(job, &job->bcl);
8001e04c3fSmrg        vc4_init_cl(job, &job->shader_rec);
8101e04c3fSmrg        vc4_init_cl(job, &job->uniforms);
8201e04c3fSmrg        vc4_init_cl(job, &job->bo_handles);
8301e04c3fSmrg        vc4_init_cl(job, &job->bo_pointers);
8401e04c3fSmrg
8501e04c3fSmrg        job->draw_min_x = ~0;
8601e04c3fSmrg        job->draw_min_y = ~0;
8701e04c3fSmrg        job->draw_max_x = 0;
8801e04c3fSmrg        job->draw_max_y = 0;
8901e04c3fSmrg
9001e04c3fSmrg        job->last_gem_handle_hindex = ~0;
9101e04c3fSmrg
9201e04c3fSmrg        if (vc4->perfmon)
9301e04c3fSmrg                job->perfmon = vc4->perfmon;
9401e04c3fSmrg
9501e04c3fSmrg        return job;
9601e04c3fSmrg}
9701e04c3fSmrg
9801e04c3fSmrgvoid
9901e04c3fSmrgvc4_flush_jobs_writing_resource(struct vc4_context *vc4,
10001e04c3fSmrg                                struct pipe_resource *prsc)
10101e04c3fSmrg{
10201e04c3fSmrg        struct hash_entry *entry = _mesa_hash_table_search(vc4->write_jobs,
10301e04c3fSmrg                                                           prsc);
10401e04c3fSmrg        if (entry) {
10501e04c3fSmrg                struct vc4_job *job = entry->data;
10601e04c3fSmrg                vc4_job_submit(vc4, job);
10701e04c3fSmrg        }
10801e04c3fSmrg}
10901e04c3fSmrg
11001e04c3fSmrgvoid
11101e04c3fSmrgvc4_flush_jobs_reading_resource(struct vc4_context *vc4,
11201e04c3fSmrg                                struct pipe_resource *prsc)
11301e04c3fSmrg{
11401e04c3fSmrg        struct vc4_resource *rsc = vc4_resource(prsc);
11501e04c3fSmrg
11601e04c3fSmrg        vc4_flush_jobs_writing_resource(vc4, prsc);
11701e04c3fSmrg
11801e04c3fSmrg        hash_table_foreach(vc4->jobs, entry) {
11901e04c3fSmrg                struct vc4_job *job = entry->data;
12001e04c3fSmrg
12101e04c3fSmrg                struct vc4_bo **referenced_bos = job->bo_pointers.base;
12201e04c3fSmrg                bool found = false;
12301e04c3fSmrg                for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) {
12401e04c3fSmrg                        if (referenced_bos[i] == rsc->bo) {
12501e04c3fSmrg                                found = true;
12601e04c3fSmrg                                break;
12701e04c3fSmrg                        }
12801e04c3fSmrg                }
12901e04c3fSmrg                if (found) {
13001e04c3fSmrg                        vc4_job_submit(vc4, job);
13101e04c3fSmrg                        continue;
13201e04c3fSmrg                }
13301e04c3fSmrg
13401e04c3fSmrg                /* Also check for the Z/color buffers, since the references to
13501e04c3fSmrg                 * those are only added immediately before submit.
13601e04c3fSmrg                 */
13701e04c3fSmrg                if (job->color_read && !(job->cleared & PIPE_CLEAR_COLOR)) {
13801e04c3fSmrg                        struct vc4_resource *ctex =
13901e04c3fSmrg                                vc4_resource(job->color_read->texture);
14001e04c3fSmrg                        if (ctex->bo == rsc->bo) {
14101e04c3fSmrg                                vc4_job_submit(vc4, job);
14201e04c3fSmrg                                continue;
14301e04c3fSmrg                        }
14401e04c3fSmrg                }
14501e04c3fSmrg
14601e04c3fSmrg                if (job->zs_read && !(job->cleared &
14701e04c3fSmrg                                      (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
14801e04c3fSmrg                        struct vc4_resource *ztex =
14901e04c3fSmrg                                vc4_resource(job->zs_read->texture);
15001e04c3fSmrg                        if (ztex->bo == rsc->bo) {
15101e04c3fSmrg                                vc4_job_submit(vc4, job);
15201e04c3fSmrg                                continue;
15301e04c3fSmrg                        }
15401e04c3fSmrg                }
15501e04c3fSmrg        }
15601e04c3fSmrg}
15701e04c3fSmrg
15801e04c3fSmrg/**
15901e04c3fSmrg * Returns a vc4_job struture for tracking V3D rendering to a particular FBO.
16001e04c3fSmrg *
16101e04c3fSmrg * If we've already started rendering to this FBO, then return old same job,
16201e04c3fSmrg * otherwise make a new one.  If we're beginning rendering to an FBO, make
16301e04c3fSmrg * sure that any previous reads of the FBO (or writes to its color/Z surfaces)
16401e04c3fSmrg * have been flushed.
16501e04c3fSmrg */
16601e04c3fSmrgstruct vc4_job *
16701e04c3fSmrgvc4_get_job(struct vc4_context *vc4,
16801e04c3fSmrg            struct pipe_surface *cbuf, struct pipe_surface *zsbuf)
16901e04c3fSmrg{
17001e04c3fSmrg        /* Return the existing job for this FBO if we have one */
17101e04c3fSmrg        struct vc4_job_key local_key = {.cbuf = cbuf, .zsbuf = zsbuf};
17201e04c3fSmrg        struct hash_entry *entry = _mesa_hash_table_search(vc4->jobs,
17301e04c3fSmrg                                                           &local_key);
17401e04c3fSmrg        if (entry)
17501e04c3fSmrg                return entry->data;
17601e04c3fSmrg
17701e04c3fSmrg        /* Creating a new job.  Make sure that any previous jobs reading or
17801e04c3fSmrg         * writing these buffers are flushed.
17901e04c3fSmrg         */
18001e04c3fSmrg        if (cbuf)
18101e04c3fSmrg                vc4_flush_jobs_reading_resource(vc4, cbuf->texture);
18201e04c3fSmrg        if (zsbuf)
18301e04c3fSmrg                vc4_flush_jobs_reading_resource(vc4, zsbuf->texture);
18401e04c3fSmrg
18501e04c3fSmrg        struct vc4_job *job = vc4_job_create(vc4);
18601e04c3fSmrg
18701e04c3fSmrg        if (cbuf) {
18801e04c3fSmrg                if (cbuf->texture->nr_samples > 1) {
18901e04c3fSmrg                        job->msaa = true;
19001e04c3fSmrg                        pipe_surface_reference(&job->msaa_color_write, cbuf);
19101e04c3fSmrg                } else {
19201e04c3fSmrg                        pipe_surface_reference(&job->color_write, cbuf);
19301e04c3fSmrg                }
19401e04c3fSmrg        }
19501e04c3fSmrg
19601e04c3fSmrg        if (zsbuf) {
19701e04c3fSmrg                if (zsbuf->texture->nr_samples > 1) {
19801e04c3fSmrg                        job->msaa = true;
19901e04c3fSmrg                        pipe_surface_reference(&job->msaa_zs_write, zsbuf);
20001e04c3fSmrg                } else {
20101e04c3fSmrg                        pipe_surface_reference(&job->zs_write, zsbuf);
20201e04c3fSmrg                }
20301e04c3fSmrg        }
20401e04c3fSmrg
20501e04c3fSmrg        if (job->msaa) {
20601e04c3fSmrg                job->tile_width = 32;
20701e04c3fSmrg                job->tile_height = 32;
20801e04c3fSmrg        } else {
20901e04c3fSmrg                job->tile_width = 64;
21001e04c3fSmrg                job->tile_height = 64;
21101e04c3fSmrg        }
21201e04c3fSmrg
21301e04c3fSmrg        if (cbuf)
21401e04c3fSmrg                _mesa_hash_table_insert(vc4->write_jobs, cbuf->texture, job);
21501e04c3fSmrg        if (zsbuf)
21601e04c3fSmrg                _mesa_hash_table_insert(vc4->write_jobs, zsbuf->texture, job);
21701e04c3fSmrg
21801e04c3fSmrg        job->key.cbuf = cbuf;
21901e04c3fSmrg        job->key.zsbuf = zsbuf;
22001e04c3fSmrg        _mesa_hash_table_insert(vc4->jobs, &job->key, job);
22101e04c3fSmrg
22201e04c3fSmrg        return job;
22301e04c3fSmrg}
22401e04c3fSmrg
22501e04c3fSmrgstruct vc4_job *
22601e04c3fSmrgvc4_get_job_for_fbo(struct vc4_context *vc4)
22701e04c3fSmrg{
22801e04c3fSmrg        if (vc4->job)
22901e04c3fSmrg                return vc4->job;
23001e04c3fSmrg
23101e04c3fSmrg        struct pipe_surface *cbuf = vc4->framebuffer.cbufs[0];
23201e04c3fSmrg        struct pipe_surface *zsbuf = vc4->framebuffer.zsbuf;
23301e04c3fSmrg        struct vc4_job *job = vc4_get_job(vc4, cbuf, zsbuf);
23401e04c3fSmrg
23501e04c3fSmrg        /* The dirty flags are tracking what's been updated while vc4->job has
23601e04c3fSmrg         * been bound, so set them all to ~0 when switching between jobs.  We
23701e04c3fSmrg         * also need to reset all state at the start of rendering.
23801e04c3fSmrg         */
23901e04c3fSmrg        vc4->dirty = ~0;
24001e04c3fSmrg
24101e04c3fSmrg        /* Set up the read surfaces in the job.  If they aren't actually
24201e04c3fSmrg         * getting read (due to a clear starting the frame), job->cleared will
24301e04c3fSmrg         * mask out the read.
24401e04c3fSmrg         */
24501e04c3fSmrg        pipe_surface_reference(&job->color_read, cbuf);
24601e04c3fSmrg        pipe_surface_reference(&job->zs_read, zsbuf);
24701e04c3fSmrg
24801e04c3fSmrg        /* If we're binding to uninitialized buffers, no need to load their
24901e04c3fSmrg         * contents before drawing.
25001e04c3fSmrg         */
25101e04c3fSmrg        if (cbuf) {
25201e04c3fSmrg                struct vc4_resource *rsc = vc4_resource(cbuf->texture);
25301e04c3fSmrg                if (!rsc->writes)
25401e04c3fSmrg                        job->cleared |= PIPE_CLEAR_COLOR0;
25501e04c3fSmrg        }
25601e04c3fSmrg
25701e04c3fSmrg        if (zsbuf) {
25801e04c3fSmrg                struct vc4_resource *rsc = vc4_resource(zsbuf->texture);
25901e04c3fSmrg                if (!rsc->writes)
26001e04c3fSmrg                        job->cleared |= PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL;
26101e04c3fSmrg        }
26201e04c3fSmrg
26301e04c3fSmrg        job->draw_tiles_x = DIV_ROUND_UP(vc4->framebuffer.width,
26401e04c3fSmrg                                         job->tile_width);
26501e04c3fSmrg        job->draw_tiles_y = DIV_ROUND_UP(vc4->framebuffer.height,
26601e04c3fSmrg                                         job->tile_height);
26701e04c3fSmrg
26801e04c3fSmrg        /* Initialize the job with the raster order flags -- each draw will
26901e04c3fSmrg         * check that we haven't changed the flags, since that requires a
27001e04c3fSmrg         * flush.
27101e04c3fSmrg         */
27201e04c3fSmrg        if (vc4->rasterizer)
27301e04c3fSmrg                job->flags = vc4->rasterizer->tile_raster_order_flags;
27401e04c3fSmrg
27501e04c3fSmrg        vc4->job = job;
27601e04c3fSmrg
27701e04c3fSmrg        return job;
27801e04c3fSmrg}
27901e04c3fSmrg
28001e04c3fSmrgstatic void
28101e04c3fSmrgvc4_submit_setup_rcl_surface(struct vc4_job *job,
28201e04c3fSmrg                             struct drm_vc4_submit_rcl_surface *submit_surf,
28301e04c3fSmrg                             struct pipe_surface *psurf,
28401e04c3fSmrg                             bool is_depth, bool is_write)
28501e04c3fSmrg{
28601e04c3fSmrg        struct vc4_surface *surf = vc4_surface(psurf);
28701e04c3fSmrg
28801e04c3fSmrg        if (!surf)
28901e04c3fSmrg                return;
29001e04c3fSmrg
29101e04c3fSmrg        struct vc4_resource *rsc = vc4_resource(psurf->texture);
29201e04c3fSmrg        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
29301e04c3fSmrg        submit_surf->offset = surf->offset;
29401e04c3fSmrg
29501e04c3fSmrg        if (psurf->texture->nr_samples <= 1) {
29601e04c3fSmrg                if (is_depth) {
29701e04c3fSmrg                        submit_surf->bits =
29801e04c3fSmrg                                VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_ZS,
29901e04c3fSmrg                                              VC4_LOADSTORE_TILE_BUFFER_BUFFER);
30001e04c3fSmrg
30101e04c3fSmrg                } else {
30201e04c3fSmrg                        submit_surf->bits =
30301e04c3fSmrg                                VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_COLOR,
30401e04c3fSmrg                                              VC4_LOADSTORE_TILE_BUFFER_BUFFER) |
30501e04c3fSmrg                                VC4_SET_FIELD(vc4_rt_format_is_565(psurf->format) ?
30601e04c3fSmrg                                              VC4_LOADSTORE_TILE_BUFFER_BGR565 :
30701e04c3fSmrg                                              VC4_LOADSTORE_TILE_BUFFER_RGBA8888,
30801e04c3fSmrg                                              VC4_LOADSTORE_TILE_BUFFER_FORMAT);
30901e04c3fSmrg                }
31001e04c3fSmrg                submit_surf->bits |=
31101e04c3fSmrg                        VC4_SET_FIELD(surf->tiling,
31201e04c3fSmrg                                      VC4_LOADSTORE_TILE_BUFFER_TILING);
31301e04c3fSmrg        } else {
31401e04c3fSmrg                assert(!is_write);
31501e04c3fSmrg                submit_surf->flags |= VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES;
31601e04c3fSmrg        }
31701e04c3fSmrg
31801e04c3fSmrg        if (is_write)
31901e04c3fSmrg                rsc->writes++;
32001e04c3fSmrg}
32101e04c3fSmrg
32201e04c3fSmrgstatic void
32301e04c3fSmrgvc4_submit_setup_rcl_render_config_surface(struct vc4_job *job,
32401e04c3fSmrg                                           struct drm_vc4_submit_rcl_surface *submit_surf,
32501e04c3fSmrg                                           struct pipe_surface *psurf)
32601e04c3fSmrg{
32701e04c3fSmrg        struct vc4_surface *surf = vc4_surface(psurf);
32801e04c3fSmrg
32901e04c3fSmrg        if (!surf)
33001e04c3fSmrg                return;
33101e04c3fSmrg
33201e04c3fSmrg        struct vc4_resource *rsc = vc4_resource(psurf->texture);
33301e04c3fSmrg        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
33401e04c3fSmrg        submit_surf->offset = surf->offset;
33501e04c3fSmrg
33601e04c3fSmrg        if (psurf->texture->nr_samples <= 1) {
33701e04c3fSmrg                submit_surf->bits =
33801e04c3fSmrg                        VC4_SET_FIELD(vc4_rt_format_is_565(surf->base.format) ?
33901e04c3fSmrg                                      VC4_RENDER_CONFIG_FORMAT_BGR565 :
34001e04c3fSmrg                                      VC4_RENDER_CONFIG_FORMAT_RGBA8888,
34101e04c3fSmrg                                      VC4_RENDER_CONFIG_FORMAT) |
34201e04c3fSmrg                        VC4_SET_FIELD(surf->tiling,
34301e04c3fSmrg                                      VC4_RENDER_CONFIG_MEMORY_FORMAT);
34401e04c3fSmrg        }
34501e04c3fSmrg
34601e04c3fSmrg        rsc->writes++;
34701e04c3fSmrg}
34801e04c3fSmrg
34901e04c3fSmrgstatic void
35001e04c3fSmrgvc4_submit_setup_rcl_msaa_surface(struct vc4_job *job,
35101e04c3fSmrg                                  struct drm_vc4_submit_rcl_surface *submit_surf,
35201e04c3fSmrg                                  struct pipe_surface *psurf)
35301e04c3fSmrg{
35401e04c3fSmrg        struct vc4_surface *surf = vc4_surface(psurf);
35501e04c3fSmrg
35601e04c3fSmrg        if (!surf)
35701e04c3fSmrg                return;
35801e04c3fSmrg
35901e04c3fSmrg        struct vc4_resource *rsc = vc4_resource(psurf->texture);
36001e04c3fSmrg        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
36101e04c3fSmrg        submit_surf->offset = surf->offset;
36201e04c3fSmrg        submit_surf->bits = 0;
36301e04c3fSmrg        rsc->writes++;
36401e04c3fSmrg}
36501e04c3fSmrg
36601e04c3fSmrg/**
36701e04c3fSmrg * Submits the job to the kernel and then reinitializes it.
36801e04c3fSmrg */
36901e04c3fSmrgvoid
37001e04c3fSmrgvc4_job_submit(struct vc4_context *vc4, struct vc4_job *job)
37101e04c3fSmrg{
37201e04c3fSmrg        if (!job->needs_flush)
37301e04c3fSmrg                goto done;
37401e04c3fSmrg
37501e04c3fSmrg        /* The RCL setup would choke if the draw bounds cause no drawing, so
37601e04c3fSmrg         * just drop the drawing if that's the case.
37701e04c3fSmrg         */
37801e04c3fSmrg        if (job->draw_max_x <= job->draw_min_x ||
37901e04c3fSmrg            job->draw_max_y <= job->draw_min_y) {
38001e04c3fSmrg                goto done;
38101e04c3fSmrg        }
38201e04c3fSmrg
38301e04c3fSmrg        if (vc4_debug & VC4_DEBUG_CL) {
38401e04c3fSmrg                fprintf(stderr, "BCL:\n");
38501e04c3fSmrg                vc4_dump_cl(job->bcl.base, cl_offset(&job->bcl), false);
38601e04c3fSmrg        }
38701e04c3fSmrg
38801e04c3fSmrg        if (cl_offset(&job->bcl) > 0) {
38901e04c3fSmrg                /* Increment the semaphore indicating that binning is done and
39001e04c3fSmrg                 * unblocking the render thread.  Note that this doesn't act
39101e04c3fSmrg                 * until the FLUSH completes.
39201e04c3fSmrg                 */
39301e04c3fSmrg                cl_ensure_space(&job->bcl, 8);
39401e04c3fSmrg                cl_emit(&job->bcl, INCREMENT_SEMAPHORE, incr);
39501e04c3fSmrg                /* The FLUSH caps all of our bin lists with a
39601e04c3fSmrg                 * VC4_PACKET_RETURN.
39701e04c3fSmrg                 */
39801e04c3fSmrg                cl_emit(&job->bcl, FLUSH, flush);
39901e04c3fSmrg        }
40001e04c3fSmrg        struct drm_vc4_submit_cl submit = {
40101e04c3fSmrg                .color_read.hindex = ~0,
40201e04c3fSmrg                .zs_read.hindex = ~0,
40301e04c3fSmrg                .color_write.hindex = ~0,
40401e04c3fSmrg                .msaa_color_write.hindex = ~0,
40501e04c3fSmrg                .zs_write.hindex = ~0,
40601e04c3fSmrg                .msaa_zs_write.hindex = ~0,
40701e04c3fSmrg        };
40801e04c3fSmrg
40901e04c3fSmrg        cl_ensure_space(&job->bo_handles, 6 * sizeof(uint32_t));
41001e04c3fSmrg        cl_ensure_space(&job->bo_pointers, 6 * sizeof(struct vc4_bo *));
41101e04c3fSmrg
41201e04c3fSmrg        if (job->resolve & PIPE_CLEAR_COLOR) {
41301e04c3fSmrg                if (!(job->cleared & PIPE_CLEAR_COLOR)) {
41401e04c3fSmrg                        vc4_submit_setup_rcl_surface(job, &submit.color_read,
41501e04c3fSmrg                                                     job->color_read,
41601e04c3fSmrg                                                     false, false);
41701e04c3fSmrg                }
41801e04c3fSmrg                vc4_submit_setup_rcl_render_config_surface(job,
41901e04c3fSmrg                                                           &submit.color_write,
42001e04c3fSmrg                                                           job->color_write);
42101e04c3fSmrg                vc4_submit_setup_rcl_msaa_surface(job,
42201e04c3fSmrg                                                  &submit.msaa_color_write,
42301e04c3fSmrg                                                  job->msaa_color_write);
42401e04c3fSmrg        }
42501e04c3fSmrg        if (job->resolve & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) {
42601e04c3fSmrg                if (!(job->cleared & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
42701e04c3fSmrg                        vc4_submit_setup_rcl_surface(job, &submit.zs_read,
42801e04c3fSmrg                                                     job->zs_read, true, false);
42901e04c3fSmrg                }
43001e04c3fSmrg                vc4_submit_setup_rcl_surface(job, &submit.zs_write,
43101e04c3fSmrg                                             job->zs_write, true, true);
43201e04c3fSmrg                vc4_submit_setup_rcl_msaa_surface(job, &submit.msaa_zs_write,
43301e04c3fSmrg                                                  job->msaa_zs_write);
43401e04c3fSmrg        }
43501e04c3fSmrg
43601e04c3fSmrg        if (job->msaa) {
43701e04c3fSmrg                /* This bit controls how many pixels the general
43801e04c3fSmrg                 * (i.e. subsampled) loads/stores are iterating over
43901e04c3fSmrg                 * (multisample loads replicate out to the other samples).
44001e04c3fSmrg                 */
44101e04c3fSmrg                submit.color_write.bits |= VC4_RENDER_CONFIG_MS_MODE_4X;
44201e04c3fSmrg                /* Controls whether color_write's
44301e04c3fSmrg                 * VC4_PACKET_STORE_MS_TILE_BUFFER does 4x decimation
44401e04c3fSmrg                 */
44501e04c3fSmrg                submit.color_write.bits |= VC4_RENDER_CONFIG_DECIMATE_MODE_4X;
44601e04c3fSmrg        }
44701e04c3fSmrg
44801e04c3fSmrg        submit.bo_handles = (uintptr_t)job->bo_handles.base;
44901e04c3fSmrg        submit.bo_handle_count = cl_offset(&job->bo_handles) / 4;
45001e04c3fSmrg        submit.bin_cl = (uintptr_t)job->bcl.base;
45101e04c3fSmrg        submit.bin_cl_size = cl_offset(&job->bcl);
45201e04c3fSmrg        submit.shader_rec = (uintptr_t)job->shader_rec.base;
45301e04c3fSmrg        submit.shader_rec_size = cl_offset(&job->shader_rec);
45401e04c3fSmrg        submit.shader_rec_count = job->shader_rec_count;
45501e04c3fSmrg        submit.uniforms = (uintptr_t)job->uniforms.base;
45601e04c3fSmrg        submit.uniforms_size = cl_offset(&job->uniforms);
45701e04c3fSmrg	if (job->perfmon)
45801e04c3fSmrg		submit.perfmonid = job->perfmon->id;
45901e04c3fSmrg
46001e04c3fSmrg        assert(job->draw_min_x != ~0 && job->draw_min_y != ~0);
46101e04c3fSmrg        submit.min_x_tile = job->draw_min_x / job->tile_width;
46201e04c3fSmrg        submit.min_y_tile = job->draw_min_y / job->tile_height;
46301e04c3fSmrg        submit.max_x_tile = (job->draw_max_x - 1) / job->tile_width;
46401e04c3fSmrg        submit.max_y_tile = (job->draw_max_y - 1) / job->tile_height;
46501e04c3fSmrg        submit.width = job->draw_width;
46601e04c3fSmrg        submit.height = job->draw_height;
46701e04c3fSmrg        if (job->cleared) {
46801e04c3fSmrg                submit.flags |= VC4_SUBMIT_CL_USE_CLEAR_COLOR;
46901e04c3fSmrg                submit.clear_color[0] = job->clear_color[0];
47001e04c3fSmrg                submit.clear_color[1] = job->clear_color[1];
47101e04c3fSmrg                submit.clear_z = job->clear_depth;
47201e04c3fSmrg                submit.clear_s = job->clear_stencil;
47301e04c3fSmrg        }
47401e04c3fSmrg        submit.flags |= job->flags;
47501e04c3fSmrg
47601e04c3fSmrg        if (vc4->screen->has_syncobj) {
47701e04c3fSmrg                submit.out_sync = vc4->job_syncobj;
47801e04c3fSmrg
47901e04c3fSmrg                if (vc4->in_fence_fd >= 0) {
48001e04c3fSmrg                        /* This replaces the fence in the syncobj. */
48101e04c3fSmrg                        drmSyncobjImportSyncFile(vc4->fd, vc4->in_syncobj,
48201e04c3fSmrg                                                 vc4->in_fence_fd);
48301e04c3fSmrg                        submit.in_sync = vc4->in_syncobj;
48401e04c3fSmrg                        close(vc4->in_fence_fd);
48501e04c3fSmrg                        vc4->in_fence_fd = -1;
48601e04c3fSmrg                }
48701e04c3fSmrg        }
48801e04c3fSmrg
48901e04c3fSmrg        if (!(vc4_debug & VC4_DEBUG_NORAST)) {
49001e04c3fSmrg                int ret;
49101e04c3fSmrg
4929f464c52Smaya                ret = vc4_ioctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit);
49301e04c3fSmrg                static bool warned = false;
49401e04c3fSmrg                if (ret && !warned) {
49501e04c3fSmrg                        fprintf(stderr, "Draw call returned %s.  "
49601e04c3fSmrg                                        "Expect corruption.\n", strerror(errno));
49701e04c3fSmrg                        warned = true;
49801e04c3fSmrg                } else if (!ret) {
49901e04c3fSmrg                        vc4->last_emit_seqno = submit.seqno;
50001e04c3fSmrg                        if (job->perfmon)
50101e04c3fSmrg                                job->perfmon->last_seqno = submit.seqno;
50201e04c3fSmrg                }
50301e04c3fSmrg        }
50401e04c3fSmrg
50501e04c3fSmrg        if (vc4->last_emit_seqno - vc4->screen->finished_seqno > 5) {
50601e04c3fSmrg                if (!vc4_wait_seqno(vc4->screen,
50701e04c3fSmrg                                    vc4->last_emit_seqno - 5,
50801e04c3fSmrg                                    PIPE_TIMEOUT_INFINITE,
50901e04c3fSmrg                                    "job throttling")) {
51001e04c3fSmrg                        fprintf(stderr, "Job throttling failed\n");
51101e04c3fSmrg                }
51201e04c3fSmrg        }
51301e04c3fSmrg
51401e04c3fSmrg        if (vc4_debug & VC4_DEBUG_ALWAYS_SYNC) {
51501e04c3fSmrg                if (!vc4_wait_seqno(vc4->screen, vc4->last_emit_seqno,
51601e04c3fSmrg                                    PIPE_TIMEOUT_INFINITE, "sync")) {
51701e04c3fSmrg                        fprintf(stderr, "Wait failed.\n");
51801e04c3fSmrg                        abort();
51901e04c3fSmrg                }
52001e04c3fSmrg        }
52101e04c3fSmrg
52201e04c3fSmrgdone:
52301e04c3fSmrg        vc4_job_free(vc4, job);
52401e04c3fSmrg}
52501e04c3fSmrg
52601e04c3fSmrgstatic bool
52701e04c3fSmrgvc4_job_compare(const void *a, const void *b)
52801e04c3fSmrg{
52901e04c3fSmrg        return memcmp(a, b, sizeof(struct vc4_job_key)) == 0;
53001e04c3fSmrg}
53101e04c3fSmrg
53201e04c3fSmrgstatic uint32_t
53301e04c3fSmrgvc4_job_hash(const void *key)
53401e04c3fSmrg{
53501e04c3fSmrg        return _mesa_hash_data(key, sizeof(struct vc4_job_key));
53601e04c3fSmrg}
53701e04c3fSmrg
53801e04c3fSmrgint
53901e04c3fSmrgvc4_job_init(struct vc4_context *vc4)
54001e04c3fSmrg{
54101e04c3fSmrg        vc4->jobs = _mesa_hash_table_create(vc4,
54201e04c3fSmrg                                            vc4_job_hash,
54301e04c3fSmrg                                            vc4_job_compare);
54401e04c3fSmrg        vc4->write_jobs = _mesa_hash_table_create(vc4,
54501e04c3fSmrg                                                  _mesa_hash_pointer,
54601e04c3fSmrg                                                  _mesa_key_pointer_equal);
54701e04c3fSmrg
54801e04c3fSmrg        if (vc4->screen->has_syncobj) {
54901e04c3fSmrg                /* Create the syncobj as signaled since with no job executed
55001e04c3fSmrg                 * there is nothing to wait on.
55101e04c3fSmrg                 */
55201e04c3fSmrg                int ret = drmSyncobjCreate(vc4->fd,
55301e04c3fSmrg                                           DRM_SYNCOBJ_CREATE_SIGNALED,
55401e04c3fSmrg                                           &vc4->job_syncobj);
55501e04c3fSmrg                if (ret) {
55601e04c3fSmrg                        /* If the screen indicated syncobj support, we should
55701e04c3fSmrg                         * be able to create a signaled syncobj.
55801e04c3fSmrg                         * At this point it is too late to pretend the screen
55901e04c3fSmrg                         * has no syncobj support.
56001e04c3fSmrg                         */
56101e04c3fSmrg                        return ret;
56201e04c3fSmrg                }
56301e04c3fSmrg        }
56401e04c3fSmrg
56501e04c3fSmrg        return 0;
56601e04c3fSmrg}
56701e04c3fSmrg
568