1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2014-2015 Broadcom
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg/** @file vc4_job.c
25b8e80941Smrg *
26b8e80941Smrg * Functions for submitting VC4 render jobs to the kernel.
27b8e80941Smrg */
28b8e80941Smrg
29b8e80941Smrg#include <xf86drm.h>
30b8e80941Smrg#include "vc4_cl_dump.h"
31b8e80941Smrg#include "vc4_context.h"
32b8e80941Smrg#include "util/hash_table.h"
33b8e80941Smrg
34b8e80941Smrgstatic void
35b8e80941Smrgvc4_job_free(struct vc4_context *vc4, struct vc4_job *job)
36b8e80941Smrg{
37b8e80941Smrg        struct vc4_bo **referenced_bos = job->bo_pointers.base;
38b8e80941Smrg        for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) {
39b8e80941Smrg                vc4_bo_unreference(&referenced_bos[i]);
40b8e80941Smrg        }
41b8e80941Smrg
42b8e80941Smrg        _mesa_hash_table_remove_key(vc4->jobs, &job->key);
43b8e80941Smrg
44b8e80941Smrg        if (job->color_write) {
45b8e80941Smrg                _mesa_hash_table_remove_key(vc4->write_jobs,
46b8e80941Smrg                                            job->color_write->texture);
47b8e80941Smrg                pipe_surface_reference(&job->color_write, NULL);
48b8e80941Smrg        }
49b8e80941Smrg        if (job->msaa_color_write) {
50b8e80941Smrg                _mesa_hash_table_remove_key(vc4->write_jobs,
51b8e80941Smrg                                            job->msaa_color_write->texture);
52b8e80941Smrg                pipe_surface_reference(&job->msaa_color_write, NULL);
53b8e80941Smrg        }
54b8e80941Smrg        if (job->zs_write) {
55b8e80941Smrg                _mesa_hash_table_remove_key(vc4->write_jobs,
56b8e80941Smrg                                            job->zs_write->texture);
57b8e80941Smrg                pipe_surface_reference(&job->zs_write, NULL);
58b8e80941Smrg        }
59b8e80941Smrg        if (job->msaa_zs_write) {
60b8e80941Smrg                _mesa_hash_table_remove_key(vc4->write_jobs,
61b8e80941Smrg                                            job->msaa_zs_write->texture);
62b8e80941Smrg                pipe_surface_reference(&job->msaa_zs_write, NULL);
63b8e80941Smrg        }
64b8e80941Smrg
65b8e80941Smrg        pipe_surface_reference(&job->color_read, NULL);
66b8e80941Smrg        pipe_surface_reference(&job->zs_read, NULL);
67b8e80941Smrg
68b8e80941Smrg        if (vc4->job == job)
69b8e80941Smrg                vc4->job = NULL;
70b8e80941Smrg
71b8e80941Smrg        ralloc_free(job);
72b8e80941Smrg}
73b8e80941Smrg
74b8e80941Smrgstatic struct vc4_job *
75b8e80941Smrgvc4_job_create(struct vc4_context *vc4)
76b8e80941Smrg{
77b8e80941Smrg        struct vc4_job *job = rzalloc(vc4, struct vc4_job);
78b8e80941Smrg
79b8e80941Smrg        vc4_init_cl(job, &job->bcl);
80b8e80941Smrg        vc4_init_cl(job, &job->shader_rec);
81b8e80941Smrg        vc4_init_cl(job, &job->uniforms);
82b8e80941Smrg        vc4_init_cl(job, &job->bo_handles);
83b8e80941Smrg        vc4_init_cl(job, &job->bo_pointers);
84b8e80941Smrg
85b8e80941Smrg        job->draw_min_x = ~0;
86b8e80941Smrg        job->draw_min_y = ~0;
87b8e80941Smrg        job->draw_max_x = 0;
88b8e80941Smrg        job->draw_max_y = 0;
89b8e80941Smrg
90b8e80941Smrg        job->last_gem_handle_hindex = ~0;
91b8e80941Smrg
92b8e80941Smrg        if (vc4->perfmon)
93b8e80941Smrg                job->perfmon = vc4->perfmon;
94b8e80941Smrg
95b8e80941Smrg        return job;
96b8e80941Smrg}
97b8e80941Smrg
98b8e80941Smrgvoid
99b8e80941Smrgvc4_flush_jobs_writing_resource(struct vc4_context *vc4,
100b8e80941Smrg                                struct pipe_resource *prsc)
101b8e80941Smrg{
102b8e80941Smrg        struct hash_entry *entry = _mesa_hash_table_search(vc4->write_jobs,
103b8e80941Smrg                                                           prsc);
104b8e80941Smrg        if (entry) {
105b8e80941Smrg                struct vc4_job *job = entry->data;
106b8e80941Smrg                vc4_job_submit(vc4, job);
107b8e80941Smrg        }
108b8e80941Smrg}
109b8e80941Smrg
110b8e80941Smrgvoid
111b8e80941Smrgvc4_flush_jobs_reading_resource(struct vc4_context *vc4,
112b8e80941Smrg                                struct pipe_resource *prsc)
113b8e80941Smrg{
114b8e80941Smrg        struct vc4_resource *rsc = vc4_resource(prsc);
115b8e80941Smrg
116b8e80941Smrg        vc4_flush_jobs_writing_resource(vc4, prsc);
117b8e80941Smrg
118b8e80941Smrg        hash_table_foreach(vc4->jobs, entry) {
119b8e80941Smrg                struct vc4_job *job = entry->data;
120b8e80941Smrg
121b8e80941Smrg                struct vc4_bo **referenced_bos = job->bo_pointers.base;
122b8e80941Smrg                bool found = false;
123b8e80941Smrg                for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) {
124b8e80941Smrg                        if (referenced_bos[i] == rsc->bo) {
125b8e80941Smrg                                found = true;
126b8e80941Smrg                                break;
127b8e80941Smrg                        }
128b8e80941Smrg                }
129b8e80941Smrg                if (found) {
130b8e80941Smrg                        vc4_job_submit(vc4, job);
131b8e80941Smrg                        continue;
132b8e80941Smrg                }
133b8e80941Smrg
134b8e80941Smrg                /* Also check for the Z/color buffers, since the references to
135b8e80941Smrg                 * those are only added immediately before submit.
136b8e80941Smrg                 */
137b8e80941Smrg                if (job->color_read && !(job->cleared & PIPE_CLEAR_COLOR)) {
138b8e80941Smrg                        struct vc4_resource *ctex =
139b8e80941Smrg                                vc4_resource(job->color_read->texture);
140b8e80941Smrg                        if (ctex->bo == rsc->bo) {
141b8e80941Smrg                                vc4_job_submit(vc4, job);
142b8e80941Smrg                                continue;
143b8e80941Smrg                        }
144b8e80941Smrg                }
145b8e80941Smrg
146b8e80941Smrg                if (job->zs_read && !(job->cleared &
147b8e80941Smrg                                      (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
148b8e80941Smrg                        struct vc4_resource *ztex =
149b8e80941Smrg                                vc4_resource(job->zs_read->texture);
150b8e80941Smrg                        if (ztex->bo == rsc->bo) {
151b8e80941Smrg                                vc4_job_submit(vc4, job);
152b8e80941Smrg                                continue;
153b8e80941Smrg                        }
154b8e80941Smrg                }
155b8e80941Smrg        }
156b8e80941Smrg}
157b8e80941Smrg
158b8e80941Smrg/**
159b8e80941Smrg * Returns a vc4_job struture for tracking V3D rendering to a particular FBO.
160b8e80941Smrg *
161b8e80941Smrg * If we've already started rendering to this FBO, then return old same job,
162b8e80941Smrg * otherwise make a new one.  If we're beginning rendering to an FBO, make
163b8e80941Smrg * sure that any previous reads of the FBO (or writes to its color/Z surfaces)
164b8e80941Smrg * have been flushed.
165b8e80941Smrg */
166b8e80941Smrgstruct vc4_job *
167b8e80941Smrgvc4_get_job(struct vc4_context *vc4,
168b8e80941Smrg            struct pipe_surface *cbuf, struct pipe_surface *zsbuf)
169b8e80941Smrg{
170b8e80941Smrg        /* Return the existing job for this FBO if we have one */
171b8e80941Smrg        struct vc4_job_key local_key = {.cbuf = cbuf, .zsbuf = zsbuf};
172b8e80941Smrg        struct hash_entry *entry = _mesa_hash_table_search(vc4->jobs,
173b8e80941Smrg                                                           &local_key);
174b8e80941Smrg        if (entry)
175b8e80941Smrg                return entry->data;
176b8e80941Smrg
177b8e80941Smrg        /* Creating a new job.  Make sure that any previous jobs reading or
178b8e80941Smrg         * writing these buffers are flushed.
179b8e80941Smrg         */
180b8e80941Smrg        if (cbuf)
181b8e80941Smrg                vc4_flush_jobs_reading_resource(vc4, cbuf->texture);
182b8e80941Smrg        if (zsbuf)
183b8e80941Smrg                vc4_flush_jobs_reading_resource(vc4, zsbuf->texture);
184b8e80941Smrg
185b8e80941Smrg        struct vc4_job *job = vc4_job_create(vc4);
186b8e80941Smrg
187b8e80941Smrg        if (cbuf) {
188b8e80941Smrg                if (cbuf->texture->nr_samples > 1) {
189b8e80941Smrg                        job->msaa = true;
190b8e80941Smrg                        pipe_surface_reference(&job->msaa_color_write, cbuf);
191b8e80941Smrg                } else {
192b8e80941Smrg                        pipe_surface_reference(&job->color_write, cbuf);
193b8e80941Smrg                }
194b8e80941Smrg        }
195b8e80941Smrg
196b8e80941Smrg        if (zsbuf) {
197b8e80941Smrg                if (zsbuf->texture->nr_samples > 1) {
198b8e80941Smrg                        job->msaa = true;
199b8e80941Smrg                        pipe_surface_reference(&job->msaa_zs_write, zsbuf);
200b8e80941Smrg                } else {
201b8e80941Smrg                        pipe_surface_reference(&job->zs_write, zsbuf);
202b8e80941Smrg                }
203b8e80941Smrg        }
204b8e80941Smrg
205b8e80941Smrg        if (job->msaa) {
206b8e80941Smrg                job->tile_width = 32;
207b8e80941Smrg                job->tile_height = 32;
208b8e80941Smrg        } else {
209b8e80941Smrg                job->tile_width = 64;
210b8e80941Smrg                job->tile_height = 64;
211b8e80941Smrg        }
212b8e80941Smrg
213b8e80941Smrg        if (cbuf)
214b8e80941Smrg                _mesa_hash_table_insert(vc4->write_jobs, cbuf->texture, job);
215b8e80941Smrg        if (zsbuf)
216b8e80941Smrg                _mesa_hash_table_insert(vc4->write_jobs, zsbuf->texture, job);
217b8e80941Smrg
218b8e80941Smrg        job->key.cbuf = cbuf;
219b8e80941Smrg        job->key.zsbuf = zsbuf;
220b8e80941Smrg        _mesa_hash_table_insert(vc4->jobs, &job->key, job);
221b8e80941Smrg
222b8e80941Smrg        return job;
223b8e80941Smrg}
224b8e80941Smrg
225b8e80941Smrgstruct vc4_job *
226b8e80941Smrgvc4_get_job_for_fbo(struct vc4_context *vc4)
227b8e80941Smrg{
228b8e80941Smrg        if (vc4->job)
229b8e80941Smrg                return vc4->job;
230b8e80941Smrg
231b8e80941Smrg        struct pipe_surface *cbuf = vc4->framebuffer.cbufs[0];
232b8e80941Smrg        struct pipe_surface *zsbuf = vc4->framebuffer.zsbuf;
233b8e80941Smrg        struct vc4_job *job = vc4_get_job(vc4, cbuf, zsbuf);
234b8e80941Smrg
235b8e80941Smrg        /* The dirty flags are tracking what's been updated while vc4->job has
236b8e80941Smrg         * been bound, so set them all to ~0 when switching between jobs.  We
237b8e80941Smrg         * also need to reset all state at the start of rendering.
238b8e80941Smrg         */
239b8e80941Smrg        vc4->dirty = ~0;
240b8e80941Smrg
241b8e80941Smrg        /* Set up the read surfaces in the job.  If they aren't actually
242b8e80941Smrg         * getting read (due to a clear starting the frame), job->cleared will
243b8e80941Smrg         * mask out the read.
244b8e80941Smrg         */
245b8e80941Smrg        pipe_surface_reference(&job->color_read, cbuf);
246b8e80941Smrg        pipe_surface_reference(&job->zs_read, zsbuf);
247b8e80941Smrg
248b8e80941Smrg        /* If we're binding to uninitialized buffers, no need to load their
249b8e80941Smrg         * contents before drawing.
250b8e80941Smrg         */
251b8e80941Smrg        if (cbuf) {
252b8e80941Smrg                struct vc4_resource *rsc = vc4_resource(cbuf->texture);
253b8e80941Smrg                if (!rsc->writes)
254b8e80941Smrg                        job->cleared |= PIPE_CLEAR_COLOR0;
255b8e80941Smrg        }
256b8e80941Smrg
257b8e80941Smrg        if (zsbuf) {
258b8e80941Smrg                struct vc4_resource *rsc = vc4_resource(zsbuf->texture);
259b8e80941Smrg                if (!rsc->writes)
260b8e80941Smrg                        job->cleared |= PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL;
261b8e80941Smrg        }
262b8e80941Smrg
263b8e80941Smrg        job->draw_tiles_x = DIV_ROUND_UP(vc4->framebuffer.width,
264b8e80941Smrg                                         job->tile_width);
265b8e80941Smrg        job->draw_tiles_y = DIV_ROUND_UP(vc4->framebuffer.height,
266b8e80941Smrg                                         job->tile_height);
267b8e80941Smrg
268b8e80941Smrg        /* Initialize the job with the raster order flags -- each draw will
269b8e80941Smrg         * check that we haven't changed the flags, since that requires a
270b8e80941Smrg         * flush.
271b8e80941Smrg         */
272b8e80941Smrg        if (vc4->rasterizer)
273b8e80941Smrg                job->flags = vc4->rasterizer->tile_raster_order_flags;
274b8e80941Smrg
275b8e80941Smrg        vc4->job = job;
276b8e80941Smrg
277b8e80941Smrg        return job;
278b8e80941Smrg}
279b8e80941Smrg
280b8e80941Smrgstatic void
281b8e80941Smrgvc4_submit_setup_rcl_surface(struct vc4_job *job,
282b8e80941Smrg                             struct drm_vc4_submit_rcl_surface *submit_surf,
283b8e80941Smrg                             struct pipe_surface *psurf,
284b8e80941Smrg                             bool is_depth, bool is_write)
285b8e80941Smrg{
286b8e80941Smrg        struct vc4_surface *surf = vc4_surface(psurf);
287b8e80941Smrg
288b8e80941Smrg        if (!surf)
289b8e80941Smrg                return;
290b8e80941Smrg
291b8e80941Smrg        struct vc4_resource *rsc = vc4_resource(psurf->texture);
292b8e80941Smrg        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
293b8e80941Smrg        submit_surf->offset = surf->offset;
294b8e80941Smrg
295b8e80941Smrg        if (psurf->texture->nr_samples <= 1) {
296b8e80941Smrg                if (is_depth) {
297b8e80941Smrg                        submit_surf->bits =
298b8e80941Smrg                                VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_ZS,
299b8e80941Smrg                                              VC4_LOADSTORE_TILE_BUFFER_BUFFER);
300b8e80941Smrg
301b8e80941Smrg                } else {
302b8e80941Smrg                        submit_surf->bits =
303b8e80941Smrg                                VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_COLOR,
304b8e80941Smrg                                              VC4_LOADSTORE_TILE_BUFFER_BUFFER) |
305b8e80941Smrg                                VC4_SET_FIELD(vc4_rt_format_is_565(psurf->format) ?
306b8e80941Smrg                                              VC4_LOADSTORE_TILE_BUFFER_BGR565 :
307b8e80941Smrg                                              VC4_LOADSTORE_TILE_BUFFER_RGBA8888,
308b8e80941Smrg                                              VC4_LOADSTORE_TILE_BUFFER_FORMAT);
309b8e80941Smrg                }
310b8e80941Smrg                submit_surf->bits |=
311b8e80941Smrg                        VC4_SET_FIELD(surf->tiling,
312b8e80941Smrg                                      VC4_LOADSTORE_TILE_BUFFER_TILING);
313b8e80941Smrg        } else {
314b8e80941Smrg                assert(!is_write);
315b8e80941Smrg                submit_surf->flags |= VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES;
316b8e80941Smrg        }
317b8e80941Smrg
318b8e80941Smrg        if (is_write)
319b8e80941Smrg                rsc->writes++;
320b8e80941Smrg}
321b8e80941Smrg
322b8e80941Smrgstatic void
323b8e80941Smrgvc4_submit_setup_rcl_render_config_surface(struct vc4_job *job,
324b8e80941Smrg                                           struct drm_vc4_submit_rcl_surface *submit_surf,
325b8e80941Smrg                                           struct pipe_surface *psurf)
326b8e80941Smrg{
327b8e80941Smrg        struct vc4_surface *surf = vc4_surface(psurf);
328b8e80941Smrg
329b8e80941Smrg        if (!surf)
330b8e80941Smrg                return;
331b8e80941Smrg
332b8e80941Smrg        struct vc4_resource *rsc = vc4_resource(psurf->texture);
333b8e80941Smrg        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
334b8e80941Smrg        submit_surf->offset = surf->offset;
335b8e80941Smrg
336b8e80941Smrg        if (psurf->texture->nr_samples <= 1) {
337b8e80941Smrg                submit_surf->bits =
338b8e80941Smrg                        VC4_SET_FIELD(vc4_rt_format_is_565(surf->base.format) ?
339b8e80941Smrg                                      VC4_RENDER_CONFIG_FORMAT_BGR565 :
340b8e80941Smrg                                      VC4_RENDER_CONFIG_FORMAT_RGBA8888,
341b8e80941Smrg                                      VC4_RENDER_CONFIG_FORMAT) |
342b8e80941Smrg                        VC4_SET_FIELD(surf->tiling,
343b8e80941Smrg                                      VC4_RENDER_CONFIG_MEMORY_FORMAT);
344b8e80941Smrg        }
345b8e80941Smrg
346b8e80941Smrg        rsc->writes++;
347b8e80941Smrg}
348b8e80941Smrg
349b8e80941Smrgstatic void
350b8e80941Smrgvc4_submit_setup_rcl_msaa_surface(struct vc4_job *job,
351b8e80941Smrg                                  struct drm_vc4_submit_rcl_surface *submit_surf,
352b8e80941Smrg                                  struct pipe_surface *psurf)
353b8e80941Smrg{
354b8e80941Smrg        struct vc4_surface *surf = vc4_surface(psurf);
355b8e80941Smrg
356b8e80941Smrg        if (!surf)
357b8e80941Smrg                return;
358b8e80941Smrg
359b8e80941Smrg        struct vc4_resource *rsc = vc4_resource(psurf->texture);
360b8e80941Smrg        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
361b8e80941Smrg        submit_surf->offset = surf->offset;
362b8e80941Smrg        submit_surf->bits = 0;
363b8e80941Smrg        rsc->writes++;
364b8e80941Smrg}
365b8e80941Smrg
366b8e80941Smrg/**
367b8e80941Smrg * Submits the job to the kernel and then reinitializes it.
368b8e80941Smrg */
369b8e80941Smrgvoid
370b8e80941Smrgvc4_job_submit(struct vc4_context *vc4, struct vc4_job *job)
371b8e80941Smrg{
372b8e80941Smrg        if (!job->needs_flush)
373b8e80941Smrg                goto done;
374b8e80941Smrg
375b8e80941Smrg        /* The RCL setup would choke if the draw bounds cause no drawing, so
376b8e80941Smrg         * just drop the drawing if that's the case.
377b8e80941Smrg         */
378b8e80941Smrg        if (job->draw_max_x <= job->draw_min_x ||
379b8e80941Smrg            job->draw_max_y <= job->draw_min_y) {
380b8e80941Smrg                goto done;
381b8e80941Smrg        }
382b8e80941Smrg
383b8e80941Smrg        if (vc4_debug & VC4_DEBUG_CL) {
384b8e80941Smrg                fprintf(stderr, "BCL:\n");
385b8e80941Smrg                vc4_dump_cl(job->bcl.base, cl_offset(&job->bcl), false);
386b8e80941Smrg        }
387b8e80941Smrg
388b8e80941Smrg        if (cl_offset(&job->bcl) > 0) {
389b8e80941Smrg                /* Increment the semaphore indicating that binning is done and
390b8e80941Smrg                 * unblocking the render thread.  Note that this doesn't act
391b8e80941Smrg                 * until the FLUSH completes.
392b8e80941Smrg                 */
393b8e80941Smrg                cl_ensure_space(&job->bcl, 8);
394b8e80941Smrg                cl_emit(&job->bcl, INCREMENT_SEMAPHORE, incr);
395b8e80941Smrg                /* The FLUSH caps all of our bin lists with a
396b8e80941Smrg                 * VC4_PACKET_RETURN.
397b8e80941Smrg                 */
398b8e80941Smrg                cl_emit(&job->bcl, FLUSH, flush);
399b8e80941Smrg        }
400b8e80941Smrg        struct drm_vc4_submit_cl submit = {
401b8e80941Smrg                .color_read.hindex = ~0,
402b8e80941Smrg                .zs_read.hindex = ~0,
403b8e80941Smrg                .color_write.hindex = ~0,
404b8e80941Smrg                .msaa_color_write.hindex = ~0,
405b8e80941Smrg                .zs_write.hindex = ~0,
406b8e80941Smrg                .msaa_zs_write.hindex = ~0,
407b8e80941Smrg        };
408b8e80941Smrg
409b8e80941Smrg        cl_ensure_space(&job->bo_handles, 6 * sizeof(uint32_t));
410b8e80941Smrg        cl_ensure_space(&job->bo_pointers, 6 * sizeof(struct vc4_bo *));
411b8e80941Smrg
412b8e80941Smrg        if (job->resolve & PIPE_CLEAR_COLOR) {
413b8e80941Smrg                if (!(job->cleared & PIPE_CLEAR_COLOR)) {
414b8e80941Smrg                        vc4_submit_setup_rcl_surface(job, &submit.color_read,
415b8e80941Smrg                                                     job->color_read,
416b8e80941Smrg                                                     false, false);
417b8e80941Smrg                }
418b8e80941Smrg                vc4_submit_setup_rcl_render_config_surface(job,
419b8e80941Smrg                                                           &submit.color_write,
420b8e80941Smrg                                                           job->color_write);
421b8e80941Smrg                vc4_submit_setup_rcl_msaa_surface(job,
422b8e80941Smrg                                                  &submit.msaa_color_write,
423b8e80941Smrg                                                  job->msaa_color_write);
424b8e80941Smrg        }
425b8e80941Smrg        if (job->resolve & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) {
426b8e80941Smrg                if (!(job->cleared & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
427b8e80941Smrg                        vc4_submit_setup_rcl_surface(job, &submit.zs_read,
428b8e80941Smrg                                                     job->zs_read, true, false);
429b8e80941Smrg                }
430b8e80941Smrg                vc4_submit_setup_rcl_surface(job, &submit.zs_write,
431b8e80941Smrg                                             job->zs_write, true, true);
432b8e80941Smrg                vc4_submit_setup_rcl_msaa_surface(job, &submit.msaa_zs_write,
433b8e80941Smrg                                                  job->msaa_zs_write);
434b8e80941Smrg        }
435b8e80941Smrg
436b8e80941Smrg        if (job->msaa) {
437b8e80941Smrg                /* This bit controls how many pixels the general
438b8e80941Smrg                 * (i.e. subsampled) loads/stores are iterating over
439b8e80941Smrg                 * (multisample loads replicate out to the other samples).
440b8e80941Smrg                 */
441b8e80941Smrg                submit.color_write.bits |= VC4_RENDER_CONFIG_MS_MODE_4X;
442b8e80941Smrg                /* Controls whether color_write's
443b8e80941Smrg                 * VC4_PACKET_STORE_MS_TILE_BUFFER does 4x decimation
444b8e80941Smrg                 */
445b8e80941Smrg                submit.color_write.bits |= VC4_RENDER_CONFIG_DECIMATE_MODE_4X;
446b8e80941Smrg        }
447b8e80941Smrg
448b8e80941Smrg        submit.bo_handles = (uintptr_t)job->bo_handles.base;
449b8e80941Smrg        submit.bo_handle_count = cl_offset(&job->bo_handles) / 4;
450b8e80941Smrg        submit.bin_cl = (uintptr_t)job->bcl.base;
451b8e80941Smrg        submit.bin_cl_size = cl_offset(&job->bcl);
452b8e80941Smrg        submit.shader_rec = (uintptr_t)job->shader_rec.base;
453b8e80941Smrg        submit.shader_rec_size = cl_offset(&job->shader_rec);
454b8e80941Smrg        submit.shader_rec_count = job->shader_rec_count;
455b8e80941Smrg        submit.uniforms = (uintptr_t)job->uniforms.base;
456b8e80941Smrg        submit.uniforms_size = cl_offset(&job->uniforms);
457b8e80941Smrg	if (job->perfmon)
458b8e80941Smrg		submit.perfmonid = job->perfmon->id;
459b8e80941Smrg
460b8e80941Smrg        assert(job->draw_min_x != ~0 && job->draw_min_y != ~0);
461b8e80941Smrg        submit.min_x_tile = job->draw_min_x / job->tile_width;
462b8e80941Smrg        submit.min_y_tile = job->draw_min_y / job->tile_height;
463b8e80941Smrg        submit.max_x_tile = (job->draw_max_x - 1) / job->tile_width;
464b8e80941Smrg        submit.max_y_tile = (job->draw_max_y - 1) / job->tile_height;
465b8e80941Smrg        submit.width = job->draw_width;
466b8e80941Smrg        submit.height = job->draw_height;
467b8e80941Smrg        if (job->cleared) {
468b8e80941Smrg                submit.flags |= VC4_SUBMIT_CL_USE_CLEAR_COLOR;
469b8e80941Smrg                submit.clear_color[0] = job->clear_color[0];
470b8e80941Smrg                submit.clear_color[1] = job->clear_color[1];
471b8e80941Smrg                submit.clear_z = job->clear_depth;
472b8e80941Smrg                submit.clear_s = job->clear_stencil;
473b8e80941Smrg        }
474b8e80941Smrg        submit.flags |= job->flags;
475b8e80941Smrg
476b8e80941Smrg        if (vc4->screen->has_syncobj) {
477b8e80941Smrg                submit.out_sync = vc4->job_syncobj;
478b8e80941Smrg
479b8e80941Smrg                if (vc4->in_fence_fd >= 0) {
480b8e80941Smrg                        /* This replaces the fence in the syncobj. */
481b8e80941Smrg                        drmSyncobjImportSyncFile(vc4->fd, vc4->in_syncobj,
482b8e80941Smrg                                                 vc4->in_fence_fd);
483b8e80941Smrg                        submit.in_sync = vc4->in_syncobj;
484b8e80941Smrg                        close(vc4->in_fence_fd);
485b8e80941Smrg                        vc4->in_fence_fd = -1;
486b8e80941Smrg                }
487b8e80941Smrg        }
488b8e80941Smrg
489b8e80941Smrg        if (!(vc4_debug & VC4_DEBUG_NORAST)) {
490b8e80941Smrg                int ret;
491b8e80941Smrg
492b8e80941Smrg                ret = vc4_ioctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit);
493b8e80941Smrg                static bool warned = false;
494b8e80941Smrg                if (ret && !warned) {
495b8e80941Smrg                        fprintf(stderr, "Draw call returned %s.  "
496b8e80941Smrg                                        "Expect corruption.\n", strerror(errno));
497b8e80941Smrg                        warned = true;
498b8e80941Smrg                } else if (!ret) {
499b8e80941Smrg                        vc4->last_emit_seqno = submit.seqno;
500b8e80941Smrg                        if (job->perfmon)
501b8e80941Smrg                                job->perfmon->last_seqno = submit.seqno;
502b8e80941Smrg                }
503b8e80941Smrg        }
504b8e80941Smrg
505b8e80941Smrg        if (vc4->last_emit_seqno - vc4->screen->finished_seqno > 5) {
506b8e80941Smrg                if (!vc4_wait_seqno(vc4->screen,
507b8e80941Smrg                                    vc4->last_emit_seqno - 5,
508b8e80941Smrg                                    PIPE_TIMEOUT_INFINITE,
509b8e80941Smrg                                    "job throttling")) {
510b8e80941Smrg                        fprintf(stderr, "Job throttling failed\n");
511b8e80941Smrg                }
512b8e80941Smrg        }
513b8e80941Smrg
514b8e80941Smrg        if (vc4_debug & VC4_DEBUG_ALWAYS_SYNC) {
515b8e80941Smrg                if (!vc4_wait_seqno(vc4->screen, vc4->last_emit_seqno,
516b8e80941Smrg                                    PIPE_TIMEOUT_INFINITE, "sync")) {
517b8e80941Smrg                        fprintf(stderr, "Wait failed.\n");
518b8e80941Smrg                        abort();
519b8e80941Smrg                }
520b8e80941Smrg        }
521b8e80941Smrg
522b8e80941Smrgdone:
523b8e80941Smrg        vc4_job_free(vc4, job);
524b8e80941Smrg}
525b8e80941Smrg
526b8e80941Smrgstatic bool
527b8e80941Smrgvc4_job_compare(const void *a, const void *b)
528b8e80941Smrg{
529b8e80941Smrg        return memcmp(a, b, sizeof(struct vc4_job_key)) == 0;
530b8e80941Smrg}
531b8e80941Smrg
532b8e80941Smrgstatic uint32_t
533b8e80941Smrgvc4_job_hash(const void *key)
534b8e80941Smrg{
535b8e80941Smrg        return _mesa_hash_data(key, sizeof(struct vc4_job_key));
536b8e80941Smrg}
537b8e80941Smrg
538b8e80941Smrgint
539b8e80941Smrgvc4_job_init(struct vc4_context *vc4)
540b8e80941Smrg{
541b8e80941Smrg        vc4->jobs = _mesa_hash_table_create(vc4,
542b8e80941Smrg                                            vc4_job_hash,
543b8e80941Smrg                                            vc4_job_compare);
544b8e80941Smrg        vc4->write_jobs = _mesa_hash_table_create(vc4,
545b8e80941Smrg                                                  _mesa_hash_pointer,
546b8e80941Smrg                                                  _mesa_key_pointer_equal);
547b8e80941Smrg
548b8e80941Smrg        if (vc4->screen->has_syncobj) {
549b8e80941Smrg                /* Create the syncobj as signaled since with no job executed
550b8e80941Smrg                 * there is nothing to wait on.
551b8e80941Smrg                 */
552b8e80941Smrg                int ret = drmSyncobjCreate(vc4->fd,
553b8e80941Smrg                                           DRM_SYNCOBJ_CREATE_SIGNALED,
554b8e80941Smrg                                           &vc4->job_syncobj);
555b8e80941Smrg                if (ret) {
556b8e80941Smrg                        /* If the screen indicated syncobj support, we should
557b8e80941Smrg                         * be able to create a signaled syncobj.
558b8e80941Smrg                         * At this point it is too late to pretend the screen
559b8e80941Smrg                         * has no syncobj support.
560b8e80941Smrg                         */
561b8e80941Smrg                        return ret;
562b8e80941Smrg                }
563b8e80941Smrg        }
564b8e80941Smrg
565b8e80941Smrg        return 0;
566b8e80941Smrg}
567b8e80941Smrg
568