ilo: rework winsys bo reloc functions
[mesa.git] / src / gallium / drivers / ilo / ilo_cp.h
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2013 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #ifndef ILO_CP_H
29 #define ILO_CP_H
30
31 #include "intel_winsys.h"
32
33 #include "ilo_common.h"
34
35 struct ilo_cp;
36
37 enum ilo_cp_ring {
38 ILO_CP_RING_RENDER,
39 ILO_CP_RING_BLT,
40
41 ILO_CP_RING_COUNT,
42 };
43
44 typedef void (*ilo_cp_callback)(struct ilo_cp *cp, void *data);
45
46 struct ilo_cp_owner {
47 ilo_cp_callback release_callback;
48 void *release_data;
49 };
50
51 /**
52 * Command parser.
53 */
54 struct ilo_cp {
55 struct intel_winsys *winsys;
56 struct intel_context *render_ctx;
57
58 ilo_cp_callback flush_callback;
59 void *flush_callback_data;
60
61 const struct ilo_cp_owner *owner;
62 int owner_reserve;
63
64 enum ilo_cp_ring ring;
65 bool no_implicit_flush;
66 unsigned one_off_flags;
67
68 int bo_size;
69 struct intel_bo *bo;
70 uint32_t *sys;
71
72 uint32_t *ptr;
73 int size, used, stolen;
74
75 int cmd_cur, cmd_end;
76 };
77
78 /**
79 * Jump buffer to save command parser state for rewind.
80 */
81 struct ilo_cp_jmp_buf {
82 intptr_t id;
83 int size, used, stolen;
84 int reloc_count;
85 };
86
87 struct ilo_cp *
88 ilo_cp_create(struct intel_winsys *winsys, bool direct_map);
89
90 void
91 ilo_cp_destroy(struct ilo_cp *cp);
92
93 void
94 ilo_cp_flush_internal(struct ilo_cp *cp);
95
96 static inline void
97 ilo_cp_flush(struct ilo_cp *cp, const char *reason)
98 {
99 if (ilo_debug & ILO_DEBUG_FLUSH) {
100 ilo_printf("cp flushed for %s with %d+%d DWords (%.1f%%) because of %s\n",
101 (cp->ring == ILO_CP_RING_RENDER) ? "render" : "blt",
102 cp->used, cp->stolen,
103 (float) (100 * (cp->used + cp->stolen)) / cp->bo_size,
104 reason);
105 }
106
107 ilo_cp_flush_internal(cp);
108 }
109
110 void
111 ilo_cp_dump(struct ilo_cp *cp);
112
113 void
114 ilo_cp_setjmp(struct ilo_cp *cp, struct ilo_cp_jmp_buf *jmp);
115
116 void
117 ilo_cp_longjmp(struct ilo_cp *cp, const struct ilo_cp_jmp_buf *jmp);
118
119 /**
120 * Return true if the parser buffer is empty.
121 */
122 static inline bool
123 ilo_cp_empty(struct ilo_cp *cp)
124 {
125 return !cp->used;
126 }
127
128 /**
129 * Return the remaining space (in dwords) in the parser buffer.
130 */
131 static inline int
132 ilo_cp_space(struct ilo_cp *cp)
133 {
134 return cp->size - cp->used;
135 }
136
137 /**
138 * Internal function called by functions that flush implicitly.
139 */
140 static inline void
141 ilo_cp_implicit_flush(struct ilo_cp *cp)
142 {
143 if (cp->no_implicit_flush) {
144 assert(!"unexpected command parser flush");
145 /* discard the commands */
146 cp->used = 0;
147 }
148
149 ilo_cp_flush(cp, "out of space (implicit)");
150 }
151
152 /**
153 * Set the ring buffer.
154 */
155 static inline void
156 ilo_cp_set_ring(struct ilo_cp *cp, enum ilo_cp_ring ring)
157 {
158 if (cp->ring != ring) {
159 ilo_cp_implicit_flush(cp);
160 cp->ring = ring;
161 }
162 }
163
164 /**
165 * Assert that no function should flush implicitly.
166 */
167 static inline void
168 ilo_cp_assert_no_implicit_flush(struct ilo_cp *cp, bool enable)
169 {
170 cp->no_implicit_flush = enable;
171 }
172
173 /**
174 * Set one-off flags. They will be cleared after flushing.
175 */
176 static inline void
177 ilo_cp_set_one_off_flags(struct ilo_cp *cp, unsigned flags)
178 {
179 cp->one_off_flags |= flags;
180 }
181
182 /**
183 * Set flush callback. The callback is invoked after the bo has been
184 * successfully executed, and before the bo is reallocated.
185 */
186 static inline void
187 ilo_cp_set_flush_callback(struct ilo_cp *cp, ilo_cp_callback callback,
188 void *data)
189 {
190 cp->flush_callback = callback;
191 cp->flush_callback_data = data;
192 }
193
194 /**
195 * Set the parser owner. If this is a new owner, the previous owner is
196 * notified and the space it reserved is reclaimed.
197 *
198 * \return true if this is a new owner
199 */
200 static inline bool
201 ilo_cp_set_owner(struct ilo_cp *cp, const struct ilo_cp_owner *owner,
202 int reserve)
203 {
204 const bool new_owner = (cp->owner != owner);
205
206 /* release current owner */
207 if (new_owner && cp->owner) {
208 const bool no_implicit_flush = cp->no_implicit_flush;
209
210 /* reclaim the reserved space */
211 cp->size += cp->owner_reserve;
212 cp->owner_reserve = 0;
213
214 /* invoke the release callback */
215 cp->no_implicit_flush = true;
216 cp->owner->release_callback(cp, cp->owner->release_data);
217 cp->no_implicit_flush = no_implicit_flush;
218
219 cp->owner = NULL;
220 }
221
222 if (cp->owner_reserve != reserve) {
223 const int extra = reserve - cp->owner_reserve;
224
225 if (cp->used > cp->size - extra) {
226 ilo_cp_implicit_flush(cp);
227 assert(cp->used <= cp->size - reserve);
228
229 cp->size -= reserve;
230 cp->owner_reserve = reserve;
231 }
232 else {
233 cp->size -= extra;
234 cp->owner_reserve += extra;
235 }
236 }
237
238 /* set owner last because of the possible flush above */
239 cp->owner = owner;
240
241 return new_owner;
242 }
243
244 /**
245 * Begin writing a command.
246 */
247 static inline void
248 ilo_cp_begin(struct ilo_cp *cp, int cmd_size)
249 {
250 if (cp->used + cmd_size > cp->size) {
251 ilo_cp_implicit_flush(cp);
252 assert(cp->used + cmd_size <= cp->size);
253 }
254
255 assert(cp->cmd_cur == cp->cmd_end);
256 cp->cmd_cur = cp->used;
257 cp->cmd_end = cp->cmd_cur + cmd_size;
258 cp->used = cp->cmd_end;
259 }
260
261 /**
262 * Begin writing data to a space stolen from the top of the parser buffer.
263 *
264 * \param desc informative description of the data to be written
265 * \param data_size in dwords
266 * \param align in dwords
267 * \param bo_offset in bytes to the stolen space
268 */
269 static inline void
270 ilo_cp_steal(struct ilo_cp *cp, const char *desc,
271 int data_size, int align, uint32_t *bo_offset)
272 {
273 int pad, steal;
274
275 if (!align)
276 align = 1;
277
278 pad = (cp->bo_size - cp->stolen - data_size) % align;
279 steal = data_size + pad;
280
281 /* flush if there is not enough space after stealing */
282 if (cp->used > cp->size - steal) {
283 ilo_cp_implicit_flush(cp);
284
285 pad = (cp->bo_size - cp->stolen - data_size) % align;
286 steal = data_size + steal;
287
288 assert(cp->used <= cp->size - steal);
289 }
290
291 cp->size -= steal;
292 cp->stolen += steal;
293
294 assert(cp->cmd_cur == cp->cmd_end);
295 cp->cmd_cur = cp->bo_size - cp->stolen;
296 cp->cmd_end = cp->cmd_cur + data_size;
297
298 /* offset in cp->bo */
299 if (bo_offset)
300 *bo_offset = cp->cmd_cur * 4;
301 }
302
303 /**
304 * Write a dword to the parser buffer. This function must be enclosed by
305 * ilo_cp_begin()/ilo_cp_steal() and ilo_cp_end().
306 */
307 static inline void
308 ilo_cp_write(struct ilo_cp *cp, uint32_t val)
309 {
310 assert(cp->cmd_cur < cp->cmd_end);
311 cp->ptr[cp->cmd_cur++] = val;
312 }
313
314 /**
315 * Write multiple dwords to the parser buffer.
316 */
317 static inline void
318 ilo_cp_write_multi(struct ilo_cp *cp, const void *vals, int num_vals)
319 {
320 assert(cp->cmd_cur + num_vals <= cp->cmd_end);
321 memcpy(cp->ptr + cp->cmd_cur, vals, num_vals * 4);
322 cp->cmd_cur += num_vals;
323 }
324
325 /**
326 * Write a bo to the parser buffer. In addition to writing the offset of the
327 * bo to the buffer, it also emits a relocation.
328 */
329 static inline void
330 ilo_cp_write_bo(struct ilo_cp *cp, uint32_t val, struct intel_bo *bo,
331 uint32_t read_domains, uint32_t write_domain)
332 {
333 uint64_t presumed_offset;
334
335 if (bo) {
336 intel_bo_add_reloc(cp->bo, cp->cmd_cur * 4, bo, val,
337 read_domains, write_domain, &presumed_offset);
338 }
339 else {
340 presumed_offset = 0;
341 }
342
343 /* 32-bit addressing */
344 assert(presumed_offset == (uint64_t) ((uint32_t) presumed_offset));
345
346 ilo_cp_write(cp, (uint32_t) presumed_offset);
347 }
348
349 /**
350 * End a command. Every ilo_cp_begin() or ilo_cp_steal() must have a
351 * matching ilo_cp_end().
352 */
353 static inline void
354 ilo_cp_end(struct ilo_cp *cp)
355 {
356 assert(cp->cmd_cur == cp->cmd_end);
357 }
358
359 /**
360 * A variant of ilo_cp_steal() where the data are written via the returned
361 * pointer.
362 *
363 * \return ptr pointer where the data are written to. It is valid until any
364 * change is made to the parser.
365 */
366 static inline void *
367 ilo_cp_steal_ptr(struct ilo_cp *cp, const char *desc,
368 int data_size, int align, uint32_t *bo_offset)
369 {
370 void *ptr;
371
372 ilo_cp_steal(cp, desc, data_size, align, bo_offset);
373
374 ptr = &cp->ptr[cp->cmd_cur];
375 cp->cmd_cur = cp->cmd_end;
376
377 ilo_cp_end(cp);
378
379 return ptr;
380 }
381
382 #endif /* ILO_CP_H */