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