vmw_screen_dri.c revision 71901594ed8bb2b47d492091f91c00c3e9da7c45
1/********************************************************** 2 * Copyright 2009 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#include "vmw_screen.h" 32 33#include "trace/tr_drm.h" 34 35#include "vmw_screen.h" 36#include "vmw_surface.h" 37#include "vmw_fence.h" 38#include "vmw_context.h" 39 40#include <state_tracker/dri1_api.h> 41#include <state_tracker/drm_api.h> 42#include "vmwgfx_drm.h" 43#include <xf86drm.h> 44 45#include <stdio.h> 46 47static struct svga_winsys_surface * 48vmw_drm_surface_from_handle(struct svga_winsys_screen *sws, 49 struct winsys_handle *whandle, 50 SVGA3dSurfaceFormat *format); 51static boolean 52vmw_drm_surface_get_handle(struct svga_winsys_screen *sws, 53 struct svga_winsys_surface *surface, 54 unsigned stride, 55 struct winsys_handle *whandle); 56 57static struct dri1_api dri1_api_hooks; 58static struct dri1_api_version ddx_required = { 0, 1, 0 }; 59static struct dri1_api_version ddx_compat = { 0, 0, 0 }; 60static struct dri1_api_version dri_required = { 4, 0, 0 }; 61static struct dri1_api_version dri_compat = { 4, 0, 0 }; 62static struct dri1_api_version drm_required = { 1, 0, 0 }; 63static struct dri1_api_version drm_compat = { 1, 0, 0 }; 64static struct dri1_api_version drm_scanout = { 0, 9, 0 }; 65 66static boolean 67vmw_dri1_check_version(const struct dri1_api_version *cur, 68 const struct dri1_api_version *required, 69 const struct dri1_api_version *compat, 70 const char component[]) 71{ 72 if (cur->major > required->major && cur->major <= compat->major) 73 return TRUE; 74 if (cur->major == required->major && cur->minor >= required->minor) 75 return TRUE; 76 77 fprintf(stderr, "%s version failure.\n", component); 78 fprintf(stderr, "%s version is %d.%d.%d and this driver can only work\n" 79 "with versions %d.%d.x through %d.x.x.\n", 80 component, 81 cur->major, 82 cur->minor, 83 cur->patch_level, required->major, required->minor, compat->major); 84 return FALSE; 85} 86 87/* This is actually the entrypoint to the entire driver, called by the 88 * libGL (or EGL, or ...) code via the drm_api_hooks table at the 89 * bottom of the file. 90 */ 91static struct pipe_screen * 92vmw_drm_create_screen(struct drm_api *drm_api, 93 int fd, 94 struct drm_create_screen_arg *arg) 95{ 96 struct vmw_winsys_screen *vws; 97 struct pipe_screen *screen; 98 struct dri1_create_screen_arg *dri1; 99 boolean use_old_scanout_flag = FALSE; 100 101 if (!arg || arg->mode == DRM_CREATE_NORMAL) { 102 struct dri1_api_version drm_ver; 103 drmVersionPtr ver; 104 105 ver = drmGetVersion(fd); 106 if (ver == NULL) 107 return NULL; 108 109 drm_ver.major = ver->version_major; 110 drm_ver.minor = ver->version_minor; 111 drm_ver.patch_level = 0; /* ??? */ 112 113 drmFreeVersion(ver); 114 if (!vmw_dri1_check_version(&drm_ver, &drm_required, 115 &drm_compat, "vmwgfx drm driver")) 116 return NULL; 117 118 if (!vmw_dri1_check_version(&drm_ver, &drm_scanout, 119 &drm_compat, "use old scanout field (not a error)")) 120 use_old_scanout_flag = TRUE; 121 } 122 123 if (arg != NULL) { 124 switch (arg->mode) { 125 case DRM_CREATE_NORMAL: 126 break; 127 case DRM_CREATE_DRI1: 128 dri1 = (struct dri1_create_screen_arg *)arg; 129 if (!vmw_dri1_check_version(&dri1->ddx_version, &ddx_required, 130 &ddx_compat, "ddx - driver api")) 131 return NULL; 132 if (!vmw_dri1_check_version(&dri1->dri_version, &dri_required, 133 &dri_compat, "dri info")) 134 return NULL; 135 if (!vmw_dri1_check_version(&dri1->drm_version, &drm_required, 136 &drm_compat, "vmwgfx drm driver")) 137 return NULL; 138 if (!vmw_dri1_check_version(&dri1->drm_version, &drm_scanout, 139 &drm_compat, "use old scanout field (not a error)")) 140 use_old_scanout_flag = TRUE; 141 dri1->api = &dri1_api_hooks; 142#if 0 143 break; 144#else 145 assert(!"No dri 1 support for now\n"); 146 return NULL; 147#endif 148 default: 149 return NULL; 150 } 151 } 152 153 vws = vmw_winsys_create( fd, use_old_scanout_flag ); 154 if (!vws) 155 goto out_no_vws; 156 157 /* XXX do this properly */ 158 vws->base.surface_from_handle = vmw_drm_surface_from_handle; 159 vws->base.surface_get_handle = vmw_drm_surface_get_handle; 160 161 screen = svga_screen_create( &vws->base ); 162 if (!screen) 163 goto out_no_screen; 164 165 return screen; 166 167 /* Failure cases: 168 */ 169out_no_screen: 170 vmw_winsys_destroy( vws ); 171 172out_no_vws: 173 return NULL; 174} 175 176static INLINE boolean 177vmw_dri1_intersect_src_bbox(struct drm_clip_rect *dst, 178 int dst_x, 179 int dst_y, 180 const struct drm_clip_rect *src, 181 const struct drm_clip_rect *bbox) 182{ 183 int xy1; 184 int xy2; 185 186 xy1 = ((int)src->x1 > (int)bbox->x1 + dst_x) ? src->x1 : 187 (int)bbox->x1 + dst_x; 188 xy2 = ((int)src->x2 < (int)bbox->x2 + dst_x) ? src->x2 : 189 (int)bbox->x2 + dst_x; 190 if (xy1 >= xy2 || xy1 < 0) 191 return FALSE; 192 193 dst->x1 = xy1; 194 dst->x2 = xy2; 195 196 xy1 = ((int)src->y1 > (int)bbox->y1 + dst_y) ? src->y1 : 197 (int)bbox->y1 + dst_y; 198 xy2 = ((int)src->y2 < (int)bbox->y2 + dst_y) ? src->y2 : 199 (int)bbox->y2 + dst_y; 200 if (xy1 >= xy2 || xy1 < 0) 201 return FALSE; 202 203 dst->y1 = xy1; 204 dst->y2 = xy2; 205 return TRUE; 206} 207 208/** 209 * No fancy get-surface-from-sarea stuff here. 210 * Just use the present blit. 211 */ 212 213static void 214vmw_dri1_present_locked(struct pipe_context *locked_pipe, 215 struct pipe_surface *surf, 216 const struct drm_clip_rect *rect, 217 unsigned int num_clip, 218 int x_draw, int y_draw, 219 const struct drm_clip_rect *bbox, 220 struct pipe_fence_handle **p_fence) 221{ 222#if 0 223 struct svga_winsys_surface *srf = 224 svga_screen_texture_get_winsys_surface(surf->texture); 225 struct vmw_svga_winsys_surface *vsrf = vmw_svga_winsys_surface(srf); 226 struct vmw_winsys_screen *vws = 227 vmw_winsys_screen(svga_winsys_screen(locked_pipe->screen)); 228 struct drm_clip_rect clip; 229 int i; 230 struct 231 { 232 SVGA3dCmdHeader header; 233 SVGA3dCmdPresent body; 234 SVGA3dCopyRect rect; 235 } cmd; 236 boolean visible = FALSE; 237 uint32_t fence_seq = 0; 238 239 VMW_FUNC; 240 cmd.header.id = SVGA_3D_CMD_PRESENT; 241 cmd.header.size = sizeof cmd.body + sizeof cmd.rect; 242 cmd.body.sid = vsrf->sid; 243 244 for (i = 0; i < num_clip; ++i) { 245 if (!vmw_dri1_intersect_src_bbox(&clip, x_draw, y_draw, rect++, bbox)) 246 continue; 247 248 cmd.rect.x = clip.x1; 249 cmd.rect.y = clip.y1; 250 cmd.rect.w = clip.x2 - clip.x1; 251 cmd.rect.h = clip.y2 - clip.y1; 252 cmd.rect.srcx = (int)clip.x1 - x_draw; 253 cmd.rect.srcy = (int)clip.y1 - y_draw; 254 255 vmw_printf("%s: Clip %d x %d y %d w %d h %d srcx %d srcy %d\n", 256 __FUNCTION__, 257 i, 258 cmd.rect.x, 259 cmd.rect.y, 260 cmd.rect.w, cmd.rect.h, cmd.rect.srcx, cmd.rect.srcy); 261 262 vmw_ioctl_command(vws, &cmd, sizeof cmd.header + cmd.header.size, 263 &fence_seq); 264 visible = TRUE; 265 } 266 267 *p_fence = (visible) ? vmw_pipe_fence(fence_seq) : NULL; 268 vmw_svga_winsys_surface_reference(&vsrf, NULL); 269#else 270 assert(!"No dri 1 support for now\n"); 271#endif 272} 273 274static struct svga_winsys_surface * 275vmw_drm_surface_from_handle(struct svga_winsys_screen *sws, 276 struct winsys_handle *whandle, 277 SVGA3dSurfaceFormat *format) 278{ 279 struct vmw_svga_winsys_surface *vsrf; 280 struct svga_winsys_surface *ssrf; 281 struct vmw_winsys_screen *vws = vmw_winsys_screen(sws); 282 union drm_vmw_surface_reference_arg arg; 283 struct drm_vmw_surface_arg *req = &arg.req; 284 struct drm_vmw_surface_create_req *rep = &arg.rep; 285 int ret; 286 int i; 287 288 /** 289 * The vmware device specific handle is the hardware SID. 290 * FIXME: We probably want to move this to the ioctl implementations. 291 */ 292 293 memset(&arg, 0, sizeof(arg)); 294 req->sid = whandle->handle; 295 296 ret = drmCommandWriteRead(vws->ioctl.drm_fd, DRM_VMW_REF_SURFACE, 297 &arg, sizeof(arg)); 298 299 if (ret) { 300 fprintf(stderr, "Failed referencing shared surface. SID %d.\n" 301 "Error %d (%s).\n", 302 whandle->handle, ret, strerror(-ret)); 303 return NULL; 304 } 305 306 if (rep->mip_levels[0] != 1) { 307 fprintf(stderr, "Incorrect number of mipmap levels on shared surface." 308 " SID %d, levels %d\n", 309 whandle->handle, rep->mip_levels[0]); 310 goto out_mip; 311 } 312 313 for (i=1; i < DRM_VMW_MAX_SURFACE_FACES; ++i) { 314 if (rep->mip_levels[i] != 0) { 315 fprintf(stderr, "Incorrect number of faces levels on shared surface." 316 " SID %d, face %d present.\n", 317 whandle->handle, i); 318 goto out_mip; 319 } 320 } 321 322 vsrf = CALLOC_STRUCT(vmw_svga_winsys_surface); 323 if (!vsrf) 324 goto out_mip; 325 326 pipe_reference_init(&vsrf->refcnt, 1); 327 p_atomic_set(&vsrf->validated, 0); 328 vsrf->screen = vws; 329 vsrf->sid = whandle->handle; 330 ssrf = svga_winsys_surface(vsrf); 331 *format = rep->format; 332 333 return ssrf; 334 335out_mip: 336 vmw_ioctl_surface_destroy(vws, whandle->handle); 337 return NULL; 338} 339 340static boolean 341vmw_drm_surface_get_handle(struct svga_winsys_screen *sws, 342 struct svga_winsys_surface *surface, 343 unsigned stride, 344 struct winsys_handle *whandle) 345{ 346 struct vmw_svga_winsys_surface *vsrf; 347 348 if (!surface) 349 return FALSE; 350 351 vsrf = vmw_svga_winsys_surface(surface); 352 whandle->handle = vsrf->sid; 353 whandle->stride = stride; 354 355 return TRUE; 356} 357 358 359static struct dri1_api dri1_api_hooks = { 360 .front_srf_locked = NULL, 361 .present_locked = vmw_dri1_present_locked 362}; 363 364static struct drm_api vmw_drm_api_hooks = { 365 .name = "vmwgfx", 366 .driver_name = "vmwgfx", 367 .create_screen = vmw_drm_create_screen, 368 .destroy = NULL, 369}; 370 371struct drm_api* drm_api_create() 372{ 373 return trace_drm_create(&vmw_drm_api_hooks); 374} 375