2 * Copyright (C) 2014-2015 Etnaviv Project
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:
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
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
24 * Christian Gmeiner <christian.gmeiner@gmail.com>
29 #include "etnaviv_drmif.h"
30 #include "etnaviv_priv.h"
32 static pthread_mutex_t idx_lock
= PTHREAD_MUTEX_INITIALIZER
;
34 static void *grow(void *ptr
, uint32_t nr
, uint32_t *max
, uint32_t sz
)
36 if ((nr
+ 1) > *max
) {
37 if ((*max
* 2) < (nr
+ 1))
41 ptr
= realloc(ptr
, *max
* sz
);
47 #define APPEND(x, name) ({ \
48 (x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \
49 (x)->nr_ ## name ++; \
52 static inline struct etna_cmd_stream_priv
*
53 etna_cmd_stream_priv(struct etna_cmd_stream
*stream
)
55 return (struct etna_cmd_stream_priv
*)stream
;
58 struct etna_cmd_stream
*etna_cmd_stream_new(struct etna_pipe
*pipe
,
60 void (*reset_notify
)(struct etna_cmd_stream
*stream
, void *priv
),
63 struct etna_cmd_stream_priv
*stream
= NULL
;
66 ERROR_MSG("invalid size of 0");
70 stream
= calloc(1, sizeof(*stream
));
72 ERROR_MSG("allocation failed");
76 /* allocate even number of 32-bit words */
77 size
= ALIGN(size
, 2);
79 stream
->base
.buffer
= malloc(size
* sizeof(uint32_t));
80 if (!stream
->base
.buffer
) {
81 ERROR_MSG("allocation failed");
85 stream
->base
.size
= size
;
87 stream
->reset_notify
= reset_notify
;
88 stream
->reset_notify_priv
= priv
;
94 etna_cmd_stream_del(&stream
->base
);
99 void etna_cmd_stream_del(struct etna_cmd_stream
*stream
)
101 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
103 free(stream
->buffer
);
104 free(priv
->submit
.relocs
);
105 free(priv
->submit
.pmrs
);
109 static void reset_buffer(struct etna_cmd_stream
*stream
)
111 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
114 priv
->submit
.nr_bos
= 0;
115 priv
->submit
.nr_relocs
= 0;
116 priv
->submit
.nr_pmrs
= 0;
119 if (priv
->reset_notify
)
120 priv
->reset_notify(stream
, priv
->reset_notify_priv
);
123 uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream
*stream
)
125 return etna_cmd_stream_priv(stream
)->last_timestamp
;
128 static uint32_t append_bo(struct etna_cmd_stream
*stream
, struct etna_bo
*bo
)
130 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
133 idx
= APPEND(&priv
->submit
, bos
);
134 idx
= APPEND(priv
, bos
);
136 priv
->submit
.bos
[idx
].flags
= 0;
137 priv
->submit
.bos
[idx
].handle
= bo
->handle
;
139 priv
->bos
[idx
] = etna_bo_ref(bo
);
144 /* add (if needed) bo, return idx: */
145 static uint32_t bo2idx(struct etna_cmd_stream
*stream
, struct etna_bo
*bo
,
148 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
151 pthread_mutex_lock(&idx_lock
);
153 if (!bo
->current_stream
) {
154 idx
= append_bo(stream
, bo
);
155 bo
->current_stream
= stream
;
157 } else if (bo
->current_stream
== stream
) {
161 for (idx
= 0; idx
< priv
->nr_bos
; idx
++)
162 if (priv
->bos
[idx
] == bo
)
164 if (idx
== priv
->nr_bos
) {
166 idx
= append_bo(stream
, bo
);
169 pthread_mutex_unlock(&idx_lock
);
171 if (flags
& ETNA_RELOC_READ
)
172 priv
->submit
.bos
[idx
].flags
|= ETNA_SUBMIT_BO_READ
;
173 if (flags
& ETNA_RELOC_WRITE
)
174 priv
->submit
.bos
[idx
].flags
|= ETNA_SUBMIT_BO_WRITE
;
179 static void flush(struct etna_cmd_stream
*stream
, int in_fence_fd
,
182 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
183 int ret
, id
= priv
->pipe
->id
;
184 struct etna_gpu
*gpu
= priv
->pipe
->gpu
;
186 struct drm_etnaviv_gem_submit req
= {
189 .bos
= VOID2U64(priv
->submit
.bos
),
190 .nr_bos
= priv
->submit
.nr_bos
,
191 .relocs
= VOID2U64(priv
->submit
.relocs
),
192 .nr_relocs
= priv
->submit
.nr_relocs
,
193 .pmrs
= VOID2U64(priv
->submit
.pmrs
),
194 .nr_pmrs
= priv
->submit
.nr_pmrs
,
195 .stream
= VOID2U64(stream
->buffer
),
196 .stream_size
= stream
->offset
* 4, /* in bytes */
199 if (in_fence_fd
!= -1) {
200 req
.flags
|= ETNA_SUBMIT_FENCE_FD_IN
| ETNA_SUBMIT_NO_IMPLICIT
;
201 req
.fence_fd
= in_fence_fd
;
205 req
.flags
|= ETNA_SUBMIT_FENCE_FD_OUT
;
207 ret
= drmCommandWriteRead(gpu
->dev
->fd
, DRM_ETNAVIV_GEM_SUBMIT
,
211 ERROR_MSG("submit failed: %d (%s)", ret
, strerror(errno
));
213 priv
->last_timestamp
= req
.fence
;
215 for (uint32_t i
= 0; i
< priv
->nr_bos
; i
++) {
216 struct etna_bo
*bo
= priv
->bos
[i
];
218 bo
->current_stream
= NULL
;
223 *out_fence_fd
= req
.fence_fd
;
226 void etna_cmd_stream_flush(struct etna_cmd_stream
*stream
)
228 flush(stream
, -1, NULL
);
229 reset_buffer(stream
);
232 void etna_cmd_stream_flush2(struct etna_cmd_stream
*stream
,
236 flush(stream
, in_fence_fd
, out_fence_fd
);
237 reset_buffer(stream
);
240 void etna_cmd_stream_finish(struct etna_cmd_stream
*stream
)
242 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
244 flush(stream
, -1, NULL
);
245 etna_pipe_wait(priv
->pipe
, priv
->last_timestamp
, 5000);
246 reset_buffer(stream
);
249 void etna_cmd_stream_reloc(struct etna_cmd_stream
*stream
,
250 const struct etna_reloc
*r
)
252 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
253 struct drm_etnaviv_gem_submit_reloc
*reloc
;
254 uint32_t idx
= APPEND(&priv
->submit
, relocs
);
257 reloc
= &priv
->submit
.relocs
[idx
];
259 reloc
->reloc_idx
= bo2idx(stream
, r
->bo
, r
->flags
);
260 reloc
->reloc_offset
= r
->offset
;
261 reloc
->submit_offset
= stream
->offset
* 4; /* in bytes */
264 etna_cmd_stream_emit(stream
, addr
);
267 void etna_cmd_stream_perf(struct etna_cmd_stream
*stream
, const struct etna_perf
*p
)
269 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
270 struct drm_etnaviv_gem_submit_pmr
*pmr
;
271 uint32_t idx
= APPEND(&priv
->submit
, pmrs
);
273 pmr
= &priv
->submit
.pmrs
[idx
];
275 pmr
->flags
= p
->flags
;
276 pmr
->sequence
= p
->sequence
;
277 pmr
->read_offset
= p
->offset
;
278 pmr
->read_idx
= bo2idx(stream
, p
->bo
, ETNA_SUBMIT_BO_READ
| ETNA_SUBMIT_BO_WRITE
);
279 pmr
->domain
= p
->signal
->domain
->id
;
280 pmr
->signal
= p
->signal
->signal
;