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