• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ilo/core/intel_winsys.h"
45 #include "intel_drm_public.h"
46 
47 struct intel_winsys {
48    int fd;
49    drm_intel_bufmgr *bufmgr;
50    struct intel_winsys_info info;
51 
52    /* these are protected by the mutex */
53    pipe_mutex mutex;
54    drm_intel_context *first_gem_ctx;
55    struct drm_intel_decode *decode;
56 };
57 
58 static drm_intel_context *
gem_ctx(const struct intel_context * ctx)59 gem_ctx(const struct intel_context *ctx)
60 {
61    return (drm_intel_context *) ctx;
62 }
63 
64 static drm_intel_bo *
gem_bo(const struct intel_bo * bo)65 gem_bo(const struct intel_bo *bo)
66 {
67    return (drm_intel_bo *) bo;
68 }
69 
70 static bool
get_param(struct intel_winsys * winsys,int param,int * value)71 get_param(struct intel_winsys *winsys, int param, int *value)
72 {
73    struct drm_i915_getparam gp;
74    int err;
75 
76    *value = 0;
77 
78    memset(&gp, 0, sizeof(gp));
79    gp.param = param;
80    gp.value = value;
81 
82    err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
83    if (err) {
84       *value = 0;
85       return false;
86    }
87 
88    return true;
89 }
90 
91 static bool
test_address_swizzling(struct intel_winsys * winsys)92 test_address_swizzling(struct intel_winsys *winsys)
93 {
94    drm_intel_bo *bo;
95    uint32_t tiling = I915_TILING_X, swizzle;
96    unsigned long pitch;
97 
98    bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
99          "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
100    if (bo) {
101       drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
102       drm_intel_bo_unreference(bo);
103    }
104    else {
105       swizzle = I915_BIT_6_SWIZZLE_NONE;
106    }
107 
108    return (swizzle != I915_BIT_6_SWIZZLE_NONE);
109 }
110 
111 static bool
test_reg_read(struct intel_winsys * winsys,uint32_t reg)112 test_reg_read(struct intel_winsys *winsys, uint32_t reg)
113 {
114    uint64_t dummy;
115 
116    return !drm_intel_reg_read(winsys->bufmgr, reg, &dummy);
117 }
118 
119 static bool
probe_winsys(struct intel_winsys * winsys)120 probe_winsys(struct intel_winsys *winsys)
121 {
122    struct intel_winsys_info *info = &winsys->info;
123    int val;
124 
125    /*
126     * When we need the Nth vertex from a user vertex buffer, and the vertex is
127     * uploaded to, say, the beginning of a bo, we want the first vertex in the
128     * bo to be fetched.  One way to do this is to set the base address of the
129     * vertex buffer to
130     *
131     *   bo->offset64 + (vb->buffer_offset - vb->stride * N).
132     *
133     * The second term may be negative, and we need kernel support to do that.
134     *
135     * This check is taken from the classic driver.  u_vbuf_upload_buffers()
136     * guarantees the term is never negative, but it is good to require a
137     * recent kernel.
138     */
139    get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
140    if (!val) {
141       debug_error("kernel 2.6.39 required");
142       return false;
143    }
144 
145    info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
146 
147    if (drm_intel_get_aperture_sizes(winsys->fd,
148          &info->aperture_mappable, &info->aperture_total)) {
149       debug_error("failed to query aperture sizes");
150       return false;
151    }
152 
153    get_param(winsys, I915_PARAM_HAS_LLC, &val);
154    info->has_llc = val;
155    info->has_address_swizzling = test_address_swizzling(winsys);
156 
157    winsys->first_gem_ctx = drm_intel_gem_context_create(winsys->bufmgr);
158    info->has_logical_context = (winsys->first_gem_ctx != NULL);
159 
160    get_param(winsys, I915_PARAM_HAS_ALIASING_PPGTT, &val);
161    info->has_ppgtt = val;
162 
163    /* test TIMESTAMP read */
164    info->has_timestamp = test_reg_read(winsys, 0x2358);
165 
166    get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
167    info->has_gen7_sol_reset = val;
168 
169    return true;
170 }
171 
172 struct intel_winsys *
intel_winsys_create_for_fd(int fd)173 intel_winsys_create_for_fd(int fd)
174 {
175    /* so that we can have enough (up to 4094) relocs per bo */
176    const int batch_size = sizeof(uint32_t) * 8192;
177    struct intel_winsys *winsys;
178 
179    winsys = CALLOC_STRUCT(intel_winsys);
180    if (!winsys)
181       return NULL;
182 
183    winsys->fd = fd;
184 
185    winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, batch_size);
186    if (!winsys->bufmgr) {
187       debug_error("failed to create GEM buffer manager");
188       FREE(winsys);
189       return NULL;
190    }
191 
192    pipe_mutex_init(winsys->mutex);
193 
194    if (!probe_winsys(winsys)) {
195       pipe_mutex_destroy(winsys->mutex);
196       drm_intel_bufmgr_destroy(winsys->bufmgr);
197       FREE(winsys);
198       return NULL;
199    }
200 
201    /*
202     * No need to implicitly set up a fence register for each non-linear reloc
203     * entry.  INTEL_RELOC_FENCE will be set on reloc entries that need them.
204     */
205    drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
206 
207    drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
208 
209    return winsys;
210 }
211 
212 void
intel_winsys_destroy(struct intel_winsys * winsys)213 intel_winsys_destroy(struct intel_winsys *winsys)
214 {
215    if (winsys->decode)
216       drm_intel_decode_context_free(winsys->decode);
217 
218    if (winsys->first_gem_ctx)
219       drm_intel_gem_context_destroy(winsys->first_gem_ctx);
220 
221    pipe_mutex_destroy(winsys->mutex);
222    drm_intel_bufmgr_destroy(winsys->bufmgr);
223    FREE(winsys);
224 }
225 
226 const struct intel_winsys_info *
intel_winsys_get_info(const struct intel_winsys * winsys)227 intel_winsys_get_info(const struct intel_winsys *winsys)
228 {
229    return &winsys->info;
230 }
231 
232 struct intel_context *
intel_winsys_create_context(struct intel_winsys * winsys)233 intel_winsys_create_context(struct intel_winsys *winsys)
234 {
235    drm_intel_context *gem_ctx;
236 
237    /* try the preallocated context first */
238    pipe_mutex_lock(winsys->mutex);
239    gem_ctx = winsys->first_gem_ctx;
240    winsys->first_gem_ctx = NULL;
241    pipe_mutex_unlock(winsys->mutex);
242 
243    if (!gem_ctx)
244       gem_ctx = drm_intel_gem_context_create(winsys->bufmgr);
245 
246    return (struct intel_context *) gem_ctx;
247 }
248 
249 void
intel_winsys_destroy_context(struct intel_winsys * winsys,struct intel_context * ctx)250 intel_winsys_destroy_context(struct intel_winsys *winsys,
251                              struct intel_context *ctx)
252 {
253    drm_intel_gem_context_destroy(gem_ctx(ctx));
254 }
255 
256 int
intel_winsys_read_reg(struct intel_winsys * winsys,uint32_t reg,uint64_t * val)257 intel_winsys_read_reg(struct intel_winsys *winsys,
258                       uint32_t reg, uint64_t *val)
259 {
260    return drm_intel_reg_read(winsys->bufmgr, reg, val);
261 }
262 
263 int
intel_winsys_get_reset_stats(struct intel_winsys * winsys,struct intel_context * ctx,uint32_t * active_lost,uint32_t * pending_lost)264 intel_winsys_get_reset_stats(struct intel_winsys *winsys,
265                              struct intel_context *ctx,
266                              uint32_t *active_lost,
267                              uint32_t *pending_lost)
268 {
269    uint32_t reset_count;
270 
271    return drm_intel_get_reset_stats(gem_ctx(ctx),
272          &reset_count, active_lost, pending_lost);
273 }
274 
275 struct intel_bo *
intel_winsys_alloc_bo(struct intel_winsys * winsys,const char * name,unsigned long size,bool cpu_init)276 intel_winsys_alloc_bo(struct intel_winsys *winsys,
277                       const char *name,
278                       unsigned long size,
279                       bool cpu_init)
280 {
281    const unsigned int alignment = 4096; /* always page-aligned */
282    drm_intel_bo *bo;
283 
284    if (cpu_init) {
285       bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
286    } else {
287       bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
288             name, size, alignment);
289    }
290 
291    return (struct intel_bo *) bo;
292 }
293 
294 struct intel_bo *
intel_winsys_import_userptr(struct intel_winsys * winsys,const char * name,void * userptr,unsigned long size,unsigned long flags)295 intel_winsys_import_userptr(struct intel_winsys *winsys,
296                             const char *name,
297                             void *userptr,
298                             unsigned long size,
299                             unsigned long flags)
300 {
301    return NULL;
302 }
303 
304 struct intel_bo *
intel_winsys_import_handle(struct intel_winsys * winsys,const char * name,const struct winsys_handle * handle,unsigned long height,enum intel_tiling_mode * tiling,unsigned long * pitch)305 intel_winsys_import_handle(struct intel_winsys *winsys,
306                            const char *name,
307                            const struct winsys_handle *handle,
308                            unsigned long height,
309                            enum intel_tiling_mode *tiling,
310                            unsigned long *pitch)
311 {
312    uint32_t real_tiling, swizzle;
313    drm_intel_bo *bo;
314    int err;
315 
316    if (handle->offset != 0) {
317       debug_error("attempt to import unsupported winsys offset");
318       return NULL;
319    }
320 
321    switch (handle->type) {
322    case DRM_API_HANDLE_TYPE_SHARED:
323       {
324          const uint32_t gem_name = handle->handle;
325          bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
326                name, gem_name);
327       }
328       break;
329    case DRM_API_HANDLE_TYPE_FD:
330       {
331          const int fd = (int) handle->handle;
332          bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
333                fd, height * handle->stride);
334       }
335       break;
336    default:
337       bo = NULL;
338       break;
339    }
340 
341    if (!bo)
342       return NULL;
343 
344    err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
345    if (err) {
346       drm_intel_bo_unreference(bo);
347       return NULL;
348    }
349 
350    *tiling = real_tiling;
351    *pitch = handle->stride;
352 
353    return (struct intel_bo *) bo;
354 }
355 
356 int
intel_winsys_export_handle(struct intel_winsys * winsys,struct intel_bo * bo,enum intel_tiling_mode tiling,unsigned long pitch,unsigned long height,struct winsys_handle * handle)357 intel_winsys_export_handle(struct intel_winsys *winsys,
358                            struct intel_bo *bo,
359                            enum intel_tiling_mode tiling,
360                            unsigned long pitch,
361                            unsigned long height,
362                            struct winsys_handle *handle)
363 {
364    int err = 0;
365 
366    switch (handle->type) {
367    case DRM_API_HANDLE_TYPE_SHARED:
368       {
369          uint32_t name;
370 
371          err = drm_intel_bo_flink(gem_bo(bo), &name);
372          if (!err)
373             handle->handle = name;
374       }
375       break;
376    case DRM_API_HANDLE_TYPE_KMS:
377       handle->handle = gem_bo(bo)->handle;
378       break;
379    case DRM_API_HANDLE_TYPE_FD:
380       {
381          int fd;
382 
383          err = drm_intel_bo_gem_export_to_prime(gem_bo(bo), &fd);
384          if (!err)
385             handle->handle = fd;
386       }
387       break;
388    default:
389       err = -EINVAL;
390       break;
391    }
392 
393    if (err)
394       return err;
395 
396    handle->stride = pitch;
397 
398    return 0;
399 }
400 
401 bool
intel_winsys_can_submit_bo(struct intel_winsys * winsys,struct intel_bo ** bo_array,int count)402 intel_winsys_can_submit_bo(struct intel_winsys *winsys,
403                            struct intel_bo **bo_array,
404                            int count)
405 {
406    return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
407                                                  count);
408 }
409 
410 int
intel_winsys_submit_bo(struct intel_winsys * winsys,enum intel_ring_type ring,struct intel_bo * bo,int used,struct intel_context * ctx,unsigned long flags)411 intel_winsys_submit_bo(struct intel_winsys *winsys,
412                        enum intel_ring_type ring,
413                        struct intel_bo *bo, int used,
414                        struct intel_context *ctx,
415                        unsigned long flags)
416 {
417    const unsigned long exec_flags = (unsigned long) ring | flags;
418 
419    /* logical contexts are only available for the render ring */
420    if (ring != INTEL_RING_RENDER)
421       ctx = NULL;
422 
423    if (ctx) {
424       return drm_intel_gem_bo_context_exec(gem_bo(bo),
425             (drm_intel_context *) ctx, used, exec_flags);
426    }
427    else {
428       return drm_intel_bo_mrb_exec(gem_bo(bo),
429             used, NULL, 0, 0, exec_flags);
430    }
431 }
432 
433 void
intel_winsys_decode_bo(struct intel_winsys * winsys,struct intel_bo * bo,int used)434 intel_winsys_decode_bo(struct intel_winsys *winsys,
435                        struct intel_bo *bo, int used)
436 {
437    void *ptr;
438 
439    ptr = intel_bo_map(bo, false);
440    if (!ptr) {
441       debug_printf("failed to map buffer for decoding\n");
442       return;
443    }
444 
445    pipe_mutex_lock(winsys->mutex);
446 
447    if (!winsys->decode) {
448       winsys->decode = drm_intel_decode_context_alloc(winsys->info.devid);
449       if (!winsys->decode) {
450          pipe_mutex_unlock(winsys->mutex);
451          intel_bo_unmap(bo);
452          return;
453       }
454 
455       /* debug_printf()/debug_error() uses stderr by default */
456       drm_intel_decode_set_output_file(winsys->decode, stderr);
457    }
458 
459    /* in dwords */
460    used /= 4;
461 
462    drm_intel_decode_set_batch_pointer(winsys->decode,
463          ptr, gem_bo(bo)->offset64, used);
464 
465    drm_intel_decode(winsys->decode);
466 
467    pipe_mutex_unlock(winsys->mutex);
468 
469    intel_bo_unmap(bo);
470 }
471 
472 struct intel_bo *
intel_bo_ref(struct intel_bo * bo)473 intel_bo_ref(struct intel_bo *bo)
474 {
475    if (bo)
476       drm_intel_bo_reference(gem_bo(bo));
477 
478    return bo;
479 }
480 
481 void
intel_bo_unref(struct intel_bo * bo)482 intel_bo_unref(struct intel_bo *bo)
483 {
484    if (bo)
485       drm_intel_bo_unreference(gem_bo(bo));
486 }
487 
488 int
intel_bo_set_tiling(struct intel_bo * bo,enum intel_tiling_mode tiling,unsigned long pitch)489 intel_bo_set_tiling(struct intel_bo *bo,
490                     enum intel_tiling_mode tiling,
491                     unsigned long pitch)
492 {
493    uint32_t real_tiling = tiling;
494    int err;
495 
496    switch (tiling) {
497    case INTEL_TILING_X:
498       if (pitch % 512)
499          return -1;
500       break;
501    case INTEL_TILING_Y:
502       if (pitch % 128)
503          return -1;
504       break;
505    default:
506       break;
507    }
508 
509    err = drm_intel_bo_set_tiling(gem_bo(bo), &real_tiling, pitch);
510    if (err || real_tiling != tiling) {
511       assert(!"tiling mismatch");
512       return -1;
513    }
514 
515    return 0;
516 }
517 
518 void *
intel_bo_map(struct intel_bo * bo,bool write_enable)519 intel_bo_map(struct intel_bo *bo, bool write_enable)
520 {
521    int err;
522 
523    err = drm_intel_bo_map(gem_bo(bo), write_enable);
524    if (err) {
525       debug_error("failed to map bo");
526       return NULL;
527    }
528 
529    return gem_bo(bo)->virtual;
530 }
531 
532 void *
intel_bo_map_async(struct intel_bo * bo)533 intel_bo_map_async(struct intel_bo *bo)
534 {
535    return NULL;
536 }
537 
538 void *
intel_bo_map_gtt(struct intel_bo * bo)539 intel_bo_map_gtt(struct intel_bo *bo)
540 {
541    int err;
542 
543    err = drm_intel_gem_bo_map_gtt(gem_bo(bo));
544    if (err) {
545       debug_error("failed to map bo");
546       return NULL;
547    }
548 
549    return gem_bo(bo)->virtual;
550 }
551 
552 void *
intel_bo_map_gtt_async(struct intel_bo * bo)553 intel_bo_map_gtt_async(struct intel_bo *bo)
554 {
555    int err;
556 
557    err = drm_intel_gem_bo_map_unsynchronized(gem_bo(bo));
558    if (err) {
559       debug_error("failed to map bo");
560       return NULL;
561    }
562 
563    return gem_bo(bo)->virtual;
564 }
565 
566 void
intel_bo_unmap(struct intel_bo * bo)567 intel_bo_unmap(struct intel_bo *bo)
568 {
569    int err;
570 
571    err = drm_intel_bo_unmap(gem_bo(bo));
572    assert(!err);
573 }
574 
575 int
intel_bo_pwrite(struct intel_bo * bo,unsigned long offset,unsigned long size,const void * data)576 intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
577                 unsigned long size, const void *data)
578 {
579    return drm_intel_bo_subdata(gem_bo(bo), offset, size, data);
580 }
581 
582 int
intel_bo_pread(struct intel_bo * bo,unsigned long offset,unsigned long size,void * data)583 intel_bo_pread(struct intel_bo *bo, unsigned long offset,
584                unsigned long size, void *data)
585 {
586    return drm_intel_bo_get_subdata(gem_bo(bo), offset, size, data);
587 }
588 
589 int
intel_bo_add_reloc(struct intel_bo * bo,uint32_t offset,struct intel_bo * target_bo,uint32_t target_offset,uint32_t flags,uint64_t * presumed_offset)590 intel_bo_add_reloc(struct intel_bo *bo, uint32_t offset,
591                    struct intel_bo *target_bo, uint32_t target_offset,
592                    uint32_t flags, uint64_t *presumed_offset)
593 {
594    uint32_t read_domains, write_domain;
595    int err;
596 
597    if (flags & INTEL_RELOC_WRITE) {
598       /*
599        * Because of the translation to domains, INTEL_RELOC_GGTT should only
600        * be set on GEN6 when the bo is written by MI_* or PIPE_CONTROL.  The
601        * kernel will translate it back to INTEL_RELOC_GGTT.
602        */
603       write_domain = (flags & INTEL_RELOC_GGTT) ?
604          I915_GEM_DOMAIN_INSTRUCTION : I915_GEM_DOMAIN_RENDER;
605       read_domains = write_domain;
606    } else {
607       write_domain = 0;
608       read_domains = I915_GEM_DOMAIN_RENDER |
609                      I915_GEM_DOMAIN_SAMPLER |
610                      I915_GEM_DOMAIN_INSTRUCTION |
611                      I915_GEM_DOMAIN_VERTEX;
612    }
613 
614    if (flags & INTEL_RELOC_FENCE) {
615       err = drm_intel_bo_emit_reloc_fence(gem_bo(bo), offset,
616             gem_bo(target_bo), target_offset,
617             read_domains, write_domain);
618    } else {
619       err = drm_intel_bo_emit_reloc(gem_bo(bo), offset,
620             gem_bo(target_bo), target_offset,
621             read_domains, write_domain);
622    }
623 
624    *presumed_offset = gem_bo(target_bo)->offset64 + target_offset;
625 
626    return err;
627 }
628 
629 int
intel_bo_get_reloc_count(struct intel_bo * bo)630 intel_bo_get_reloc_count(struct intel_bo *bo)
631 {
632    return drm_intel_gem_bo_get_reloc_count(gem_bo(bo));
633 }
634 
635 void
intel_bo_truncate_relocs(struct intel_bo * bo,int start)636 intel_bo_truncate_relocs(struct intel_bo *bo, int start)
637 {
638    drm_intel_gem_bo_clear_relocs(gem_bo(bo), start);
639 }
640 
641 bool
intel_bo_has_reloc(struct intel_bo * bo,struct intel_bo * target_bo)642 intel_bo_has_reloc(struct intel_bo *bo, struct intel_bo *target_bo)
643 {
644    return drm_intel_bo_references(gem_bo(bo), gem_bo(target_bo));
645 }
646 
647 int
intel_bo_wait(struct intel_bo * bo,int64_t timeout)648 intel_bo_wait(struct intel_bo *bo, int64_t timeout)
649 {
650    int err;
651 
652    if (timeout >= 0) {
653       err = drm_intel_gem_bo_wait(gem_bo(bo), timeout);
654    } else {
655       drm_intel_bo_wait_rendering(gem_bo(bo));
656       err = 0;
657    }
658 
659    /* consider the bo idle on errors */
660    if (err && err != -ETIME)
661       err = 0;
662 
663    return err;
664 }
665