~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/etnaviv/drm/etnaviv_cmd_stream.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2014-2015 Etnaviv Project
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 FROM,
20
 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
 
 * SOFTWARE.
22
 
 *
23
 
 * Authors:
24
 
 *    Christian Gmeiner <christian.gmeiner@gmail.com>
25
 
 */
26
 
 
27
 
#include <assert.h>
28
 
#include <stdlib.h>
29
 
 
30
 
#include "etnaviv_drmif.h"
31
 
#include "etnaviv_priv.h"
32
 
 
33
 
static simple_mtx_t idx_lock = _SIMPLE_MTX_INITIALIZER_NP;
34
 
 
35
 
static void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz)
36
 
{
37
 
        if ((nr + 1) > *max) {
38
 
                if ((*max * 2) < (nr + 1))
39
 
                        *max = nr + 5;
40
 
                else
41
 
                        *max = *max * 2;
42
 
                ptr = realloc(ptr, *max * sz);
43
 
        }
44
 
 
45
 
        return ptr;
46
 
}
47
 
 
48
 
#define APPEND(x, name) ({ \
49
 
        (x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \
50
 
        (x)->nr_ ## name ++; \
51
 
})
52
 
 
53
 
void etna_cmd_stream_realloc(struct etna_cmd_stream *stream, size_t n)
54
 
{
55
 
        size_t size;
56
 
        void *buffer;
57
 
 
58
 
        /*
59
 
         * Increase the command buffer size by 4 kiB. Here we pick 4 kiB
60
 
         * increment to prevent it from growing too much too quickly.
61
 
         */
62
 
        size = ALIGN(stream->size + n, 1024);
63
 
 
64
 
        /* Command buffer is too big for older kernel versions */
65
 
        if (size > 0x4000)
66
 
                goto error;
67
 
 
68
 
        buffer = realloc(stream->buffer, size * 4);
69
 
        if (!buffer)
70
 
                goto error;
71
 
 
72
 
        stream->buffer = buffer;
73
 
        stream->size = size;
74
 
 
75
 
        return;
76
 
 
77
 
error:
78
 
        DEBUG_MSG("command buffer too long, forcing flush.");
79
 
        etna_cmd_stream_force_flush(stream);
80
 
}
81
 
 
82
 
static inline struct etna_cmd_stream_priv *
83
 
etna_cmd_stream_priv(struct etna_cmd_stream *stream)
84
 
{
85
 
    return (struct etna_cmd_stream_priv *)stream;
86
 
}
87
 
 
88
 
struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe,
89
 
        uint32_t size,
90
 
                void (*force_flush)(struct etna_cmd_stream *stream, void *priv),
91
 
                void *priv)
92
 
{
93
 
        struct etna_cmd_stream_priv *stream = NULL;
94
 
 
95
 
        if (size == 0) {
96
 
                ERROR_MSG("invalid size of 0");
97
 
                goto fail;
98
 
        }
99
 
 
100
 
        stream = calloc(1, sizeof(*stream));
101
 
        if (!stream) {
102
 
                ERROR_MSG("allocation failed");
103
 
                goto fail;
104
 
        }
105
 
 
106
 
        /* allocate even number of 32-bit words */
107
 
        size = ALIGN(size, 2);
108
 
 
109
 
        stream->base.buffer = malloc(size * sizeof(uint32_t));
110
 
        if (!stream->base.buffer) {
111
 
                ERROR_MSG("allocation failed");
112
 
                goto fail;
113
 
        }
114
 
 
115
 
        stream->base.size = size;
116
 
        stream->pipe = pipe;
117
 
        stream->force_flush = force_flush;
118
 
        stream->force_flush_priv = priv;
119
 
 
120
 
        return &stream->base;
121
 
 
122
 
fail:
123
 
        if (stream)
124
 
                etna_cmd_stream_del(&stream->base);
125
 
 
126
 
        return NULL;
127
 
}
128
 
 
129
 
void etna_cmd_stream_del(struct etna_cmd_stream *stream)
130
 
