1/* 2 * Copyright 2017 VMWare, Inc. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * Author: Thomas Hellstrom <thellstrom@vmware.com> 26 * 27 */ 28#ifdef _HAVE_CONFIG_H_ 29#include "config.h" 30#endif 31 32#include <xorg-server.h> 33 34#ifdef DRI3 35#include "vmwgfx_driver.h" 36#if (XA_TRACKER_VERSION_MAJOR == VMW_XA_VERSION_MAJOR_DRI3 && \ 37 XA_TRACKER_VERSION_MINOR >= VMW_XA_VERSION_MINOR_DRI3) 38 39#include "vmwgfx_driver.h" 40#include "vmwgfx_saa_priv.h" 41#include <dri3.h> 42#include <misyncshm.h> 43#include <xf86drm.h> 44#include <unistd.h> 45 46 47/** 48 * \brief DRI3 fd_from_pixmap callback. 49 * 50 */ 51static int 52vmwgfx_dri3_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, 53 CARD16 *stride, CARD32 *size) 54{ 55 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(pixmap); 56 uint32_t handle; 57 unsigned int byte_stride; 58 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 59 60 if (!vmwgfx_hw_dri2_validate(pixmap, 0)) { 61 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 62 "DRI3 pixmap export failed to create HW surface.\n"); 63 return -1; 64 } 65 66 if (xa_surface_handle(vpix->hw, xa_handle_type_fd, &handle, 67 &byte_stride)) { 68 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 69 "DRI3 pixmap export failed to create handle.\n"); 70 return -1; 71 } 72 73 *stride = byte_stride; 74 *size = byte_stride * pixmap->drawable.height; 75 76 /* 77 * hw_is_dri2_fronts will make sure any software rendering to 78 * this pixmap is immediately flushed to the underlying surface. 79 * Strictly, we could wait for glxWaitX to do that, but alas, 80 * even the dri3 glxWaitX appears as broken as the dri2 version. 81 * If we, however, wanted to do that, we'd hook up a shm fence 82 * trigger callback. (Like glamor does). 83 */ 84 vpix->hw_is_dri2_fronts = 1; 85 86 return handle; 87} 88 89/** 90 * \brief DRI3 pixmap_from_fd callback. 91 * 92 */ 93static PixmapPtr 94vmwgfx_dri3_pixmap_from_fd(ScreenPtr screen, int fd, 95 CARD16 width, CARD16 height, CARD16 stride, 96 CARD8 depth, CARD8 bpp) 97{ 98 struct vmwgfx_saa *vsaa = to_vmwgfx_saa(saa_get_driver(screen)); 99 struct xa_surface *srf; 100 struct vmwgfx_saa_pixmap *vpix; 101 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 102 PixmapPtr pixmap; 103 104 if (width == 0 || height == 0 || 105 depth < 15 || bpp != BitsPerPixel(depth) || stride < width * bpp / 8) 106 return NULL; 107 108 pixmap = screen->CreatePixmap(screen, width, height, depth, 0); 109 if (!pixmap) { 110 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DRI3 pixmap creation failed.\n"); 111 return NULL; 112 } 113 114 vpix = vmwgfx_saa_pixmap(pixmap); 115 116 if (!vmwgfx_hw_dri2_stage(pixmap, depth)) { 117 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 118 "DRI3 pixmap creation bad format.\n"); 119 goto out_bad_format; 120 } 121 122 srf = xa_surface_from_handle2(vsaa->xat, width, height, depth, 123 xa_type_other, 124 vpix->staging_format, 125 vpix->staging_add_flags, 126 xa_handle_type_fd, 127 fd, stride); 128 if (!srf) { 129 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 130 "DRI3 pixmap creation surface sharing failed.\n"); 131 goto out_bad_format; 132 } 133 134 vpix->xa_flags = vpix->staging_add_flags; 135 vpix->hw = srf; 136 if (!vmwgfx_create_hw(vsaa, pixmap, TRUE)) { 137 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 138 "DRI3 pixmap creation failed SAA enabling.\n"); 139 goto out_no_damage; 140 } 141 142 vpix->hw_is_dri2_fronts = 1; 143 return pixmap; 144 145 out_no_damage: 146 xa_surface_unref(srf); 147 out_bad_format: 148 screen->DestroyPixmap(pixmap); 149 150 return NULL; 151} 152 153/** 154 * \brief Open a render node. 155 * 156 * \param screen[IN] Pointer to the screen 157 * \return A valid file descriptor or -1 on failure. 158 */ 159static int 160vmwgfx_dri3_open_render(ScreenPtr screen) 161{ 162 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 163 modesettingPtr ms = modesettingPTR(pScrn); 164 char bus_id[64]; 165 int fd; 166 167 snprintf(bus_id, sizeof(bus_id), "PCI:%d:%d:%d", 168 ((ms->PciInfo->domain << 8) | ms->PciInfo->bus), 169 ms->PciInfo->dev, ms->PciInfo->func); 170 171 /* Render nodes can't be opened by busid yet.. */ 172 fd = drmOpenWithType("vmwgfx", bus_id, DRM_NODE_RENDER); 173 if (fd < 0) 174 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 175 "DRI3 client open busid \"%s\" failed.\n", bus_id); 176 177 return fd; 178} 179 180/** 181 * \brief DRI3 open_client callback. 182 * 183 */ 184static int 185vmwgfx_dri3_open_client(ClientPtr client, ScreenPtr screen, 186 RRProviderPtr provider, int *pfd) 187{ 188 *pfd = vmwgfx_dri3_open_render(screen); 189 190 return (*pfd >= 0) ? Success : BadAlloc; 191} 192 193/** 194 * \brief Verify that surface sharing between render client and X server 195 * works. 196 * 197 * \param screen[IN,OUT] A pointer to the current screen. 198 * \return TRUE if successful, FALSE otherwise. 199 * 200 * Opens a render client, creates a surface and tries to share that surface 201 * with the X server. There is a vmwgfx kernel driver bug that, combined 202 * with a pre-guest-backed-surface svga mesa driver bug, 203 * prevents this sharing to happen and thus breaks dri3. 204 * 205 * Also, we need to make sure that we can share an XRGB surface as an 206 * ARGB surface since DRI3 does not appear to be as strict about internal 207 * surface formats as DRI2. 208 */ 209static Bool 210vmwgfx_dri3_verify_sharing(ScreenPtr screen) 211{ 212 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 213 modesettingPtr ms = modesettingPTR(pScrn); 214 int fd = vmwgfx_dri3_open_render(screen); 215 struct xa_tracker *xat; 216 struct xa_surface *srf1; 217 unsigned int stride; 218 uint32_t handle; 219 Bool ret = FALSE; 220 221 if (fd < 0) 222 return FALSE; 223 224 xat = xa_tracker_create(fd); 225 if (!xat) 226 goto out_no_xa; 227 228 /* Here we're the render client (xat) */ 229 srf1 = xa_surface_create(xat, 16, 16, 32, xa_type_argb, 230 xa_format_unknown, 231 XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED); 232 if (!srf1) 233 goto out_no_surface; 234 235 if (xa_surface_handle(srf1, xa_handle_type_fd, &handle, &stride) != 236 XA_ERR_NONE) 237 goto out_no_handle; 238 239 xa_surface_unref(srf1); 240 241 /* Now we're the X server (ms->xat) */ 242 srf1 = xa_surface_from_handle2(ms->xat, 16, 16, 24, xa_type_argb, 243 xa_format_unknown, 244 XA_FLAG_RENDER_TARGET | XA_FLAG_SHARED, 245 xa_handle_type_fd, handle, stride); 246 if (!srf1) 247 goto out_no_surface; 248 249 ret = TRUE; 250 close(handle); 251 252 out_no_handle: 253 xa_surface_unref(srf1); 254 out_no_surface: 255 xa_tracker_destroy(xat); 256 out_no_xa: 257 close(fd); 258 259 return ret; 260} 261 262static dri3_screen_info_rec vmwgfx_dri3_info = { 263 .version = 1, 264 .open = NULL, 265 .pixmap_from_fd = vmwgfx_dri3_pixmap_from_fd, 266 .fd_from_pixmap = vmwgfx_dri3_fd_from_pixmap, 267 .open_client = vmwgfx_dri3_open_client, 268}; 269 270 271/** 272 * \brief Initialize dri3. 273 * 274 * \param screen[IN,OUT] A pointer to the current screen. 275 * \return TRUE if successful, FALSE otherwise. 276 */ 277Bool 278vmwgfx_dri3_init(ScreenPtr screen) 279{ 280 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); 281 282 if (!vmwgfx_dri3_verify_sharing(screen)) { 283 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 284 "Failed to verify XA surface sharing for DRI3.\n"); 285 return FALSE; 286 } 287 288 if (!miSyncShmScreenInit(screen)) { 289 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 290 "Failed to initialize xshm sync for DRI3.\n"); 291 return FALSE; 292 } 293 294 if (!dri3_screen_init(screen, &vmwgfx_dri3_info)) { 295 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to initialize DRI3.\n"); 296 return FALSE; 297 } 298 299 return TRUE; 300} 301 302#else /* XA INCLUDES SUFFICIENT */ 303Bool 304vmwgfx_dri3_init(ScreenPtr screen) 305{ 306 return FALSE; 307} 308 309#endif /* !XA INCLUDES SUFFICIENT */ 310#endif /* DRI3 */ 311