C++程序  |  372行  |  10.59 KB

/**************************************************************************
 *
 * Copyright (C) 2014 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 **************************************************************************/

#include <stdio.h>
#include <time.h>

#include <epoxy/gl.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include "pipe/p_state.h"
#include "util/u_format.h"
#include "util/u_math.h"
#include "vrend_renderer.h"

#include "virglrenderer.h"

#ifdef HAVE_EPOXY_EGL_H
#include "virgl_egl.h"
static struct virgl_egl *egl_info;
#endif

#ifdef HAVE_EPOXY_GLX_H
#include "virgl_glx.h"
static struct virgl_glx *glx_info;
#endif

enum {
   CONTEXT_NONE,
   CONTEXT_EGL,
   CONTEXT_GLX
};

static int use_context = CONTEXT_NONE;

/* new API - just wrap internal API for now */

int virgl_renderer_resource_create(struct virgl_renderer_resource_create_args *args, struct iovec *iov, uint32_t num_iovs)
{
   return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, iov, num_iovs, NULL);
}

int virgl_renderer_resource_import_eglimage(struct virgl_renderer_resource_create_args *args, void *image)
{
#ifdef HAVE_EPOXY_EGL_H
   return vrend_renderer_resource_create((struct vrend_renderer_resource_create_args *)args, 0, 0, image);
#else
   return EINVAL;
#endif
}

void virgl_renderer_resource_unref(uint32_t res_handle)
{
   vrend_renderer_resource_unref(res_handle);
}

void virgl_renderer_fill_caps(uint32_t set, uint32_t version,
                              void *caps)
{
   vrend_renderer_fill_caps(set, version, (union virgl_caps *)caps);
}

int virgl_renderer_context_create(uint32_t handle, uint32_t nlen, const char *name)
{
   return vrend_renderer_context_create(handle, nlen, name);
}

void virgl_renderer_context_destroy(uint32_t handle)
{
   vrend_renderer_context_destroy(handle);
}

int virgl_renderer_submit_cmd(void *buffer,
                              int ctx_id,
                              int ndw)
{
   return vrend_decode_block(ctx_id, buffer, ndw);
}

int virgl_renderer_transfer_write_iov(uint32_t handle,
                                      uint32_t ctx_id,
                                      int level,
                                      uint32_t stride,
                                      uint32_t layer_stride,
                                      struct virgl_box *box,
                                      uint64_t offset,
                                      struct iovec *iovec,
                                      unsigned int iovec_cnt)
{
   struct vrend_transfer_info transfer_info;

   transfer_info.handle = handle;
   transfer_info.ctx_id = ctx_id;
   transfer_info.level = level;
   transfer_info.stride = stride;
   transfer_info.layer_stride = layer_stride;
   transfer_info.box = (struct pipe_box *)box;
   transfer_info.offset = offset;
   transfer_info.iovec = iovec;
   transfer_info.iovec_cnt = iovec_cnt;

   return vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_WRITE);
}

int virgl_renderer_transfer_read_iov(uint32_t handle, uint32_t ctx_id,
                                     uint32_t level, uint32_t stride,
                                     uint32_t layer_stride,
                                     struct virgl_box *box,
                                     uint64_t offset, struct iovec *iovec,
                                     int iovec_cnt)
{
   struct vrend_transfer_info transfer_info;

   transfer_info.handle = handle;
   transfer_info.ctx_id = ctx_id;
   transfer_info.level = level;
   transfer_info.stride = stride;
   transfer_info.layer_stride = layer_stride;
   transfer_info.box = (struct pipe_box *)box;
   transfer_info.offset = offset;
   transfer_info.iovec = iovec;
   transfer_info.iovec_cnt = iovec_cnt;

   return vrend_renderer_transfer_iov(&transfer_info, VREND_TRANSFER_READ);
}

int virgl_renderer_resource_attach_iov(int res_handle, struct iovec *iov,
                                       int num_iovs)
{
   return vrend_renderer_resource_attach_iov(res_handle, iov, num_iovs);
}

void virgl_renderer_resource_detach_iov(int res_handle, struct iovec **iov_p, int *num_iovs_p)
{
   return vrend_renderer_resource_detach_iov(res_handle, iov_p, num_iovs_p);
}

int virgl_renderer_create_fence(int client_fence_id, uint32_t ctx_id)
{
   return vrend_renderer_create_fence(client_fence_id, ctx_id);
}

void virgl_renderer_force_ctx_0(void)
{
   vrend_renderer_force_ctx_0();
}

void virgl_renderer_ctx_attach_resource(int ctx_id, int res_handle)
{
   vrend_renderer_attach_res_ctx(ctx_id, res_handle);
}

void virgl_renderer_ctx_detach_resource(int ctx_id, int res_handle)
{
   vrend_renderer_detach_res_ctx(ctx_id, res_handle);
}

int virgl_renderer_resource_get_info(int res_handle,
                                     struct virgl_renderer_resource_info *info)
{
   int ret;
   ret = vrend_renderer_resource_get_info(res_handle, (struct vrend_renderer_resource_info *)info);
#ifdef HAVE_EPOXY_EGL_H
   if (ret == 0 && use_context == CONTEXT_EGL)
      return virgl_egl_get_fourcc_for_texture(egl_info, info->tex_id, info->virgl_format, &info->drm_fourcc);
#endif

   return ret;
}

void virgl_renderer_get_cap_set(uint32_t cap_set, uint32_t *max_ver,
                                uint32_t *max_size)
{
   vrend_renderer_get_cap_set(cap_set, max_ver, max_size);
}

