dri2ext.c revision 52397711
1/* 2 * Copyright © 2008 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Soft- 6 * ware"), to deal in the Software without restriction, including without 7 * limitation the rights to use, copy, modify, merge, publish, distribute, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, provided that the above copyright 10 * notice(s) and this permission notice appear in all copies of the Soft- 11 * ware and that both the above copyright notice(s) and this permission 12 * notice appear in supporting documentation. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 22 * MANCE OF THIS SOFTWARE. 23 * 24 * Except as contained in this notice, the name of a copyright holder shall 25 * not be used in advertising or otherwise to promote the sale, use or 26 * other dealings in this Software without prior written authorization of 27 * the copyright holder. 28 * 29 * Authors: 30 * Kristian Høgsberg (krh@redhat.com) 31 */ 32 33#ifdef HAVE_XORG_CONFIG_H 34#include <xorg-config.h> 35#endif 36 37#define NEED_REPLIES 38#include <X11/X.h> 39#include <X11/Xproto.h> 40#include <X11/extensions/dri2proto.h> 41#include <X11/extensions/xfixeswire.h> 42#include "dixstruct.h" 43#include "scrnintstr.h" 44#include "pixmapstr.h" 45#include "extnsionst.h" 46#include "xf86drm.h" 47#include "xfixes.h" 48#include "dri2.h" 49 50/* The only xf86 include */ 51#include "xf86Module.h" 52 53static ExtensionEntry *dri2Extension; 54static RESTYPE dri2DrawableRes; 55 56static Bool 57validDrawable(ClientPtr client, XID drawable, 58 DrawablePtr *pDrawable, int *status) 59{ 60 *status = dixLookupDrawable(pDrawable, drawable, client, 0, DixReadAccess); 61 if (*status != Success) { 62 client->errorValue = drawable; 63 return FALSE; 64 } 65 66 return TRUE; 67} 68 69static int 70ProcDRI2QueryVersion(ClientPtr client) 71{ 72 REQUEST(xDRI2QueryVersionReq); 73 xDRI2QueryVersionReply rep; 74 int n; 75 76 if (client->swapped) 77 swaps(&stuff->length, n); 78 79 REQUEST_SIZE_MATCH(xDRI2QueryVersionReq); 80 rep.type = X_Reply; 81 rep.length = 0; 82 rep.sequenceNumber = client->sequence; 83 rep.majorVersion = 1; 84 rep.minorVersion = 1; 85 86 if (client->swapped) { 87 swaps(&rep.sequenceNumber, n); 88 swapl(&rep.length, n); 89 swapl(&rep.majorVersion, n); 90 swapl(&rep.minorVersion, n); 91 } 92 93 WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep); 94 95 return client->noClientException; 96} 97 98static int 99ProcDRI2Connect(ClientPtr client) 100{ 101 REQUEST(xDRI2ConnectReq); 102 xDRI2ConnectReply rep; 103 DrawablePtr pDraw; 104 int fd, status; 105 const char *driverName; 106 const char *deviceName; 107 108 REQUEST_SIZE_MATCH(xDRI2ConnectReq); 109 if (!validDrawable(client, stuff->window, &pDraw, &status)) 110 return status; 111 112 rep.type = X_Reply; 113 rep.length = 0; 114 rep.sequenceNumber = client->sequence; 115 rep.driverNameLength = 0; 116 rep.deviceNameLength = 0; 117 118 if (!DRI2Connect(pDraw->pScreen, 119 stuff->driverType, &fd, &driverName, &deviceName)) 120 goto fail; 121 122 rep.driverNameLength = strlen(driverName); 123 rep.deviceNameLength = strlen(deviceName); 124 rep.length = (rep.driverNameLength + 3) / 4 + 125 (rep.deviceNameLength + 3) / 4; 126 127 fail: 128 WriteToClient(client, sizeof(xDRI2ConnectReply), &rep); 129 WriteToClient(client, rep.driverNameLength, driverName); 130 WriteToClient(client, rep.deviceNameLength, deviceName); 131 132 return client->noClientException; 133} 134 135static int 136ProcDRI2Authenticate(ClientPtr client) 137{ 138 REQUEST(xDRI2AuthenticateReq); 139 xDRI2AuthenticateReply rep; 140 DrawablePtr pDraw; 141 int status; 142 143 REQUEST_SIZE_MATCH(xDRI2AuthenticateReq); 144 if (!validDrawable(client, stuff->window, &pDraw, &status)) 145 return status; 146 147 rep.type = X_Reply; 148 rep.sequenceNumber = client->sequence; 149 rep.length = 0; 150 rep.authenticated = DRI2Authenticate(pDraw->pScreen, stuff->magic); 151 WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep); 152 153 return client->noClientException; 154} 155 156static int 157ProcDRI2CreateDrawable(ClientPtr client) 158{ 159 REQUEST(xDRI2CreateDrawableReq); 160 DrawablePtr pDrawable; 161 int status; 162 163 REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq); 164 165 if (!validDrawable(client, stuff->drawable, &pDrawable, &status)) 166 return status; 167 168 status = DRI2CreateDrawable(pDrawable); 169 if (status != Success) 170 return status; 171 172 if (!AddResource(stuff->drawable, dri2DrawableRes, pDrawable)) { 173 DRI2DestroyDrawable(pDrawable); 174 return BadAlloc; 175 } 176 177 return client->noClientException; 178} 179 180static int 181ProcDRI2DestroyDrawable(ClientPtr client) 182{ 183 REQUEST(xDRI2DestroyDrawableReq); 184 DrawablePtr pDrawable; 185 int status; 186 187 REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq); 188 if (!validDrawable(client, stuff->drawable, &pDrawable, &status)) 189 return status; 190 191 FreeResourceByType(stuff->drawable, dri2DrawableRes, FALSE); 192 193 return client->noClientException; 194} 195 196 197static void 198send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, 199 DRI2Buffer2Ptr *buffers, int count, int width, int height) 200{ 201 xDRI2GetBuffersReply rep; 202 int skip = 0; 203 int i; 204 205 if (pDrawable->type == DRAWABLE_WINDOW) { 206 for (i = 0; i < count; i++) { 207 /* Do not send the real front buffer of a window to the client. 208 */ 209 if (buffers[i]->attachment == DRI2BufferFrontLeft) { 210 skip++; 211 continue; 212 } 213 } 214 } 215 216 rep.type = X_Reply; 217 rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4; 218 rep.sequenceNumber = client->sequence; 219 rep.width = width; 220 rep.height = height; 221 rep.count = count - skip; 222 WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep); 223 224 for (i = 0; i < count; i++) { 225 xDRI2Buffer buffer; 226 227 /* Do not send the real front buffer of a window to the client. 228 */ 229 if ((pDrawable->type == DRAWABLE_WINDOW) 230 && (buffers[i]->attachment == DRI2BufferFrontLeft)) { 231 continue; 232 } 233 234 buffer.attachment = buffers[i]->attachment; 235 buffer.name = buffers[i]->name; 236 buffer.pitch = buffers[i]->pitch; 237 buffer.cpp = buffers[i]->cpp; 238 buffer.flags = buffers[i]->flags; 239 WriteToClient(client, sizeof(xDRI2Buffer), &buffer); 240 } 241} 242 243 244static int 245ProcDRI2GetBuffers(ClientPtr client) 246{ 247 REQUEST(xDRI2GetBuffersReq); 248 DrawablePtr pDrawable; 249 DRI2Buffer2Ptr *buffers; 250 int status, width, height, count; 251 unsigned int *attachments; 252 253 REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4); 254 if (!validDrawable(client, stuff->drawable, &pDrawable, &status)) 255 return status; 256 257 attachments = (unsigned int *) &stuff[1]; 258 buffers = DRI2GetBuffers(pDrawable, &width, &height, 259 attachments, stuff->count, &count); 260 261 262 send_buffers_reply(client, pDrawable, buffers, count, width, height); 263 264 return client->noClientException; 265} 266 267static int 268ProcDRI2GetBuffersWithFormat(ClientPtr client) 269{ 270 REQUEST(xDRI2GetBuffersReq); 271 DrawablePtr pDrawable; 272 DRI2Buffer2Ptr *buffers; 273 int status, width, height, count; 274 unsigned int *attachments; 275 276 REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * (2 * 4)); 277 if (!validDrawable(client, stuff->drawable, &pDrawable, &status)) 278 return status; 279 280 attachments = (unsigned int *) &stuff[1]; 281 buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height, 282 attachments, stuff->count, &count); 283 284 send_buffers_reply(client, pDrawable, buffers, count, width, height); 285 286 return client->noClientException; 287} 288 289static int 290ProcDRI2CopyRegion(ClientPtr client) 291{ 292 REQUEST(xDRI2CopyRegionReq); 293 xDRI2CopyRegionReply rep; 294 DrawablePtr pDrawable; 295 int status; 296 RegionPtr pRegion; 297 298 REQUEST_SIZE_MATCH(xDRI2CopyRegionReq); 299 300 if (!validDrawable(client, stuff->drawable, &pDrawable, &status)) 301 return status; 302 303 VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess); 304 305 status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src); 306 if (status != Success) 307 return status; 308 309 /* CopyRegion needs to be a round trip to make sure the X server 310 * queues the swap buffer rendering commands before the DRI client 311 * continues rendering. The reply has a bitmask to signal the 312 * presense of optional return values as well, but we're not using 313 * that yet. 314 */ 315 316 rep.type = X_Reply; 317 rep.length = 0; 318 rep.sequenceNumber = client->sequence; 319 320 WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep); 321 322 return client->noClientException; 323} 324 325static int 326ProcDRI2Dispatch (ClientPtr client) 327{ 328 REQUEST(xReq); 329 330 switch (stuff->data) { 331 case X_DRI2QueryVersion: 332 return ProcDRI2QueryVersion(client); 333 } 334 335 if (!LocalClient(client)) 336 return BadRequest; 337 338 switch (stuff->data) { 339 case X_DRI2Connect: 340 return ProcDRI2Connect(client); 341 case X_DRI2Authenticate: 342 return ProcDRI2Authenticate(client); 343 case X_DRI2CreateDrawable: 344 return ProcDRI2CreateDrawable(client); 345 case X_DRI2DestroyDrawable: 346 return ProcDRI2DestroyDrawable(client); 347 case X_DRI2GetBuffers: 348 return ProcDRI2GetBuffers(client); 349 case X_DRI2CopyRegion: 350 return ProcDRI2CopyRegion(client); 351 case X_DRI2GetBuffersWithFormat: 352 return ProcDRI2GetBuffersWithFormat(client); 353 default: 354 return BadRequest; 355 } 356} 357 358static int 359SProcDRI2Connect(ClientPtr client) 360{ 361 REQUEST(xDRI2ConnectReq); 362 xDRI2ConnectReply rep; 363 int n; 364 365 /* If the client is swapped, it's not local. Talk to the hand. */ 366 367 swaps(&stuff->length, n); 368 if (sizeof(*stuff) / 4 != client->req_len) 369 return BadLength; 370 371 rep.sequenceNumber = client->sequence; 372 swaps(&rep.sequenceNumber, n); 373 rep.length = 0; 374 rep.driverNameLength = 0; 375 rep.deviceNameLength = 0; 376 377 return client->noClientException; 378} 379 380static int 381SProcDRI2Dispatch (ClientPtr client) 382{ 383 REQUEST(xReq); 384 385 /* 386 * Only local clients are allowed DRI access, but remote clients 387 * still need these requests to find out cleanly. 388 */ 389 switch (stuff->data) 390 { 391 case X_DRI2QueryVersion: 392 return ProcDRI2QueryVersion(client); 393 case X_DRI2Connect: 394 return SProcDRI2Connect(client); 395 default: 396 return BadRequest; 397 } 398} 399 400static int DRI2DrawableGone(pointer p, XID id) 401{ 402 DrawablePtr pDrawable = p; 403 404 DRI2DestroyDrawable(pDrawable); 405 406 return Success; 407} 408 409static void 410DRI2ExtensionInit(void) 411{ 412 dri2Extension = AddExtension(DRI2_NAME, 413 DRI2NumberEvents, 414 DRI2NumberErrors, 415 ProcDRI2Dispatch, 416 SProcDRI2Dispatch, 417 NULL, 418 StandardMinorOpcode); 419 420 dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone); 421} 422 423extern Bool noDRI2Extension; 424 425_X_HIDDEN ExtensionModule dri2ExtensionModule = { 426 DRI2ExtensionInit, 427 DRI2_NAME, 428 &noDRI2Extension, 429 NULL, 430 NULL 431}; 432