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
30 RESTYPE RRProviderType = 0;
31
32 /*
33 * Initialize provider type error value
34 */
35 void
RRProviderInitErrorValue(void)36 RRProviderInitErrorValue(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
51 int
ProcRRGetProviders(ClientPtr client)52 ProcRRGetProviders (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
133 int
ProcRRGetProviderInfo(ClientPtr client)134 ProcRRGetProviderInfo (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
264 static void
RRInitPrimeSyncProps(ScreenPtr pScreen)265 RRInitPrimeSyncProps(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
294 static void
RRFiniPrimeSyncProps(ScreenPtr pScreen)295 RRFiniPrimeSyncProps(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
316 int
ProcRRSetProviderOutputSource(ClientPtr client)317 ProcRRSetProviderOutputSource(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
356 int
ProcRRSetProviderOffloadSink(ClientPtr client)357 ProcRRSetProviderOffloadSink(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
390 RRProviderPtr
RRProviderCreate(ScreenPtr pScreen,const char * name,int nameLength)391 RRProviderCreate(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 */
420 void
RRProviderDestroy(RRProviderPtr provider)421 RRProviderDestroy (RRProviderPtr provider)
422 {
423 RRFiniPrimeSyncProps(provider->pScreen);
424 FreeResource (provider->id, 0);
425 }
426
427 void
RRProviderSetCapabilities(RRProviderPtr provider,uint32_t capabilities)428 RRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities)
429 {
430 provider->capabilities = capabilities;
431 }
432
433 static int
RRProviderDestroyResource(void * value,XID pid)434 RRProviderDestroyResource (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
451 Bool
RRProviderInit(void)452 RRProviderInit(void)
453 {
454 RRProviderType = CreateNewResourceType(RRProviderDestroyResource, "Provider");
455 if (!RRProviderType)
456 return FALSE;
457
458 return TRUE;
459 }
460
461 extern _X_EXPORT Bool
RRProviderLookup(XID id,RRProviderPtr * provider_p)462 RRProviderLookup(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
471 void
RRDeliverProviderEvent(ClientPtr client,WindowPtr pWin,RRProviderPtr provider)472 RRDeliverProviderEvent(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