Home | History | Annotate | Download | only in drm
      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 (at) 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 *
     59 gem_ctx(const struct intel_context *ctx)
     60 {
     61    return (drm_intel_context *) ctx;
     62 }
     63 
     64 static drm_intel_bo *
     65 gem_bo(const struct intel_bo *bo)
     66 {
     67    return (drm_intel_bo *) bo;
     68 }
     69 
     70 static bool
     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
     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
    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
    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 *
    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
    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 *
    227 intel_winsys_get_info(const struct intel_winsys *winsys)
    228 {
    229    return &winsys->info;
    230 }
    231 
    232 struct intel_context *
    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
    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
    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
    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 *
    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 *
    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 *
    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
    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
    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
    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
    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 *
    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
    482 intel_bo_unref(struct intel_bo *bo)
    483 {
    484    if (bo)
    485       drm_intel_bo_unreference(gem_bo(bo));
    486 }
    487 
    488 int
    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 *
    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 *
    533 intel_bo_map_async(struct intel_bo *bo)
    534 {
    535    return NULL;
    536 }
    537 
    538 void *
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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