vc4_job.c revision f473348468ae1c68e7ef8eaf29f2cc51d17fbec7
1/*
2 * Copyright © 2014-2015 Broadcom
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24/** @file vc4_job.c
25 *
26 * Functions for submitting VC4 render jobs to the kernel.
27 */
28
29#include <xf86drm.h>
30#include "vc4_context.h"
31
32void
33vc4_job_init(struct vc4_job *job)
34{
35        vc4_init_cl(job, &job->bcl);
36        vc4_init_cl(job, &job->shader_rec);
37        vc4_init_cl(job, &job->uniforms);
38        vc4_init_cl(job, &job->bo_handles);
39        vc4_init_cl(job, &job->bo_pointers);
40        vc4_job_reset(job);
41}
42
43void
44vc4_job_reset(struct vc4_job *job)
45{
46        struct vc4_bo **referenced_bos = job->bo_pointers.base;
47        for (int i = 0; i < cl_offset(&job->bo_handles) / 4; i++) {
48                vc4_bo_unreference(&referenced_bos[i]);
49        }
50        vc4_reset_cl(&job->bcl);
51        vc4_reset_cl(&job->shader_rec);
52        vc4_reset_cl(&job->uniforms);
53        vc4_reset_cl(&job->bo_handles);
54        vc4_reset_cl(&job->bo_pointers);
55        job->shader_rec_count = 0;
56
57        job->needs_flush = false;
58        job->draw_calls_queued = 0;
59
60        job->resolve = 0;
61        job->cleared = 0;
62
63        job->draw_min_x = ~0;
64        job->draw_min_y = ~0;
65        job->draw_max_x = 0;
66        job->draw_max_y = 0;
67
68        pipe_surface_reference(&job->color_write, NULL);
69        pipe_surface_reference(&job->color_read, NULL);
70        pipe_surface_reference(&job->msaa_color_write, NULL);
71        pipe_surface_reference(&job->zs_write, NULL);
72        pipe_surface_reference(&job->zs_read, NULL);
73        pipe_surface_reference(&job->msaa_zs_write, NULL);
74}
75
76static void
77vc4_submit_setup_rcl_surface(struct vc4_job *job,
78                             struct drm_vc4_submit_rcl_surface *submit_surf,
79                             struct pipe_surface *psurf,
80                             bool is_depth, bool is_write)
81{
82        struct vc4_surface *surf = vc4_surface(psurf);
83
84        if (!surf)
85                return;
86
87        struct vc4_resource *rsc = vc4_resource(psurf->texture);
88        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
89        submit_surf->offset = surf->offset;
90
91        if (psurf->texture->nr_samples <= 1) {
92                if (is_depth) {
93                        submit_surf->bits =
94                                VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_ZS,
95                                              VC4_LOADSTORE_TILE_BUFFER_BUFFER);
96
97                } else {
98                        submit_surf->bits =
99                                VC4_SET_FIELD(VC4_LOADSTORE_TILE_BUFFER_COLOR,
100                                              VC4_LOADSTORE_TILE_BUFFER_BUFFER) |
101                                VC4_SET_FIELD(vc4_rt_format_is_565(psurf->format) ?
102                                              VC4_LOADSTORE_TILE_BUFFER_BGR565 :
103                                              VC4_LOADSTORE_TILE_BUFFER_RGBA8888,
104                                              VC4_LOADSTORE_TILE_BUFFER_FORMAT);
105                }
106                submit_surf->bits |=
107                        VC4_SET_FIELD(surf->tiling,
108                                      VC4_LOADSTORE_TILE_BUFFER_TILING);
109        } else {
110                assert(!is_write);
111                submit_surf->flags |= VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES;
112        }
113
114        if (is_write)
115                rsc->writes++;
116}
117
118static void
119vc4_submit_setup_rcl_render_config_surface(struct vc4_job *job,
120                                           struct drm_vc4_submit_rcl_surface *submit_surf,
121                                           struct pipe_surface *psurf)
122{
123        struct vc4_surface *surf = vc4_surface(psurf);
124
125        if (!surf)
126                return;
127
128        struct vc4_resource *rsc = vc4_resource(psurf->texture);
129        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
130        submit_surf->offset = surf->offset;
131
132        if (psurf->texture->nr_samples <= 1) {
133                submit_surf->bits =
134                        VC4_SET_FIELD(vc4_rt_format_is_565(surf->base.format) ?
135                                      VC4_RENDER_CONFIG_FORMAT_BGR565 :
136                                      VC4_RENDER_CONFIG_FORMAT_RGBA8888,
137                                      VC4_RENDER_CONFIG_FORMAT) |
138                        VC4_SET_FIELD(surf->tiling,
139                                      VC4_RENDER_CONFIG_MEMORY_FORMAT);
140        }
141
142        rsc->writes++;
143}
144
145static void
146vc4_submit_setup_rcl_msaa_surface(struct vc4_job *job,
147                                  struct drm_vc4_submit_rcl_surface *submit_surf,
148                                  struct pipe_surface *psurf)
149{
150        struct vc4_surface *surf = vc4_surface(psurf);
151
152        if (!surf)
153                return;
154
155        struct vc4_resource *rsc = vc4_resource(psurf->texture);
156        submit_surf->hindex = vc4_gem_hindex(job, rsc->bo);
157        submit_surf->offset = surf->offset;
158        submit_surf->bits = 0;
159        rsc->writes++;
160}
161
162/**
163 * Submits the job to the kernel and then reinitializes it.
164 */
165void
166vc4_job_submit(struct vc4_context *vc4, struct vc4_job *job)
167{
168        if (!job->needs_flush)
169                return;
170
171        /* The RCL setup would choke if the draw bounds cause no drawing, so
172         * just drop the drawing if that's the case.
173         */
174        if (job->draw_max_x <= job->draw_min_x ||
175            job->draw_max_y <= job->draw_min_y) {
176                vc4_job_reset(job);
177                return;
178        }
179
180        if (vc4_debug & VC4_DEBUG_CL) {
181                fprintf(stderr, "BCL:\n");
182                vc4_dump_cl(job->bcl.base, cl_offset(&job->bcl), false);
183        }
184
185        if (cl_offset(&job->bcl) > 0) {
186                /* Increment the semaphore indicating that binning is done and
187                 * unblocking the render thread.  Note that this doesn't act
188                 * until the FLUSH completes.
189                 */
190                cl_ensure_space(&job->bcl, 8);
191                struct vc4_cl_out *bcl = cl_start(&job->bcl);
192                cl_u8(&bcl, VC4_PACKET_INCREMENT_SEMAPHORE);
193                /* The FLUSH caps all of our bin lists with a
194                 * VC4_PACKET_RETURN.
195                 */
196                cl_u8(&bcl, VC4_PACKET_FLUSH);
197                cl_end(&job->bcl, bcl);
198        }
199        struct drm_vc4_submit_cl submit = {
200                .color_read.hindex = ~0,
201                .zs_read.hindex = ~0,
202                .color_write.hindex = ~0,
203                .msaa_color_write.hindex = ~0,
204                .zs_write.hindex = ~0,
205                .msaa_zs_write.hindex = ~0,
206        };
207
208        cl_ensure_space(&job->bo_handles, 6 * sizeof(uint32_t));
209        cl_ensure_space(&job->bo_pointers, 6 * sizeof(struct vc4_bo *));
210
211        if (job->resolve & PIPE_CLEAR_COLOR) {
212                if (!(job->cleared & PIPE_CLEAR_COLOR)) {
213                        vc4_submit_setup_rcl_surface(job, &submit.color_read,
214                                                     job->color_read,
215                                                     false, false);
216                }
217                vc4_submit_setup_rcl_render_config_surface(job,
218                                                           &submit.color_write,
219                                                           job->color_write);
220                vc4_submit_setup_rcl_msaa_surface(job,
221                                                  &submit.msaa_color_write,
222                                                  job->msaa_color_write);
223        }
224        if (job->resolve & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) {
225                if (!(job->cleared & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL))) {
226                        vc4_submit_setup_rcl_surface(job, &submit.zs_read,
227                                                     job->zs_read, true, false);
228                }
229                vc4_submit_setup_rcl_surface(job, &submit.zs_write,
230                                             job->zs_write, true, true);
231                vc4_submit_setup_rcl_msaa_surface(job, &submit.msaa_zs_write,
232                                                  job->msaa_zs_write);
233        }
234
235        if (job->msaa) {
236                /* This bit controls how many pixels the general
237                 * (i.e. subsampled) loads/stores are iterating over
238                 * (multisample loads replicate out to the other samples).
239                 */
240                submit.color_write.bits |= VC4_RENDER_CONFIG_MS_MODE_4X;
241                /* Controls whether color_write's
242                 * VC4_PACKET_STORE_MS_TILE_BUFFER does 4x decimation
243                 */
244                submit.color_write.bits |= VC4_RENDER_CONFIG_DECIMATE_MODE_4X;
245        }
246
247        submit.bo_handles = (uintptr_t)job->bo_handles.base;
248        submit.bo_handle_count = cl_offset(&job->bo_handles) / 4;
249        submit.bin_cl = (uintptr_t)job->bcl.base;
250        submit.bin_cl_size = cl_offset(&job->bcl);
251        submit.shader_rec = (uintptr_t)job->shader_rec.base;
252        submit.shader_rec_size = cl_offset(&job->shader_rec);
253        submit.shader_rec_count = job->shader_rec_count;
254        submit.uniforms = (uintptr_t)job->uniforms.base;
255        submit.uniforms_size = cl_offset(&job->uniforms);
256
257        assert(job->draw_min_x != ~0 && job->draw_min_y != ~0);
258        submit.min_x_tile = job->draw_min_x / job->tile_width;
259        submit.min_y_tile = job->draw_min_y / job->tile_height;
260        submit.max_x_tile = (job->draw_max_x - 1) / job->tile_width;
261        submit.max_y_tile = (job->draw_max_y - 1) / job->tile_height;
262        submit.width = job->draw_width;
263        submit.height = job->draw_height;
264        if (job->cleared) {
265                submit.flags |= VC4_SUBMIT_CL_USE_CLEAR_COLOR;
266                submit.clear_color[0] = job->clear_color[0];
267                submit.clear_color[1] = job->clear_color[1];
268                submit.clear_z = job->clear_depth;
269                submit.clear_s = job->clear_stencil;
270        }
271
272        if (!(vc4_debug & VC4_DEBUG_NORAST)) {
273                int ret;
274
275#ifndef USE_VC4_SIMULATOR
276                ret = drmIoctl(vc4->fd, DRM_IOCTL_VC4_SUBMIT_CL, &submit);
277#else
278                ret = vc4_simulator_flush(vc4, &submit);
279#endif
280                static bool warned = false;
281                if (ret && !warned) {
282                        fprintf(stderr, "Draw call returned %s.  "
283                                        "Expect corruption.\n", strerror(errno));
284                        warned = true;
285                } else if (!ret) {
286                        vc4->last_emit_seqno = submit.seqno;
287                }
288        }
289
290        if (vc4->last_emit_seqno - vc4->screen->finished_seqno > 5) {
291                if (!vc4_wait_seqno(vc4->screen,
292                                    vc4->last_emit_seqno - 5,
293                                    PIPE_TIMEOUT_INFINITE,
294                                    "job throttling")) {
295                        fprintf(stderr, "Job throttling failed\n");
296                }
297        }
298
299        if (vc4_debug & VC4_DEBUG_ALWAYS_SYNC) {
300                if (!vc4_wait_seqno(vc4->screen, vc4->last_emit_seqno,
301                                    PIPE_TIMEOUT_INFINITE, "sync")) {
302                        fprintf(stderr, "Wait failed.\n");
303                        abort();
304                }
305        }
306
307        vc4_job_reset(vc4->job);
308}
309