rrprovider.c revision a035e2b2
1/* 2 * Copyright © 2012 Red Hat Inc. 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 * 22 * Authors: Dave Airlie 23 */ 24 25#include "randrstr.h" 26#include "swaprep.h" 27 28#include <X11/Xatom.h> 29 30RESTYPE RRProviderType = 0; 31 32/* 33 * Initialize provider type error value 34 */ 35void 36RRProviderInitErrorValue(void) 37{ 38 SetResourceTypeErrorValue(RRProviderType, RRErrorBase + BadRRProvider); 39} 40 41#define ADD_PROVIDER(_pScreen) do { \ 42 pScrPriv = rrGetScrPriv((_pScreen)); \ 43 if (pScrPriv->provider) { \ 44 providers[count_providers] = pScrPriv->provider->id; \ 45 if (client->swapped) \ 46 swapl(&providers[count_providers]); \ 47 count_providers++; \ 48 } \ 49 } while(0) 50 51int 52ProcRRGetProviders (ClientPtr client) 53{ 54 REQUEST(xRRGetProvidersReq); 55 xRRGetProvidersReply rep; 56 WindowPtr pWin; 57 ScreenPtr pScreen; 58 rrScrPrivPtr pScrPriv; 59 int rc; 60 CARD8 *extra; 61 unsigned int extraLen; 62 RRProvider *providers; 63 int total_providers = 0, count_providers = 0; 64 ScreenPtr iter; 65 66 REQUEST_SIZE_MATCH(xRRGetProvidersReq); 67 rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); 68 if (rc != Success) 69 return rc; 70 71 pScreen = pWin->drawable.pScreen; 72 73 pScrPriv = rrGetScrPriv(pScreen); 74 75 if (pScrPriv->provider) 76 total_providers++; 77 xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { 78 pScrPriv = rrGetScrPriv(iter); 79 total_providers += pScrPriv->provider ? 1 : 0; 80 } 81 82 pScrPriv = rrGetScrPriv(pScreen); 83 84 if (!pScrPriv) 85 { 86 rep = (xRRGetProvidersReply) { 87 .type = X_Reply, 88 .sequenceNumber = client->sequence, 89 .length = 0, 90 .timestamp = currentTime.milliseconds, 91 .nProviders = 0 92 }; 93 extra = NULL; 94 extraLen = 0; 95 } else { 96 rep = (xRRGetProvidersReply) { 97 .type = X_Reply, 98 .sequenceNumber = client->sequence, 99 .timestamp = pScrPriv->lastSetTime.milliseconds, 100 .nProviders = total_providers, 101 .length = total_providers 102 }; 103 extraLen = rep.length << 2; 104 if (extraLen) { 105 extra = malloc(extraLen); 106 if (!extra) 107 return BadAlloc; 108 } else 109 extra = NULL; 110 111 providers = (RRProvider *)extra; 112 ADD_PROVIDER(pScreen); 113 xorg_list_for_each_entry(iter, &pScreen->slave_list, slave_head) { 114 ADD_PROVIDER(iter); 115 } 116 } 117 118 if (client->swapped) { 119 swaps(&rep.sequenceNumber); 120 swapl(&rep.length); 121 swapl(&rep.timestamp); 122 swaps(&rep.nProviders); 123 } 124 WriteToClient(client, sizeof(xRRGetProvidersReply), (char *)&rep); 125 if (extraLen) 126 { 127 WriteToClient (client, extraLen, (char *) extra); 128 free(extra); 129 } 130 return Success; 131} 132 133int 134ProcRRGetProviderInfo (ClientPtr client) 135{ 136 REQUEST(xRRGetProviderInfoReq); 137 xRRGetProviderInfoReply rep; 138 rrScrPrivPtr pScrPriv, pScrProvPriv; 139 RRProviderPtr provider; 140 ScreenPtr pScreen; 141 CARD8 *extra; 142 unsigned int extraLen = 0; 143 RRCrtc *crtcs; 144 RROutput *outputs; 145 int i; 146 char *name; 147 ScreenPtr provscreen; 148 RRProvider *providers; 149 uint32_t *prov_cap; 150 151 REQUEST_SIZE_MATCH(xRRGetProviderInfoReq); 152 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); 153 154 pScreen = provider->pScreen; 155 pScrPriv = rrGetScrPriv(pScreen); 156 157 rep = (xRRGetProviderInfoReply) { 158 .type = X_Reply, 159 .status = RRSetConfigSuccess, 160 .sequenceNumber = client->sequence, 161 .length = 0, 162 .capabilities = provider->capabilities, 163 .nameLength = provider->nameLength, 164 .timestamp = pScrPriv->lastSetTime.milliseconds, 165 .nCrtcs = pScrPriv->numCrtcs, 166 .nOutputs = pScrPriv->numOutputs, 167 .nAssociatedProviders = 0 168 }; 169 170 /* count associated providers */ 171 if (provider->offload_sink) 172 rep.nAssociatedProviders++; 173 if (provider->output_source && 174 provider->output_source != provider->offload_sink) 175 rep.nAssociatedProviders++; 176 xorg_list_for_each_entry(provscreen, &pScreen->slave_list, slave_head) { 177 if (provscreen->is_output_slave || provscreen->is_offload_slave) 178 rep.nAssociatedProviders++; 179 } 180 181 rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs + 182 (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength)); 183 184 extraLen = rep.length << 2; 185 if (extraLen) { 186 extra = malloc(extraLen); 187 if (!extra) 188 return BadAlloc; 189 } 190 else 191 extra = NULL; 192 193 crtcs = (RRCrtc *)extra; 194 outputs = (RROutput *)(crtcs + rep.nCrtcs); 195 providers = (RRProvider *)(outputs + rep.nOutputs); 196 prov_cap = (unsigned int *)(providers + rep.nAssociatedProviders); 197 name = (char *)(prov_cap + rep.nAssociatedProviders); 198 199 for (i = 0; i < pScrPriv->numCrtcs; i++) { 200 crtcs[i] = pScrPriv->crtcs[i]->id; 201 if (client->swapped) 202 swapl(&crtcs[i]); 203 } 204 205 for (i = 0; i < pScrPriv->numOutputs; i++) { 206 outputs[i] = pScrPriv->outputs[i]->id; 207 if (client->swapped) 208 swapl(&outputs[i]); 209 } 210 211 i = 0; 212 if (provider->offload_sink) { 213 providers[i] = provider->offload_sink->id; 214 if (client->swapped) 215 swapl(&providers[i]); 216 prov_cap[i] = RR_Capability_SinkOffload; 217 if (client->swapped) 218 swapl(&prov_cap[i]); 219 i++; 220 } 221 if (provider->output_source) { 222 providers[i] = provider->output_source->id; 223 if (client->swapped) 224 swapl(&providers[i]); 225 prov_cap[i] = RR_Capability_SourceOutput; 226 swapl(&prov_cap[i]); 227 i++; 228 } 229 xorg_list_for_each_entry(provscreen, &pScreen->slave_list, slave_head) { 230 if (!provscreen->is_output_slave && !provscreen->is_offload_slave) 231 continue; 232 pScrProvPriv = rrGetScrPriv(provscreen); 233 providers[i] = pScrProvPriv->provider->id; 234 if (client->swapped) 235 swapl(&providers[i]); 236 prov_cap[i] = 0; 237 if (provscreen->is_output_slave) 238 prov_cap[i] |= RR_Capability_SinkOutput; 239 if (provscreen->is_offload_slave) 240 prov_cap[i] |= RR_Capability_SourceOffload; 241 if (client->swapped) 242 swapl(&prov_cap[i]); 243 i++; 244 } 245 246 memcpy(name, provider->name, rep.nameLength); 247 if (client->swapped) { 248 swaps(&rep.sequenceNumber); 249 swapl(&rep.length); 250 swapl(&rep.capabilities); 251 swaps(&rep.nCrtcs); 252 swaps(&rep.nOutputs); 253 swaps(&rep.nameLength); 254 } 255 WriteToClient(client, sizeof(xRRGetProviderInfoReply), (char *)&rep); 256 if (extraLen) 257 { 258 WriteToClient (client, extraLen, (char *) extra); 259 free(extra); 260 } 261 return Success; 262} 263 264static void 265RRInitPrimeSyncProps(ScreenPtr pScreen) 266{ 267 /* 268 * TODO: When adding support for different sources for different outputs, 269 * make sure this sets up the output properties only on outputs associated 270 * with the correct source provider. 271 */ 272 273 rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen); 274 275 const char *syncStr = PRIME_SYNC_PROP; 276 Atom syncProp = MakeAtom(syncStr, strlen(syncStr), TRUE); 277 278 int defaultVal = TRUE; 279 INT32 validVals[2] = {FALSE, TRUE}; 280 281 int i; 282 for (i = 0; i < pScrPriv->numOutputs; i++) { 283 if (!RRQueryOutputProperty(pScrPriv->outputs[i], syncProp)) { 284 RRConfigureOutputProperty(pScrPriv->outputs[i], syncProp, 285 TRUE, FALSE, FALSE, 286 2, &validVals[0]); 287 RRChangeOutputProperty(pScrPriv->outputs[i], syncProp, XA_INTEGER, 288 8, PropModeReplace, 1, &defaultVal, 289 FALSE, FALSE); 290 } 291 } 292} 293 294static void 295RRFiniPrimeSyncProps(ScreenPtr pScreen) 296{ 297 /* 298 * TODO: When adding support for different sources for different outputs, 299 * make sure this tears down the output properties only on outputs 300 * associated with the correct source provider. 301 */ 302 303 rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen); 304 int i; 305 306 const char *syncStr = PRIME_SYNC_PROP; 307 Atom syncProp = MakeAtom(syncStr, strlen(syncStr), FALSE); 308 if (syncProp == None) 309 return; 310 311 for (i = 0; i < pScrPriv->numOutputs; i++) { 312 RRDeleteOutputProperty(pScrPriv->outputs[i], syncProp); 313 } 314} 315 316int 317ProcRRSetProviderOutputSource(ClientPtr client) 318{ 319 REQUEST(xRRSetProviderOutputSourceReq); 320 rrScrPrivPtr pScrPriv; 321 RRProviderPtr provider, source_provider = NULL; 322 ScreenPtr pScreen; 323 324 REQUEST_SIZE_MATCH(xRRSetProviderOutputSourceReq); 325 326 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); 327 328 if (!(provider->capabilities & RR_Capability_SinkOutput)) 329 return BadValue; 330 331 if (stuff->source_provider) { 332 VERIFY_RR_PROVIDER(stuff->source_provider, source_provider, DixReadAccess); 333 334 if (!(source_provider->capabilities & RR_Capability_SourceOutput)) 335 return BadValue; 336 } 337 338 pScreen = provider->pScreen; 339 pScrPriv = rrGetScrPriv(pScreen); 340 341 if (!pScreen->isGPU) 342 return BadValue; 343 344 pScrPriv->rrProviderSetOutputSource(pScreen, provider, source_provider); 345 346 RRInitPrimeSyncProps(pScreen); 347 348 provider->changed = TRUE; 349 RRSetChanged(pScreen); 350 351 RRTellChanged (pScreen); 352 353 return Success; 354} 355 356int 357ProcRRSetProviderOffloadSink(ClientPtr client) 358{ 359 REQUEST(xRRSetProviderOffloadSinkReq); 360 rrScrPrivPtr pScrPriv; 361 RRProviderPtr provider, sink_provider = NULL; 362 ScreenPtr pScreen; 363 364 REQUEST_SIZE_MATCH(xRRSetProviderOffloadSinkReq); 365 366 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); 367 if (!(provider->capabilities & RR_Capability_SourceOffload)) 368 return BadValue; 369 if (!provider->pScreen->isGPU) 370 return BadValue; 371 372 if (stuff->sink_provider) { 373 VERIFY_RR_PROVIDER(stuff->sink_provider, sink_provider, DixReadAccess); 374 if (!(sink_provider->capabilities & RR_Capability_SinkOffload)) 375 return BadValue; 376 } 377 pScreen = provider->pScreen; 378 pScrPriv = rrGetScrPriv(pScreen); 379 380 pScrPriv->rrProviderSetOffloadSink(pScreen, provider, sink_provider); 381 382 provider->changed = TRUE; 383 RRSetChanged(pScreen); 384 385 RRTellChanged (pScreen); 386 387 return Success; 388} 389 390RRProviderPtr 391RRProviderCreate(ScreenPtr pScreen, const char *name, 392 int nameLength) 393{ 394 RRProviderPtr provider; 395 rrScrPrivPtr pScrPriv; 396 397 pScrPriv = rrGetScrPriv(pScreen); 398 399 provider = calloc(1, sizeof(RRProviderRec) + nameLength + 1); 400 if (!provider) 401 return NULL; 402 403 provider->id = FakeClientID(0); 404 provider->pScreen = pScreen; 405 provider->name = (char *) (provider + 1); 406 provider->nameLength = nameLength; 407 memcpy(provider->name, name, nameLength); 408 provider->name[nameLength] = '\0'; 409 provider->changed = FALSE; 410 411 if (!AddResource (provider->id, RRProviderType, (void *) provider)) 412 return NULL; 413 pScrPriv->provider = provider; 414 return provider; 415} 416 417/* 418 * Destroy a provider at shutdown 419 */ 420void 421RRProviderDestroy (RRProviderPtr provider) 422{ 423 RRFiniPrimeSyncProps(provider->pScreen); 424 FreeResource (provider->id, 0); 425} 426 427void 428RRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities) 429{ 430 provider->capabilities = capabilities; 431} 432 433static int 434RRProviderDestroyResource (void *value, XID pid) 435{ 436 RRProviderPtr provider = (RRProviderPtr)value; 437 ScreenPtr pScreen = provider->pScreen; 438 439 if (pScreen) 440 { 441 rrScrPriv(pScreen); 442 443 if (pScrPriv->rrProviderDestroy) 444 (*pScrPriv->rrProviderDestroy)(pScreen, provider); 445 pScrPriv->provider = NULL; 446 } 447 free(provider); 448 return 1; 449} 450 451Bool 452RRProviderInit(void) 453{ 454 RRProviderType = CreateNewResourceType(RRProviderDestroyResource, "Provider"); 455 if (!RRProviderType) 456 return FALSE; 457 458 return TRUE; 459} 460 461extern _X_EXPORT Bool 462RRProviderLookup(XID id, RRProviderPtr *provider_p) 463{ 464 int rc = dixLookupResourceByType((void **)provider_p, id, 465 RRProviderType, NullClient, DixReadAccess); 466 if (rc == Success) 467 return TRUE; 468 return FALSE; 469} 470 471void 472RRDeliverProviderEvent(ClientPtr client, WindowPtr pWin, RRProviderPtr provider) 473{ 474 ScreenPtr pScreen = pWin->drawable.pScreen; 475 476 rrScrPriv(pScreen); 477 478 xRRProviderChangeNotifyEvent pe = { 479 .type = RRNotify + RREventBase, 480 .subCode = RRNotify_ProviderChange, 481 .timestamp = pScrPriv->lastSetTime.milliseconds, 482 .window = pWin->drawable.id, 483 .provider = provider->id 484 }; 485 486 WriteEventsToClient(client, 1, (xEvent *) &pe); 487} 488