{
131
 
        struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
132
 
 
133
 
        free(stream->buffer);
134
 
        free(priv->submit.relocs);
135
 
        free(priv->submit.pmrs);
136
 
        free(priv);
137
 
}
138
 
 
139
 
void etna_cmd_stream_force_flush(struct etna_cmd_stream *stream)
140
 
{
141
 
        struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
142
 
 
143
 
        if (priv->force_flush)
144
 
                priv->force_flush(stream, priv->force_flush_priv);
145
 
}
146
 
 
147
 
uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream)
148
 
{
149
 
        return etna_cmd_stream_priv(stream)->last_timestamp;
150
 
}
151
 
 
152
 
static uint32_t append_bo(struct etna_cmd_stream *stream, struct etna_bo *bo)
153
 
{
154
 
        struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
155
 
        uint32_t idx;
156
 
 
157
 
        simple_mtx_assert_locked(&idx_lock);
158
 
 
159
 
        idx = APPEND(&priv->submit, bos);
160
 
        idx = APPEND(priv, bos);
161
 
 
162
 
        priv->submit.bos[idx].flags = 0;
163
 
        priv->submit.bos[idx].handle = bo->handle;
164
 
        priv->submit.bos[idx].presumed = bo->va;
165
 
 
166
 
        priv->bos[idx] = etna_bo_ref(bo);
167
 
 
168
 
        return idx;
169
 
}
170
 
 
171
 
/* add (if needed) bo, return idx: */
172
 
static uint32_t bo2idx(struct etna_cmd_stream *stream, struct etna_bo *bo,
173
 
                uint32_t flags)
174
 
{
175
 
        struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
176
 
        uint32_t idx;
177
 
 
178
 
        simple_mtx_lock(&idx_lock);
179
 
 
180
 
        if (bo->current_stream == stream) {
181
 
                idx = bo->idx;
182
 
        } else {
183
 
                void *val;
184
 
 
185
 
                if (!priv->bo_table)
186
 
                        priv->bo_table = drmHashCreate();
187
 
 
188
 
                if (!drmHashLookup(priv->bo_table, bo->handle, &val)) {
189
 
                        /* found */
190
 
                        idx = (uint32_t)(uintptr_t)val;
191
 
                } else {
192
 
                        idx = append_bo(stream, bo);
193
 
                        val = (void *)(uintptr_t)idx;
194
 
                        drmHashInsert(priv->bo_table, bo->handle, val);
195
 
                }
196
 
 
197
 
                bo->current_stream = stream;
198
 
                bo->idx = idx;
199
 
        }
200
 
        simple_mtx_unlock(&idx_lock);
201
 
 
202
 
        if (flags & ETNA_RELOC_READ)
203
 
                priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_READ;
204
 
        if (flags & ETNA_RELOC_WRITE)
205
 
                priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_WRITE;
206
 
 
207
 
        return idx;
208
 
}
209
 
 
210
 
void etna_cmd_stream_flush(struct etna_cmd_stream *stream, int in_fence_fd,
211
 
                int *out_fence_fd, bool is_noop)
212
 
