1 /********************************************************** 2 * Copyright 2009-2015 VMware, Inc. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person 5 * obtaining a copy of this software and associated documentation 6 * files (the "Software"), to deal in the Software without 7 * restriction, including without limitation the rights to use, copy, 8 * modify, merge, publish, distribute, sublicense, and/or sell copies 9 * of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 * 24 **********************************************************/ 25 26 27 #include "pipe/p_compiler.h" 28 #include "util/u_inlines.h" 29 #include "util/u_memory.h" 30 #include "util/u_format.h" 31 32 #include "vmw_context.h" 33 #include "vmw_screen.h" 34 #include "vmw_surface.h" 35 #include "vmw_buffer.h" 36 #include "svga_drm_public.h" 37 #include "svga3d_surfacedefs.h" 38 39 #include "state_tracker/drm_driver.h" 40 41 #include "vmwgfx_drm.h" 42 #include <xf86drm.h> 43 44 #include <stdio.h> 45 #include <fcntl.h> 46 47 struct dri1_api_version { 48 int major; 49 int minor; 50 int patch_level; 51 }; 52 53 static struct svga_winsys_surface * 54 vmw_drm_surface_from_handle(struct svga_winsys_screen *sws, 55 struct winsys_handle *whandle, 56 SVGA3dSurfaceFormat *format); 57 58 static struct svga_winsys_surface * 59 vmw_drm_gb_surface_from_handle(struct svga_winsys_screen *sws, 60 struct winsys_handle *whandle, 61 SVGA3dSurfaceFormat *format); 62 static boolean 63 vmw_drm_surface_get_handle(struct svga_winsys_screen *sws, 64 struct svga_winsys_surface *surface, 65 unsigned stride, 66 struct winsys_handle *whandle); 67 68 static struct dri1_api_version drm_required = { 2, 1, 0 }; 69 static struct dri1_api_version drm_compat = { 2, 0, 0 }; 70 71 static boolean 72 vmw_dri1_check_version(const struct dri1_api_version *cur, 73 const struct dri1_api_version *required, 74 const struct dri1_api_version *compat, 75 const char component[]) 76 { 77 if (cur->major > required->major && cur->major <= compat->major) 78 return TRUE; 79 if (cur->major == required->major && cur->minor >= required->minor) 80 return TRUE; 81 82 vmw_error("%s version failure.\n", component); 83 vmw_error("%s version is %d.%d.%d and this driver can only work\n" 84 "with versions %d.%d.x through %d.x.x.\n", 85 component, 86 cur->major, cur->minor, cur->patch_level, 87 required->major, required->minor, compat->major); 88 return FALSE; 89 } 90 91 /* This is actually the entrypoint to the entire driver, 92 * called by the target bootstrap code. 93 */ 94 struct svga_winsys_screen * 95 svga_drm_winsys_screen_create(int fd) 96 { 97 struct vmw_winsys_screen *vws; 98 struct dri1_api_version drm_ver; 99 drmVersionPtr ver; 100 101 ver = drmGetVersion(fd); 102 if (ver == NULL) 103 return NULL; 104 105 drm_ver.major = ver->version_major; 106 drm_ver.minor = ver->version_minor; 107 drm_ver.patch_level = 0; /* ??? */ 108 109 drmFreeVersion(ver); 110 if (!vmw_dri1_check_version(&drm_ver, &drm_required, 111 &drm_compat, "vmwgfx drm driver")) 112 return NULL; 113 114 vws = vmw_winsys_create(fd); 115 if (!vws) 116 goto out_no_vws; 117 118 /* XXX do this properly */ 119 vws->base.surface_from_handle = vws->base.have_gb_objects ? 120 vmw_drm_gb_surface_from_handle : vmw_drm_surface_from_handle; 121 vws->base.surface_get_handle = vmw_drm_surface_get_handle; 122 123 return &vws->base; 124 125 out_no_vws: 126 return NULL; 127 } 128 129 static inline boolean 130 vmw_dri1_intersect_src_bbox(struct drm_clip_rect *dst, 131 int dst_x, 132 int dst_y, 133 const struct drm_clip_rect *src, 134 const struct drm_clip_rect *bbox) 135 { 136 int xy1; 137 int xy2; 138 139 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 : 140 (int)bbox->x1 + dst_x; 141 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 : 142 (int)bbox->x2 + dst_x; 143 if (xy1 >= xy2 || xy1 < 0) 144 return FALSE; 145 146 dst->x1 = xy1; 147 dst->x2 = xy2; 148 149 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 : 150 (int)bbox->y1 + dst_y; 151 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 : 152 (int)bbox->y2 + dst_y; 153 if (xy1 >= xy2 || xy1 < 0) 154 return FALSE; 155 156 dst->y1 = xy1; 157 dst->y2 = xy2; 158 return TRUE; 159 } 160 161 /** 162 * vmw_drm_gb_surface_from_handle - Create a shared surface 163 * 164 * @sws: Screen to register the surface with. 165 * @whandle: struct winsys_handle identifying the kernel surface object 166 * @format: On successful return points to a value describing the 167 * surface format. 168 * 169 * Returns a refcounted pointer to a struct svga_winsys_surface 170 * embedded in a struct vmw_svga_winsys_surface on success or NULL 171 * on failure. 172 */ 173 static struct svga_winsys_surface * 174 vmw_drm_gb_surface_from_handle(struct svga_winsys_screen *sws, 175 struct winsys_handle *whandle, 176 SVGA3dSurfaceFormat *format) 177 { 178 struct vmw_svga_winsys_surface *vsrf; 179 struct svga_winsys_surface *ssrf; 180 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 181 SVGA3dSurfaceFlags flags; 182 uint32_t mip_levels; 183 struct vmw_buffer_desc desc; 184 struct pb_manager *provider = vws->pools.gmr; 185 struct pb_buffer *pb_buf; 186 uint32_t handle; 187 int ret; 188 189 if (whandle->offset != 0) { 190 fprintf(stderr, "Attempt to import unsupported winsys offset %u\n", 191 whandle->offset); 192 return NULL; 193 } 194 195 ret = vmw_ioctl_gb_surface_ref(vws, whandle, &flags, format, 196 &mip_levels, &handle, &desc.region); 197 198 if (ret) { 199 fprintf(stderr, "Failed referencing shared surface. SID %d.\n" 200 "Error %d (%s).\n", 201 whandle->handle, ret, strerror(-ret)); 202 return NULL; 203 } 204 205 if (mip_levels != 1) { 206 fprintf(stderr, "Incorrect number of mipmap levels on shared surface." 207 " SID %d, levels %d\n", 208 whandle->handle, mip_levels); 209 goto out_mip; 210 } 211 212 vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface); 213 if (!vsrf) 214 goto out_mip; 215 216 pipe_reference_init(&vsrf->refcnt, 1); 217 p_atomic_set(&vsrf->validated, 0); 218 vsrf->screen = vws; 219 vsrf->sid = handle; 220 vsrf->size = vmw_region_size(desc.region); 221 222 /* 223 * Synchronize backing buffers of shared surfaces using the 224 * kernel, since we don't pass fence objects around between 225 * processes. 226 */ 227 desc.pb_desc.alignment = 4096; 228 desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED | VMW_BUFFER_USAGE_SYNC; 229 pb_buf = provider->create_buffer(provider, vsrf->size, &desc.pb_desc); 230 vsrf->buf = vmw_svga_winsys_buffer_wrap(pb_buf); 231 if (!vsrf->buf) 232 goto out_no_buf; 233 ssrf = svga_winsys_surface(vsrf); 234 235 return ssrf; 236 237 out_no_buf: 238 FREE(vsrf); 239 out_mip: 240 vmw_ioctl_region_destroy(desc.region); 241 vmw_ioctl_surface_destroy(vws, whandle->handle); 242 return NULL; 243 } 244 245 static struct svga_winsys_surface * 246 vmw_drm_surface_from_handle(struct svga_winsys_screen *sws, 247 struct winsys_handle *whandle, 248 SVGA3dSurfaceFormat *format) 249 { 250 struct vmw_svga_winsys_surface *vsrf; 251 struct svga_winsys_surface *ssrf; 252 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 253 union drm_vmw_surface_reference_arg arg; 254 struct drm_vmw_surface_arg *req = &arg.req; 255 struct drm_vmw_surface_create_req *rep = &arg.rep; 256 uint32_t handle = 0; 257 struct drm_vmw_size size; 258 SVGA3dSize base_size; 259 int ret; 260 int i; 261 262 if (whandle->offset != 0) { 263 fprintf(stderr, "Attempt to import unsupported winsys offset %u\n", 264 whandle->offset); 265 return NULL; 266 } 267 268 switch (whandle->type) { 269 case DRM_API_HANDLE_TYPE_SHARED: 270 case DRM_API_HANDLE_TYPE_KMS: 271 handle = whandle->handle; 272 break; 273 case DRM_API_HANDLE_TYPE_FD: 274 ret = drmPrimeFDToHandle(vws->ioctl.drm_fd, whandle->handle, 275 &handle); 276 if (ret) { 277 vmw_error("Failed to get handle from prime fd %d.\n", 278 (int) whandle->handle); 279 return NULL; 280 } 281 break; 282 default: 283 vmw_error("Attempt to import unsupported handle type %d.\n", 284 whandle->type); 285 return NULL; 286 } 287 288 memset(&arg, 0, sizeof(arg)); 289 req->sid = handle; 290 rep->size_addr = (unsigned long)&size; 291 292 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE, 293 &arg, sizeof(arg)); 294 295 /* 296 * Need to close the handle we got from prime. 297 */ 298 if (whandle->type == DRM_API_HANDLE_TYPE_FD) 299 vmw_ioctl_surface_destroy(vws, handle); 300 301 if (ret) { 302 /* 303 * Any attempt to share something other than a surface, like a dumb 304 * kms buffer, should fail here. 305 */ 306 vmw_error("Failed referencing shared surface. SID %d.\n" 307 "Error %d (%s).\n", 308 handle, ret, strerror(-ret)); 309 return NULL; 310 } 311 312 if (rep->mip_levels[0] != 1) { 313 vmw_error("Incorrect number of mipmap levels on shared surface." 314 " SID %d, levels %d\n", 315 handle, rep->mip_levels[0]); 316 goto out_mip; 317 } 318 319 for (i=1; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { 320 if (rep->mip_levels[i] != 0) { 321 vmw_error("Incorrect number of faces levels on shared surface." 322 " SID %d, face %d present.\n", 323 handle, i); 324 goto out_mip; 325 } 326 } 327 328 vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface); 329 if (!vsrf) 330 goto out_mip; 331 332 pipe_reference_init(&vsrf->refcnt, 1); 333 p_atomic_set(&vsrf->validated, 0); 334 vsrf->screen = vws; 335 vsrf->sid = handle; 336 ssrf = svga_winsys_surface(vsrf); 337 *format = rep->format; 338 339 /* Estimate usage, for early flushing. */ 340 341 base_size.width = size.width; 342 base_size.height = size.height; 343 base_size.depth = size.depth; 344 vsrf->size = svga3dsurface_get_serialized_size(rep->format, base_size, 345 rep->mip_levels[0], 346 FALSE); 347 348 return ssrf; 349 350 out_mip: 351 vmw_ioctl_surface_destroy(vws, handle); 352 353 return NULL; 354 } 355 356 static boolean 357 vmw_drm_surface_get_handle(struct svga_winsys_screen *sws, 358 struct svga_winsys_surface *surface, 359 unsigned stride, 360 struct winsys_handle *whandle) 361 { 362 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 363 struct vmw_svga_winsys_surface *vsrf; 364 int ret; 365 366 if (!surface) 367 return FALSE; 368 369 vsrf = vmw_svga_winsys_surface(surface); 370 whandle->handle = vsrf->sid; 371 whandle->stride = stride; 372 whandle->offset = 0; 373 374 switch (whandle->type) { 375 case DRM_API_HANDLE_TYPE_SHARED: 376 case DRM_API_HANDLE_TYPE_KMS: 377 whandle->handle = vsrf->sid; 378 break; 379 case DRM_API_HANDLE_TYPE_FD: 380 ret = drmPrimeHandleToFD(vws->ioctl.drm_fd, vsrf->sid, DRM_CLOEXEC, 381 (int *)&whandle->handle); 382 if (ret) { 383 vmw_error("Failed to get file descriptor from prime.\n"); 384 return FALSE; 385 } 386 break; 387 default: 388 vmw_error("Attempt to export unsupported handle type %d.\n", 389 whandle->type); 390 return FALSE; 391 } 392 393 return TRUE; 394 } 395