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 (*force_flush
)(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
->force_flush
= force_flush
;
88 stream
->force_flush_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 void etna_cmd_stream_force_flush(struct etna_cmd_stream
*stream
)
111 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
113 if (priv
->force_flush
)
114 priv
->force_flush(stream
, priv
->force_flush_priv
);
117 uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream
*stream
)
119 return etna_cmd_stream_priv(stream
)->last_timestamp
;
122 static uint32_t append_bo(struct etna_cmd_stream
*stream
, struct etna_bo
*bo
)
124 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
127 idx
= APPEND(&priv
->submit
, bos
);
128 idx
= APPEND(priv
, bos
);
130 priv
->submit
.bos
[idx
].flags
= 0;
131 priv
->submit
.bos
[idx
].handle
= bo
->handle
;
133 priv
->bos
[idx
] = etna_bo_ref(bo
);
138 /* add (if needed) bo, return idx: */
139 static uint32_t bo2idx(struct etna_cmd_stream
*stream
, struct etna_bo
*bo
,
142 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
145 pthread_mutex_lock(&idx_lock
);
147 if (bo
->current_stream
== stream
) {
153 priv
->bo_table
= drmHashCreate();
155 if (!drmHashLookup(priv
->bo_table
, bo
->handle
, &val
)) {
157 idx
= (uint32_t)(uintptr_t)val
;
159 idx
= append_bo(stream
, bo
);
160 val
= (void *)(uintptr_t)idx
;
161 drmHashInsert(priv
->bo_table
, bo
->handle
, val
);
164 bo
->current_stream
= stream
;
167 pthread_mutex_unlock(&idx_lock
);
169 if (flags
& ETNA_RELOC_READ
)
170 priv
->submit
.bos
[idx
].flags
|= ETNA_SUBMIT_BO_READ
;
171 if (flags
& ETNA_RELOC_WRITE
)
172 priv
->submit
.bos
[idx
].flags
|= ETNA_SUBMIT_BO_WRITE
;
177 void etna_cmd_stream_flush(struct etna_cmd_stream
*stream
, int in_fence_fd
,
180 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
181 int ret
, id
= priv
->pipe
->id
;
182 struct etna_gpu
*gpu
= priv
->pipe
->gpu
;
184 struct drm_etnaviv_gem_submit req
= {
187 .bos
= VOID2U64(priv
->submit
.bos
),
188 .nr_bos
= priv
->submit
.nr_bos
,
189 .relocs
= VOID2U64(priv
->submit
.relocs
),
190 .nr_relocs
= priv
->submit
.nr_relocs
,
191 .pmrs
= VOID2U64(priv
->submit
.pmrs
),
192 .nr_pmrs
= priv
->submit
.nr_pmrs
,
193 .stream
= VOID2U64(stream
->buffer
),
194 .stream_size
= stream
->offset
* 4, /* in bytes */
197 if (in_fence_fd
!= -1) {
198 req
.flags
|= ETNA_SUBMIT_FENCE_FD_IN
| ETNA_SUBMIT_NO_IMPLICIT
;
199 req
.fence_fd
= in_fence_fd
;
203 req
.flags
|= ETNA_SUBMIT_FENCE_FD_OUT
;
205 ret
= drmCommandWriteRead(gpu
->dev
->fd
, DRM_ETNAVIV_GEM_SUBMIT
,
209 ERROR_MSG("submit failed: %d (%s)", ret
, strerror(errno
));
211 priv
->last_timestamp
= req
.fence
;
213 for (uint32_t i
= 0; i
< priv
->nr_bos
; i
++) {
214 struct etna_bo
*bo
= priv
->bos
[i
];
216 bo
->current_stream
= NULL
;
220 if (priv
->bo_table
) {
221 drmHashDestroy(priv
->bo_table
);
222 priv
->bo_table
= NULL
;
226 *out_fence_fd
= req
.fence_fd
;
229 priv
->submit
.nr_bos
= 0;
230 priv
->submit
.nr_relocs
= 0;
231 priv
->submit
.nr_pmrs
= 0;
235 void etna_cmd_stream_reloc(struct etna_cmd_stream
*stream
,
236 const struct etna_reloc
*r
)
238 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
239 struct drm_etnaviv_gem_submit_reloc
*reloc
;
240 uint32_t idx
= APPEND(&priv
->submit
, relocs
);
243 reloc
= &priv
->submit
.relocs
[idx
];
245 reloc
->reloc_idx
= bo2idx(stream
, r
->bo
, r
->flags
);
246 reloc
->reloc_offset
= r
->offset
;
247 reloc
->submit_offset
= stream
->offset
* 4; /* in bytes */
250 etna_cmd_stream_emit(stream
, addr
);
253 void etna_cmd_stream_perf(struct etna_cmd_stream
*stream
, const struct etna_perf
*p
)
255 struct etna_cmd_stream_priv
*priv
= etna_cmd_stream_priv(stream
);
256 struct drm_etnaviv_gem_submit_pmr
*pmr
;
257 uint32_t idx
= APPEND(&priv
->submit
, pmrs
);
259 pmr
= &priv
->submit
.pmrs
[idx
];
261 pmr
->flags
= p
->flags
;
262 pmr
->sequence
= p
->sequence
;
263 pmr
->read_offset
= p
->offset
;
264 pmr
->read_idx
= bo2idx(stream
, p
->bo
, ETNA_SUBMIT_BO_READ
| ETNA_SUBMIT_BO_WRITE
);
265 pmr
->domain
= p
->signal
->domain
->id
;
266 pmr
->signal
= p
->signal
->signal
;