void virgl_renderer_get_rect(int resource_id, struct iovec *iov, unsigned int num_iovs,
                             uint32_t offset, int x, int y, int width, int height)
{
   vrend_renderer_get_rect(resource_id, iov, num_iovs, offset, x, y, width, height);
}


static struct virgl_renderer_callbacks *rcbs;

static void *dev_cookie;

static struct vrend_if_cbs virgl_cbs;

static void virgl_write_fence(uint32_t fence_id)
{
   rcbs->write_fence(dev_cookie, fence_id);
}

static virgl_renderer_gl_context create_gl_context(int scanout_idx, struct virgl_gl_ctx_param *param)
{
   struct virgl_renderer_gl_ctx_param vparam;

#ifdef HAVE_EPOXY_EGL_H
   if (use_context == CONTEXT_EGL)
      return virgl_egl_create_context(egl_info, param);
#endif
#ifdef HAVE_EPOXY_GLX_H
   if (use_context == CONTEXT_GLX)
      return virgl_glx_create_context(glx_info, param);
#endif
   vparam.version = 1;
   vparam.shared = param->shared;
   vparam.major_ver = param->major_ver;
   vparam.minor_ver = param->minor_ver;
   return rcbs->create_gl_context(dev_cookie, scanout_idx, &vparam);
}

static void destroy_gl_context(virgl_renderer_gl_context ctx)
{
#ifdef HAVE_EPOXY_EGL_H
   if (use_context == CONTEXT_EGL)
      return virgl_egl_destroy_context(egl_info, ctx);
#endif
#ifdef HAVE_EPOXY_GLX_H
   if (use_context == CONTEXT_GLX)
      return virgl_glx_destroy_context(glx_info, ctx);
#endif
   return rcbs->destroy_gl_context(dev_cookie, ctx);
}

static int make_current(int scanout_idx, virgl_renderer_gl_context ctx)
{
#ifdef HAVE_EPOXY_EGL_H
   if (use_context == CONTEXT_EGL)
      return virgl_egl_make_context_current(egl_info, ctx);
#endif
#ifdef HAVE_EPOXY_GLX_H
   if (use_context == CONTEXT_GLX)
      return virgl_glx_make_context_current(glx_info, ctx);
#endif
   return rcbs->make_current(dev_cookie, scanout_idx, ctx);
}

static struct vrend_if_cbs virgl_cbs = {
   virgl_write_fence,
   create_gl_context,
   destroy_gl_context,
   make_current,
};

void *virgl_renderer_get_cursor_data(uint32_t resource_id, uint32_t *width, uint32_t *height)
{
   return vrend_renderer_get_cursor_contents(resource_id, width, height);
}

void virgl_renderer_poll(void)
{
   vrend_renderer_check_queries();
   vrend_renderer_check_fences();
}

void virgl_renderer_cleanup(UNUSED void *cookie)
{
   vrend_renderer_fini();
#ifdef HAVE_EPOXY_EGL_H
   if (use_context == CONTEXT_EGL) {
      virgl_egl_destroy(egl_info);
      egl_info = NULL;
      use_context = CONTEXT_NONE;
   }
#endif
#ifdef HAVE_EPOXY_GLX_H
   if (use_context == CONTEXT_GLX) {
      virgl_glx_destroy(glx_info);
      glx_info = NULL;
      use_context = CONTEXT_NONE;
   }
#endif
}

int virgl_renderer_init(void *cookie, int flags, struct virgl_renderer_callbacks *cbs)
{
   uint32_t renderer_flags = 0;
   if (!cookie || !cbs)
      return -1;

   if (cbs->version < 1 || cbs->version > VIRGL_RENDERER_CALLBACKS_VERSION)
      return -1;

   dev_cookie = cookie;
   rcbs = cbs;

   if (flags & VIRGL_RENDERER_USE_EGL) {
#ifdef HAVE_EPOXY_EGL_H
      int fd = -1;
      if (cbs->version >= 2 && cbs->get_drm_fd) {
         fd = cbs->get_drm_fd(cookie);
      }
      egl_info = virgl_egl_init(fd, flags & VIRGL_RENDERER_USE_SURFACELESS,
                                    flags & VIRGL_RENDERER_USE_GLES);
      if (!egl_info)
         return -1;
      use_context = CONTEXT_EGL;
#else
      fprintf(stderr, "EGL is not supported on this platform\n");
      return -1;
#endif
   } else if (flags & VIRGL_RENDERER_USE_GLX) {
#ifdef HAVE_EPOXY_GLX_H
      glx_info = virgl_glx_init();
      if (!glx_info)
         return -1;
      use_context = CONTEXT_GLX;
#else
      fprintf(stderr, "GLX is not supported on this platform\n");
      return -1;
#endif
   }

   if (flags & VIRGL_RENDERER_THREAD_SYNC)
      renderer_flags |= VREND_USE_THREAD_SYNC;

   return vrend_renderer_init(&virgl_cbs, renderer_flags);
}

int virgl_renderer_get_fd_for_texture(uint32_t tex_id, int *fd)
{
#ifdef HAVE_EPOXY_EGL_H
   return virgl_egl_get_fd_for_texture(egl_info, tex_id, fd);
#else
   return -1;
#endif
}

int virgl_renderer_get_fd_for_texture2(uint32_t tex_id, int *fd, int *stride, int *offset)
{
#ifdef HAVE_EPOXY_EGL_H
   return virgl_egl_get_fd_for_texture2(egl_info, tex_id, fd, stride, offset);
#else
   return -1;
#endif
}

void virgl_renderer_reset(void)
{
   vrend_renderer_reset();
}

int virgl_renderer_get_poll_fd(void)
{
   return vrend_renderer_get_poll_fd();
}