ilo: set I915_EXEC_NO_RELOC when available
[mesa.git] / src / gallium / winsys / intel / drm / intel_drm_winsys.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2014 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 #include <string.h>
29 #include <errno.h>
30 #ifndef ETIME
31 #define ETIME ETIMEDOUT
32 #endif
33
34 #include <xf86drm.h>
35 #include <i915_drm.h>
36 #include <intel_bufmgr.h>
37
38 #include "state_tracker/drm_driver.h"
39 #include "pipe/p_state.h"
40 #include "util/u_inlines.h"
41 #include "util/u_memory.h"
42 #include "util/u_debug.h"
43 #include "../intel_winsys.h"
44
45 #define BATCH_SZ (8192 * sizeof(uint32_t))
46
47 struct intel_winsys {
48 int fd;
49 drm_intel_bufmgr *bufmgr;
50 struct intel_winsys_info info;
51 unsigned long exec_flags;
52
53 struct drm_intel_decode *decode;
54 };
55
56 static drm_intel_bo *
57 gem_bo(const struct intel_bo *bo)
58 {
59 return (drm_intel_bo *) bo;
60 }
61
62 static bool
63 get_param(struct intel_winsys *winsys, int param, int *value)
64 {
65 struct drm_i915_getparam gp;
66 int err;
67
68 *value = 0;
69
70 memset(&gp, 0, sizeof(gp));
71 gp.param = param;
72 gp.value = value;
73
74 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
75 if (err) {
76 *value = 0;
77 return false;
78 }
79
80 return true;
81 }
82
83 static bool
84 test_address_swizzling(struct intel_winsys *winsys)
85 {
86 drm_intel_bo *bo;
87 uint32_t tiling = I915_TILING_X, swizzle;
88 unsigned long pitch;
89
90 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
91 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
92 if (bo) {
93 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
94 drm_intel_bo_unreference(bo);
95 }
96 else {
97 swizzle = I915_BIT_6_SWIZZLE_NONE;
98 }
99
100 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
101 }
102
103 static bool
104 test_reg_read(struct intel_winsys *winsys, uint32_t reg)
105 {
106 uint64_t dummy;
107
108 return !drm_intel_reg_read(winsys->bufmgr, reg, &dummy);
109 }
110
111 static bool
112 probe_winsys(struct intel_winsys *winsys)
113 {
114 struct intel_winsys_info *info = &winsys->info;
115 int val;
116
117 /*
118 * When we need the Nth vertex from a user vertex buffer, and the vertex is
119 * uploaded to, say, the beginning of a bo, we want the first vertex in the
120 * bo to be fetched. One way to do this is to set the base address of the
121 * vertex buffer to
122 *
123 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
124 *
125 * The second term may be negative, and we need kernel support to do that.
126 *
127 * This check is taken from the classic driver. u_vbuf_upload_buffers()
128 * guarantees the term is never negative, but it is good to require a
129 * recent kernel.
130 */
131 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
132 if (!val) {
133 debug_error("kernel 2.6.39 required");
134 return false;
135 }
136
137 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
138
139 info->max_batch_size = BATCH_SZ;
140
141 get_param(winsys, I915_PARAM_HAS_LLC, &val);
142 info->has_llc = val;
143 info->has_address_swizzling = test_address_swizzling(winsys);
144
145 /* test TIMESTAMP read */
146 info->has_timestamp = test_reg_read(winsys, 0x2358);
147
148 get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
149 info->has_gen7_sol_reset = val;
150
151 /*
152 * pipe drivers are expected to write the presumed offsets after adding
153 * reloc entries
154 */
155 get_param(winsys, I915_PARAM_HAS_EXEC_NO_RELOC, &val);
156 if (val)
157 winsys->exec_flags |= I915_EXEC_NO_RELOC;
158
159 return true;
160 }
161
162 struct intel_winsys *
163 intel_winsys_create_for_fd(int fd)
164 {
165 struct intel_winsys *winsys;
166
167 winsys = CALLOC_STRUCT(intel_winsys);
168 if (!winsys)
169 return NULL;
170
171 winsys->fd = fd;
172
173 winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, BATCH_SZ);
174 if (!winsys->bufmgr) {
175 debug_error("failed to create GEM buffer manager");
176 FREE(winsys);
177 return NULL;
178 }
179
180 if (!probe_winsys(winsys)) {
181 drm_intel_bufmgr_destroy(winsys->bufmgr);
182 FREE(winsys);
183 return NULL;
184 }
185
186 /*
187 * No need to implicitly set up a fence register for each non-linear reloc
188 * entry. When a fence register is needed for a reloc entry,
189 * drm_intel_bo_emit_reloc_fence() will be called explicitly.
190 *
191 * intel_bo_add_reloc() currently lacks "bool fenced" for this to work.
192 * But we never need a fence register on GEN4+ so we do not need to worry
193 * about it yet.
194 */
195 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
196
197 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
198
199 return winsys;
200 }
201
202 void
203 intel_winsys_destroy(struct intel_winsys *winsys)
204 {
205 if (winsys->decode)
206 drm_intel_decode_context_free(winsys->decode);
207
208 drm_intel_bufmgr_destroy(winsys->bufmgr);
209 FREE(winsys);
210 }
211
212 const struct intel_winsys_info *
213 intel_winsys_get_info(const struct intel_winsys *winsys)
214 {
215 return &winsys->info;
216 }
217
218 struct intel_context *
219 intel_winsys_create_context(struct intel_winsys *winsys)
220 {
221 return (struct intel_context *)
222 drm_intel_gem_context_create(winsys->bufmgr);
223 }
224
225 void
226 intel_winsys_destroy_context(struct intel_winsys *winsys,
227 struct intel_context *ctx)
228 {
229 drm_intel_gem_context_destroy((drm_intel_context *) ctx);
230 }
231
232 int
233 intel_winsys_read_reg(struct intel_winsys *winsys,
234 uint32_t reg, uint64_t *val)
235 {
236 return drm_intel_reg_read(winsys->bufmgr, reg, val);
237 }
238
239 struct intel_bo *
240 intel_winsys_alloc_buffer(struct intel_winsys *winsys,
241 const char *name,
242 unsigned long size,
243 uint32_t initial_domain)
244 {
245 const bool for_render =
246 (initial_domain & (INTEL_DOMAIN_RENDER | INTEL_DOMAIN_INSTRUCTION));
247 const int alignment = 4096; /* always page-aligned */
248 drm_intel_bo *bo;
249
250 if (for_render) {
251 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
252 name, size, alignment);
253 }
254 else {
255 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
256 }
257
258 return (struct intel_bo *) bo;
259 }
260
261 struct intel_bo *
262 intel_winsys_alloc_texture(struct intel_winsys *winsys,
263 const char *name,
264 int width, int height, int cpp,
265 enum intel_tiling_mode tiling,
266 uint32_t initial_domain,
267 unsigned long *pitch)
268 {
269 const unsigned long flags =
270 (initial_domain & (INTEL_DOMAIN_RENDER | INTEL_DOMAIN_INSTRUCTION)) ?
271 BO_ALLOC_FOR_RENDER : 0;
272 uint32_t real_tiling = tiling;
273 drm_intel_bo *bo;
274
275 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr, name,
276 width, height, cpp, &real_tiling, pitch, flags);
277 if (!bo)
278 return NULL;
279
280 if (real_tiling != tiling) {
281 assert(!"tiling mismatch");
282 drm_intel_bo_unreference(bo);
283 return NULL;
284 }
285
286 return (struct intel_bo *) bo;
287 }
288
289 struct intel_bo *
290 intel_winsys_import_handle(struct intel_winsys *winsys,
291 const char *name,
292 const struct winsys_handle *handle,
293 int width, int height, int cpp,
294 enum intel_tiling_mode *tiling,
295 unsigned long *pitch)
296 {
297 uint32_t real_tiling, swizzle;
298 drm_intel_bo *bo;
299 int err;
300
301 switch (handle->type) {
302 case DRM_API_HANDLE_TYPE_SHARED:
303 {
304 const uint32_t gem_name = handle->handle;
305 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
306 name, gem_name);
307 }
308 break;
309 case DRM_API_HANDLE_TYPE_FD:
310 {
311 const int fd = (int) handle->handle;
312 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
313 fd, height * handle->stride);
314 }
315 break;
316 default:
317 bo = NULL;
318 break;
319 }
320
321 if (!bo)
322 return NULL;
323
324 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
325 if (err) {
326 drm_intel_bo_unreference(bo);
327 return NULL;
328 }
329
330 *tiling = real_tiling;
331 *pitch = handle->stride;
332
333 return (struct intel_bo *) bo;
334 }
335
336 int
337 intel_winsys_export_handle(struct intel_winsys *winsys,
338 struct intel_bo *bo,
339 enum intel_tiling_mode tiling,
340 unsigned long pitch,
341 struct winsys_handle *handle)
342 {
343 int err = 0;
344
345 switch (handle->type) {
346 case DRM_API_HANDLE_TYPE_SHARED:
347 {
348 uint32_t name;
349
350 err = drm_intel_bo_flink(gem_bo(bo), &name);
351 if (!err)
352 handle->handle = name;
353 }
354 break;
355 case DRM_API_HANDLE_TYPE_KMS:
356 handle->handle = gem_bo(bo)->handle;
357 break;
358 case DRM_API_HANDLE_TYPE_FD:
359 {
360 int fd;
361
362 err = drm_intel_bo_gem_export_to_prime(gem_bo(bo), &fd);
363 if (!err)
364 handle->handle = fd;
365 }
366 break;
367 default:
368 err = -EINVAL;
369 break;
370 }
371
372 if (err)
373 return err;
374
375 handle->stride = pitch;
376
377 return 0;
378 }
379
380 bool
381 intel_winsys_can_submit_bo(struct intel_winsys *winsys,
382 struct intel_bo **bo_array,
383 int count)
384 {
385 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
386 count);
387 }
388
389 int
390 intel_winsys_submit_bo(struct intel_winsys *winsys,
391 enum intel_ring_type ring,
392 struct intel_bo *bo, int used,
393 struct intel_context *ctx,
394 unsigned long flags)
395 {
396 const unsigned long exec_flags =
397 winsys->exec_flags | (unsigned long) ring | flags;
398
399 /* logical contexts are only available for the render ring */
400 if (ring != INTEL_RING_RENDER)
401 ctx = NULL;
402
403 if (ctx) {
404 return drm_intel_gem_bo_context_exec(gem_bo(bo),
405 (drm_intel_context *) ctx, used, exec_flags);
406 }
407 else {
408 return drm_intel_bo_mrb_exec(gem_bo(bo),
409 used, NULL, 0, 0, exec_flags);
410 }
411 }
412
413 void
414 intel_winsys_decode_bo(struct intel_winsys *winsys,
415 struct intel_bo *bo, int used)
416 {
417 void *ptr;
418
419 if (!winsys->decode) {
420 winsys->decode = drm_intel_decode_context_alloc(winsys->info.devid);
421 if (!winsys->decode)
422 return;
423
424 /* debug_printf()/debug_error() uses stderr by default */
425 drm_intel_decode_set_output_file(winsys->decode, stderr);
426 }
427
428 ptr = intel_bo_map(bo, false);
429 if (!ptr) {
430 debug_printf("failed to map buffer for decoding\n");
431 return;
432 }
433
434 /* in dwords */
435 used /= 4;
436
437 drm_intel_decode_set_batch_pointer(winsys->decode,
438 ptr, gem_bo(bo)->offset64, used);
439
440 drm_intel_decode(winsys->decode);
441
442 intel_bo_unmap(bo);
443 }
444
445 void
446 intel_bo_reference(struct intel_bo *bo)
447 {
448 drm_intel_bo_reference(gem_bo(bo));
449 }
450
451 void
452 intel_bo_unreference(struct intel_bo *bo)
453 {
454 drm_intel_bo_unreference(gem_bo(bo));
455 }
456
457 void *
458 intel_bo_map(struct intel_bo *bo, bool write_enable)
459 {
460 int err;
461
462 err = drm_intel_bo_map(gem_bo(bo), write_enable);
463 if (err) {
464 debug_error("failed to map bo");
465 return NULL;
466 }
467
468 return gem_bo(bo)->virtual;
469 }
470
471 void *
472 intel_bo_map_gtt(struct intel_bo *bo)
473 {
474 int err;
475
476 err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
477 if (err) {
478 debug_error("failed to map bo");
479 return NULL;
480 }
481
482 return gem_bo(bo)->virtual;
483 }
484
485 void *
486 intel_bo_map_unsynchronized(struct intel_bo *bo)
487 {
488 int err;
489
490 err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
491 if (err) {
492 debug_error("failed to map bo");
493 return NULL;
494 }
495
496 return gem_bo(bo)->virtual;
497 }
498
499 void
500 intel_bo_unmap(struct intel_bo *bo)
501 {
502 int err;
503
504 err = drm_intel_bo_unmap(gem_bo(bo));
505 assert(!err);
506 }
507
508 int
509 intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
510 unsigned long size, const void *data)
511 {
512 return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
513 }
514
515 int
516 intel_bo_pread(struct intel_bo *bo, unsigned long offset,
517 unsigned long size, void *data)
518 {
519 return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
520 }
521
522 int
523 intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
524 struct intel_bo *target_bo, uint32_t target_offset,
525 uint32_t read_domains, uint32_t write_domain,
526 uint64_t *presumed_offset)
527 {
528 int err;
529
530 err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
531 gem_bo(target_bo), target_offset,
532 read_domains, write_domain);
533
534 *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
535
536 return err;
537 }
538
539 int
540 intel_bo_get_reloc_count(struct intel_bo *bo)
541 {
542 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
543 }
544
545 void
546 intel_bo_truncate_relocs(struct intel_bo *bo, int start)
547 {
548 drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
549 }
550
551 bool
552 intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
553 {
554 return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
555 }
556
557 int
558 intel_bo_wait(struct intel_bo *bo, int64_t timeout)
559 {
560 int err;
561
562 err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
563 /* consider the bo idle on errors */
564 if (err && err != -ETIME)
565 err = 0;
566
567 return err;
568 }