Home | History | Annotate | Download | only in src
      1 /**************************************************************************
      2  *
      3  * Copyright (C) 2014 Red Hat Inc.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the "Software"),
      7  * to deal in the Software without restriction, including without limitation
      8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      9  * and/or sell copies of the Software, and to permit persons to whom the
     10  * Software is furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be included
     13  * in all copies or substantial portions of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     21  * OTHER DEALINGS IN THE SOFTWARE.
     22  *
     23  **************************************************************************/
     24 
     25 #include <stdio.h>
     26 #include <time.h>
     27 
     28 #include <epoxy/gl.h>
     29 
     30 #include <sys/stat.h>
     31 #include <fcntl.h>
     32 #include <errno.h>
     33 #include <unistd.h>
     34 #include "pipe/p_state.h"
     35 #include "util/u_format.h"
     36 #include "util/u_math.h"
     37 #include "vrend_renderer.h"
     38 
     39 #include "virglrenderer.h"
     40 
     41 #ifdef HAVE_EPOXY_EGL_H
     42 #include "virgl_egl.h"
     43 static struct virgl_egl *egl_info;
     44 #endif
     45 
     46 #ifdef HAVE_EPOXY_GLX_H
     47 #include "virgl_glx.h"
     48 static struct virgl_glx *glx_info;
     49 #endif
     50 
     51 enum {
     52    CONTEXT_NONE,
     53    CONTEXT_EGL,
     54    CONTEXT_GLX
     55 };
     56 
     57 static int use_context = CONTEXT_NONE;
     58 
     59 /* new API - just wrap internal API for now */
     60 
     61 int virgl_renderer_resource_create(struct virgl_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs)
     62 {
     63    return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, iov, num_iovs, NULL);
     64 }
     65 
     66 int virgl_renderer_resource_import_eglimage(struct virgl_renderer_resource_create_args *args, void *image)
     67 {
     68 #ifdef HAVE_EPOXY_EGL_H
     69    return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, 0, 0, image);
     70 #else
     71    return EINVAL;
     72 #endif
     73 }
     74 
     75 void virgl_renderer_resource_unref(uint32_t res_handle)
     76 {
     77    vrend_renderer_resource_unref(res_handle);
     78 }
     79 
     80 void virgl_renderer_fill_caps(uint32_t set, uint32_t version,
     81                               void *caps)
     82 {
     83    vrend_renderer_fill_caps(set, version, (union virgl_caps *)caps);
     84 }
     85 
     86 int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char *name)
     87 {
     88    return vrend_renderer_context_create(handle, nlen, name);
     89 }
     90 
     91 void virgl_renderer_context_destroy(uint32_t handle)
     92 {
     93    vrend_renderer_context_destroy(handle);
     94 }
     95 
     96 int virgl_renderer_submit_cmd(void *buffer,
     97                               int ctx_id,
     98                               int ndw)
     99 {
    100    return vrend_decode_block(ctx_id, buffer, ndw);
    101 }
    102 
    103 int virgl_renderer_transfer_write_iov(uint32_t handle,
    104                                       uint32_t ctx_id,
    105                                       int level,
    106                                       uint32_t stride,
    107                                       uint32_t layer_stride,
    108                                       struct virgl_box *box,
    109                                       uint64_t offset,
    110                                       struct iovec *iovec,
    111                                       unsigned int iovec_cnt)
    112 {
    113    struct vrend_transfer_info transfer_info;
    114 
    115    transfer_info.handle = handle;
    116    transfer_info.ctx_id = ctx_id;
    117    transfer_info.level = level;
    118    transfer_info.stride = stride;
    119    transfer_info.layer_stride = layer_stride;
    120    transfer_info.box = (struct pipe_box *)box;
    121    transfer_info.offset = offset;
    122    transfer_info.iovec = iovec;
    123    transfer_info.iovec_cnt = iovec_cnt;
    124 
    125    return vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_WRITE);
    126 }
    127 
    128 int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id,
    129                                      uint32_t level, uint32_t stride,
    130                                      uint32_t layer_stride,
    131                                      struct virgl_box *box,
    132                                      uint64_t offset, struct iovec *iovec,
    133                                      int iovec_cnt)
    134 {
    135    struct vrend_transfer_info transfer_info;
    136 
    137    transfer_info.handle = handle;
    138    transfer_info.ctx_id = ctx_id;
    139    transfer_info.level = level;
    140    transfer_info.stride = stride;
    141    transfer_info.layer_stride = layer_stride;
    142    transfer_info.box = (struct pipe_box *)box;
    143    transfer_info.offset = offset;
    144    transfer_info.iovec = iovec;
    145    transfer_info.iovec_cnt = iovec_cnt;
    146 
    147    return vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_READ);
    148 }
    149 
    150 int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov,
    151                                        int num_iovs)
    152 {
    153    return vrend_renderer_resource_attach_iov(res_handle, iov, num_iovs);
    154 }
    155 
    156 void virgl_renderer_resource_detach_iov(int res_handle, struct iovec **iov_p, int *num_iovs_p)
    157 {
    158    return vrend_renderer_resource_detach_iov(res_handle, iov_p, num_iovs_p);
    159 }
    160 
    161 int virgl_renderer_create_fence(int client_fence_id, uint32_t ctx_id)
    162 {
    163    return vrend_renderer_create_fence(client_fence_id, ctx_id);
    164 }
    165 
    166 void virgl_renderer_force_ctx_0(void)
    167 {
    168    vrend_renderer_force_ctx_0();
    169 }
    170 
    171 void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle)
    172 {
    173    vrend_renderer_attach_res_ctx(ctx_id, res_handle);
    174 }
    175 
    176 void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle)
    177 {
    178    vrend_renderer_detach_res_ctx(ctx_id, res_handle);
    179 }
    180 
    181 int virgl_renderer_resource_get_info(int res_handle,
    182                                      struct virgl_renderer_resource_info *info)
    183 {
    184    int ret;
    185    ret = vrend_renderer_resource_get_info(res_handle, (struct vrend_renderer_resource_info *)info);
    186 #ifdef HAVE_EPOXY_EGL_H
    187    if (ret == 0 && use_context == CONTEXT_EGL)
    188       return virgl_egl_get_fourcc_for_texture(egl_info, info->tex_id, info->virgl_format, &info->drm_fourcc);
    189 #endif
    190 
    191    return ret;
    192 }
    193 
    194 void virgl_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver,
    195                                 uint32_t *max_size)
    196 {
    197    vrend_renderer_get_cap_set(cap_set, max_ver, max_size);
    198 }
    199 
    200 void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int num_iovs,
    201                              uint32_t offset, int x, int y, int width, int height)
    202 {
    203    vrend_renderer_get_rect(resource_id, iov, num_iovs, offset, x, y, width, height);
    204 }
    205 
    206 
    207 static struct virgl_renderer_callbacks *rcbs;
    208 
    209 static void *dev_cookie;
    210 
    211 static struct vrend_if_cbs virgl_cbs;
    212 
    213 static void virgl_write_fence(uint32_t fence_id)
    214 {
    215    rcbs->write_fence(dev_cookie, fence_id);
    216 }
    217 
    218 static virgl_renderer_gl_context create_gl_context(int scanout_idx, struct virgl_gl_ctx_param *param)
    219 {
    220    struct virgl_renderer_gl_ctx_param vparam;
    221 
    222 #ifdef HAVE_EPOXY_EGL_H
    223    if (use_context == CONTEXT_EGL)
    224       return virgl_egl_create_context(egl_info, param);
    225 #endif
    226 #ifdef HAVE_EPOXY_GLX_H
    227    if (use_context == CONTEXT_GLX)
    228       return virgl_glx_create_context(glx_info, param);
    229 #endif
    230    vparam.version = 1;
    231    vparam.shared = param->shared;
    232    vparam.major_ver = param->major_ver;
    233    vparam.minor_ver = param->minor_ver;
    234    return rcbs->create_gl_context(dev_cookie, scanout_idx, &vparam);
    235 }
    236 
    237 static void destroy_gl_context(virgl_renderer_gl_context ctx)
    238 {
    239 #ifdef HAVE_EPOXY_EGL_H
    240    if (use_context == CONTEXT_EGL)
    241       return virgl_egl_destroy_context(egl_info, ctx);
    242 #endif
    243 #ifdef HAVE_EPOXY_GLX_H
    244    if (use_context == CONTEXT_GLX)
    245       return virgl_glx_destroy_context(glx_info, ctx);
    246 #endif
    247    return rcbs->destroy_gl_context(dev_cookie, ctx);
    248 }
    249 
    250 static int make_current(int scanout_idx, virgl_renderer_gl_context ctx)
    251 {
    252 #ifdef HAVE_EPOXY_EGL_H
    253    if (use_context == CONTEXT_EGL)
    254       return virgl_egl_make_context_current(egl_info, ctx);
    255 #endif
    256 #ifdef HAVE_EPOXY_GLX_H
    257    if (use_context == CONTEXT_GLX)
    258       return virgl_glx_make_context_current(glx_info, ctx);
    259 #endif
    260    return rcbs->make_current(dev_cookie, scanout_idx, ctx);
    261 }
    262 
    263 static struct vrend_if_cbs virgl_cbs = {
    264    virgl_write_fence,
    265    create_gl_context,
    266    destroy_gl_context,
    267    make_current,
    268 };
    269 
    270 void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height)
    271 {
    272    return vrend_renderer_get_cursor_contents(resource_id, width, height);
    273 }
    274 
    275 void virgl_renderer_poll(void)
    276 {
    277    vrend_renderer_check_queries();
    278    vrend_renderer_check_fences();
    279 }
    280 
    281 void virgl_renderer_cleanup(UNUSED void *cookie)
    282 {
    283    vrend_renderer_fini();
    284 #ifdef HAVE_EPOXY_EGL_H
    285    if (use_context == CONTEXT_EGL) {
    286       virgl_egl_destroy(egl_info);
    287       egl_info = NULL;
    288       use_context = CONTEXT_NONE;
    289    }
    290 #endif
    291 #ifdef HAVE_EPOXY_GLX_H
    292    if (use_context == CONTEXT_GLX) {
    293       virgl_glx_destroy(glx_info);
    294       glx_info = NULL;
    295       use_context = CONTEXT_NONE;
    296    }
    297 #endif
    298 }
    299 
    300 int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cbs)
    301 {
    302    uint32_t renderer_flags = 0;
    303    if (!cookie || !cbs)
    304       return -1;
    305 
    306    if (cbs->version < 1 || cbs->version > VIRGL_RENDERER_CALLBACKS_VERSION)
    307       return -1;
    308 
    309    dev_cookie = cookie;
    310    rcbs = cbs;
    311 
    312    if (flags & VIRGL_RENDERER_USE_EGL) {
    313 #ifdef HAVE_EPOXY_EGL_H
    314       int fd = -1;
    315       if (cbs->version >= 2 && cbs->get_drm_fd) {
    316          fd = cbs->get_drm_fd(cookie);
    317       }
    318       egl_info = virgl_egl_init(fd, flags & VIRGL_RENDERER_USE_SURFACELESS,
    319                                     flags & VIRGL_RENDERER_USE_GLES);
    320       if (!egl_info)
    321          return -1;
    322       use_context = CONTEXT_EGL;
    323 #else
    324       fprintf(stderr, "EGL is not supported on this platform\n");
    325       return -1;
    326 #endif
    327    } else if (flags & VIRGL_RENDERER_USE_GLX) {
    328 #ifdef HAVE_EPOXY_GLX_H
    329       glx_info = virgl_glx_init();
    330       if (!glx_info)
    331          return -1;
    332       use_context = CONTEXT_GLX;
    333 #else
    334       fprintf(stderr, "GLX is not supported on this platform\n");
    335       return -1;
    336 #endif
    337    }
    338 
    339    if (flags & VIRGL_RENDERER_THREAD_SYNC)
    340       renderer_flags |= VREND_USE_THREAD_SYNC;
    341 
    342    return vrend_renderer_init(&virgl_cbs, renderer_flags);
    343 }
    344 
    345 int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd)
    346 {
    347 #ifdef HAVE_EPOXY_EGL_H
    348    return virgl_egl_get_fd_for_texture(egl_info, tex_id, fd);
    349 #else
    350    return -1;
    351 #endif
    352 }
    353 
    354 int virgl_renderer_get_fd_for_texture2(uint32_t tex_id, int *fd, int *stride, int *offset)
    355 {
    356 #ifdef HAVE_EPOXY_EGL_H
    357    return virgl_egl_get_fd_for_texture2(egl_info, tex_id, fd, stride, offset);
    358 #else
    359    return -1;
    360 #endif
    361 }
    362 
    363 void virgl_renderer_reset(void)
    364 {
    365    vrend_renderer_reset();
    366 }
    367 
    368 int virgl_renderer_get_poll_fd(void)
    369 {
    370    return vrend_renderer_get_poll_fd();
    371 }
    372