Home | History | Annotate | Download | only in nouveau
      1 #include "pipe/p_defines.h"
      2 #include "pipe/p_screen.h"
      3 #include "pipe/p_state.h"
      4 
      5 #include "util/u_memory.h"
      6 #include "util/u_inlines.h"
      7 #include "util/u_format.h"
      8 #include "util/u_format_s3tc.h"
      9 #include "util/u_string.h"
     10 
     11 #include "os/os_time.h"
     12 
     13 #include <stdio.h>
     14 #include <errno.h>
     15 #include <stdlib.h>
     16 
     17 #include <nouveau_drm.h>
     18 
     19 #include "nouveau_winsys.h"
     20 #include "nouveau_screen.h"
     21 #include "nouveau_context.h"
     22 #include "nouveau_fence.h"
     23 #include "nouveau_mm.h"
     24 #include "nouveau_buffer.h"
     25 
     26 /* XXX this should go away */
     27 #include "state_tracker/drm_driver.h"
     28 
     29 int nouveau_mesa_debug = 0;
     30 
     31 static const char *
     32 nouveau_screen_get_name(struct pipe_screen *pscreen)
     33 {
     34    struct nouveau_device *dev = nouveau_screen(pscreen)->device;
     35    static char buffer[128];
     36 
     37    util_snprintf(buffer, sizeof(buffer), "NV%02X", dev->chipset);
     38    return buffer;
     39 }
     40 
     41 static const char *
     42 nouveau_screen_get_vendor(struct pipe_screen *pscreen)
     43 {
     44    return "nouveau";
     45 }
     46 
     47 static const char *
     48 nouveau_screen_get_device_vendor(struct pipe_screen *pscreen)
     49 {
     50    return "NVIDIA";
     51 }
     52 
     53 static uint64_t
     54 nouveau_screen_get_timestamp(struct pipe_screen *pscreen)
     55 {
     56    int64_t cpu_time = os_time_get() * 1000;
     57 
     58    /* getparam of PTIMER_TIME takes about x10 as long (several usecs) */
     59 
     60    return cpu_time + nouveau_screen(pscreen)->cpu_gpu_time_delta;
     61 }
     62 
     63 static void
     64 nouveau_screen_fence_ref(struct pipe_screen *pscreen,
     65                          struct pipe_fence_handle **ptr,
     66                          struct pipe_fence_handle *pfence)
     67 {
     68    nouveau_fence_ref(nouveau_fence(pfence), (struct nouveau_fence **)ptr);
     69 }
     70 
     71 static boolean
     72 nouveau_screen_fence_finish(struct pipe_screen *screen,
     73                             struct pipe_context *ctx,
     74                             struct pipe_fence_handle *pfence,
     75                             uint64_t timeout)
     76 {
     77    if (!timeout)
     78       return nouveau_fence_signalled(nouveau_fence(pfence));
     79 
     80    return nouveau_fence_wait(nouveau_fence(pfence), NULL);
     81 }
     82 
     83 
     84 struct nouveau_bo *
     85 nouveau_screen_bo_from_handle(struct pipe_screen *pscreen,
     86                               struct winsys_handle *whandle,
     87                               unsigned *out_stride)
     88 {
     89    struct nouveau_device *dev = nouveau_screen(pscreen)->device;
     90    struct nouveau_bo *bo = 0;
     91    int ret;
     92 
     93    if (whandle->offset != 0) {
     94       debug_printf("%s: attempt to import unsupported winsys offset %d\n",
     95                    __FUNCTION__, whandle->offset);
     96       return NULL;
     97    }
     98 
     99    if (whandle->type != DRM_API_HANDLE_TYPE_SHARED &&
    100        whandle->type != DRM_API_HANDLE_TYPE_FD) {
    101       debug_printf("%s: attempt to import unsupported handle type %d\n",
    102                    __FUNCTION__, whandle->type);
    103       return NULL;
    104    }
    105 
    106    if (whandle->type == DRM_API_HANDLE_TYPE_SHARED)
    107       ret = nouveau_bo_name_ref(dev, whandle->handle, &bo);
    108    else
    109       ret = nouveau_bo_prime_handle_ref(dev, whandle->handle, &bo);
    110 
    111    if (ret) {
    112       debug_printf("%s: ref name 0x%08x failed with %d\n",
    113                    __FUNCTION__, whandle->handle, ret);
    114       return NULL;
    115    }
    116 
    117    *out_stride = whandle->stride;
    118    return bo;
    119 }
    120 
    121 
    122 bool
    123 nouveau_screen_bo_get_handle(struct pipe_screen *pscreen,
    124                              struct nouveau_bo *bo,
    125                              unsigned stride,
    126                              struct winsys_handle *whandle)
    127 {
    128    whandle->stride = stride;
    129 
    130    if (whandle->type == DRM_API_HANDLE_TYPE_SHARED) {
    131       return nouveau_bo_name_get(bo, &whandle->handle) == 0;
    132    } else if (whandle->type == DRM_API_HANDLE_TYPE_KMS) {
    133       whandle->handle = bo->handle;
    134       return true;
    135    } else if (whandle->type == DRM_API_HANDLE_TYPE_FD) {
    136       return nouveau_bo_set_prime(bo, (int *)&whandle->handle) == 0;
    137    } else {
    138       return false;
    139    }
    140 }
    141 
    142 int
    143 nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
    144 {
    145    struct pipe_screen *pscreen = &screen->base;
    146    struct nv04_fifo nv04_data = { .vram = 0xbeef0201, .gart = 0xbeef0202 };
    147    struct nvc0_fifo nvc0_data = { };
    148    uint64_t time;
    149    int size, ret;
    150    void *data;
    151    union nouveau_bo_config mm_config;
    152 
    153    char *nv_dbg = getenv("NOUVEAU_MESA_DEBUG");
    154    if (nv_dbg)
    155       nouveau_mesa_debug = atoi(nv_dbg);
    156 
    157    /* These must be set before any failure is possible, as the cleanup
    158     * paths assume they're responsible for deleting them.
    159     */
    160    screen->drm = nouveau_drm(&dev->object);
    161    screen->device = dev;
    162 
    163    /*
    164     * this is initialized to 1 in nouveau_drm_screen_create after screen
    165     * is fully constructed and added to the global screen list.
    166     */
    167    screen->refcount = -1;
    168 
    169    if (dev->chipset < 0xc0) {
    170       data = &nv04_data;
    171       size = sizeof(nv04_data);
    172    } else {
    173       data = &nvc0_data;
    174       size = sizeof(nvc0_data);
    175    }
    176 
    177    /*
    178     * Set default VRAM domain if not overridden
    179     */
    180    if (!screen->vram_domain) {
    181       if (dev->vram_size > 0)
    182          screen->vram_domain = NOUVEAU_BO_VRAM;
    183       else
    184          screen->vram_domain = NOUVEAU_BO_GART;
    185    }
    186 
    187    ret = nouveau_object_new(&dev->object, 0, NOUVEAU_FIFO_CHANNEL_CLASS,
    188                             data, size, &screen->channel);
    189    if (ret)
    190       return ret;
    191 
    192    ret = nouveau_client_new(screen->device, &screen->client);
    193    if (ret)
    194       return ret;
    195    ret = nouveau_pushbuf_new(screen->client, screen->channel,
    196                              4, 512 * 1024, 1,
    197                              &screen->pushbuf);
    198    if (ret)
    199       return ret;
    200 
    201    /* getting CPU time first appears to be more accurate */
    202    screen->cpu_gpu_time_delta = os_time_get();
    203 
    204    ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_PTIMER_TIME, &time);
    205    if (!ret)
    206       screen->cpu_gpu_time_delta = time - screen->cpu_gpu_time_delta * 1000;
    207 
    208    pscreen->get_name = nouveau_screen_get_name;
    209    pscreen->get_vendor = nouveau_screen_get_vendor;
    210    pscreen->get_device_vendor = nouveau_screen_get_device_vendor;
    211 
    212    pscreen->get_timestamp = nouveau_screen_get_timestamp;
    213 
    214    pscreen->fence_reference = nouveau_screen_fence_ref;
    215    pscreen->fence_finish = nouveau_screen_fence_finish;
    216 
    217    util_format_s3tc_init();
    218 
    219    screen->lowmem_bindings = PIPE_BIND_GLOBAL; /* gallium limit */
    220    screen->vidmem_bindings =
    221       PIPE_BIND_RENDER_TARGET | PIPE_BIND_DEPTH_STENCIL |
    222       PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT |
    223       PIPE_BIND_CURSOR |
    224       PIPE_BIND_SAMPLER_VIEW |
    225       PIPE_BIND_SHADER_BUFFER | PIPE_BIND_SHADER_IMAGE |
    226       PIPE_BIND_COMPUTE_RESOURCE |
    227       PIPE_BIND_GLOBAL;
    228    screen->sysmem_bindings =
    229       PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_STREAM_OUTPUT |
    230       PIPE_BIND_COMMAND_ARGS_BUFFER;
    231 
    232    memset(&mm_config, 0, sizeof(mm_config));
    233 
    234    screen->mm_GART = nouveau_mm_create(dev,
    235                                        NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
    236                                        &mm_config);
    237    screen->mm_VRAM = nouveau_mm_create(dev, NOUVEAU_BO_VRAM, &mm_config);
    238    return 0;
    239 }
    240 
    241 void
    242 nouveau_screen_fini(struct nouveau_screen *screen)
    243 {
    244    int fd = screen->drm->fd;
    245 
    246    nouveau_mm_destroy(screen->mm_GART);
    247    nouveau_mm_destroy(screen->mm_VRAM);
    248 
    249    nouveau_pushbuf_del(&screen->pushbuf);
    250 
    251    nouveau_client_del(&screen->client);
    252    nouveau_object_del(&screen->channel);
    253 
    254    nouveau_device_del(&screen->device);
    255    nouveau_drm_del(&screen->drm);
    256    close(fd);
    257 }
    258 
    259 static void
    260 nouveau_set_debug_callback(struct pipe_context *pipe,
    261                            const struct pipe_debug_callback *cb)
    262 {
    263    struct nouveau_context *context = nouveau_context(pipe);
    264 
    265    if (cb)
    266       context->debug = *cb;
    267    else
    268       memset(&context->debug, 0, sizeof(context->debug));
    269 }
    270 
    271 void
    272 nouveau_context_init(struct nouveau_context *context)
    273 {
    274    context->pipe.set_debug_callback = nouveau_set_debug_callback;
    275 }
    276