{
213
 
        struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
214
 
        int ret, id = priv->pipe->id;
215
 
        struct etna_gpu *gpu = priv->pipe->gpu;
216
 
 
217
 
        struct drm_etnaviv_gem_submit req = {
218
 
                .pipe = gpu->core,
219
 
                .exec_state = id,
220
 
                .bos = VOID2U64(priv->submit.bos),
221
 
                .nr_bos = priv->submit.nr_bos,
222
 
                .relocs = VOID2U64(priv->submit.relocs),
223
 
                .nr_relocs = priv->submit.nr_relocs,
224
 
                .pmrs = VOID2U64(priv->submit.pmrs),
225
 
                .nr_pmrs = priv->submit.nr_pmrs,
226
 
                .stream = VOID2U64(stream->buffer),
227
 
                .stream_size = stream->offset * 4, /* in bytes */
228
 
        };
229
 
 
230
 
        if (in_fence_fd != -1) {
231
 
                req.flags |= ETNA_SUBMIT_FENCE_FD_IN | ETNA_SUBMIT_NO_IMPLICIT;
232
 
                req.fence_fd = in_fence_fd;
233
 
        }
234
 
 
235
 
        if (out_fence_fd)
236
 
                req.flags |= ETNA_SUBMIT_FENCE_FD_OUT;
237
 
 
238
 
        if (gpu->dev->use_softpin)
239
 
                req.flags |= ETNA_SUBMIT_SOFTPIN;
240
 
 
241
 
        if (unlikely(is_noop))
242
 
                ret = 0;
243
 
        else
244
 
                ret = drmCommandWriteRead(gpu->dev->fd, DRM_ETNAVIV_GEM_SUBMIT,
245
 
                                &req, sizeof(req));
246
 
 
247
 
        if (ret)
248
 
                ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno));
249
 
        else
250
 
                priv->last_timestamp = req.fence;
251
 
 
252
 
        for (uint32_t i = 0; i < priv->nr_bos; i++) {
253
 
                struct etna_bo *bo = priv->bos[i];
254
 
 
255
 
                bo->current_stream = NULL;
256
 
                etna_bo_del(bo);
257
 
        }
258
 
 
259
 
        if (priv->bo_table) {
260
 
                drmHashDestroy(priv->bo_table);
261
 
                priv->bo_table = NULL;
262
 
        }
263
 
 
264
 
        if (out_fence_fd)
265
 
                *out_fence_fd = req.fence_fd;
266
 
 
267
 
        stream->offset = 0;
268
 
        priv->submit.nr_bos = 0;
269
 
        priv->submit.nr_relocs = 0;
270
 
        priv->submit.nr_pmrs = 0;
271
 
        priv->nr_bos = 0;
272
 
}
273
 
 
274
 
void etna_cmd_stream_reloc(struct etna_cmd_stream *stream,
275
 
                                                                          const struct etna_reloc *r)
276
 
{
277
 
        struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
278
 
        struct drm_etnaviv_gem_submit_reloc *reloc;
279
 
        uint32_t addr = r->bo->va + r->offset;
280
 
        uint32_t bo_idx = bo2idx(stream, r->bo, r->flags);
281
 
        uint32_t idx;
282
 
 
283
 
        if (!priv->pipe->gpu->dev->use_softpin) {
284
 
                idx = APPEND(&priv->submit, relocs);
285
 
                reloc = &priv->submit.relocs[idx];
286
 
 
287
 
                reloc->reloc_idx = bo_idx;
288
 
                reloc->reloc_offset = r->offset;
289
 
                reloc->submit_offset = stream->offset * 4; /* in bytes */
290
 
                reloc->flags = 0;
291
 
        }
292
 
 
293
 
        etna_cmd_stream_emit(stream, addr);
294
 
}
295
 
 
296
 
void etna_cmd_stream_ref_bo(struct etna_cmd_stream *stream, struct etna_bo *bo,
297
 
                uint32_t flags)
298
 
{
299
 
        bo2idx(stream, bo, flags);
300
 
}
301
 
 
302
 
void etna_cmd_stream_perf(struct etna_cmd_stream *stream, const struct etna_perf *p)
303
 
{
304
 
        struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
305
 
        struct drm_etnaviv_gem_submit_pmr *pmr;
306
 
        uint32_t idx = APPEND(&priv->submit, pmrs);
307
 
 
308
 
        pmr = &priv->submit.pmrs[idx];
309
 
 
310
 
        pmr->flags = p->flags;
311
 
        pmr->sequence = p->sequence;
312
 
        pmr->read_offset = p->offset;
313
 
        pmr->read_idx = bo2idx(stream, p->bo, ETNA_SUBMIT_BO_READ | ETNA_SUBMIT_BO_WRITE);
314
 
        pmr->domain = p->signal->domain->id;
315
 
        pmr->signal = p->signal->signal;
316
 
}