Commit | Line | Data |
---|---|---|
a09e091a JB |
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 | RESTYPE RRProviderType; | |
29 | ||
30 | /* | |
31 | * Initialize provider type error value | |
32 | */ | |
33 | void | |
34 | RRProviderInitErrorValue(void) | |
35 | { | |
36 | SetResourceTypeErrorValue(RRProviderType, RRErrorBase + BadRRProvider); | |
37 | } | |
38 | ||
39 | #define ADD_PROVIDER(_pScreen) do { \ | |
40 | pScrPriv = rrGetScrPriv((_pScreen)); \ | |
41 | if (pScrPriv->provider) { \ | |
42 | providers[count_providers] = pScrPriv->provider->id; \ | |
43 | if (client->swapped) \ | |
44 | swapl(&providers[count_providers]); \ | |
45 | count_providers++; \ | |
46 | } \ | |
47 | } while(0) | |
48 | ||
49 | int | |
50 | ProcRRGetProviders (ClientPtr client) | |
51 | { | |
52 | REQUEST(xRRGetProvidersReq); | |
53 | xRRGetProvidersReply rep; | |
54 | WindowPtr pWin; | |
55 | ScreenPtr pScreen; | |
56 | rrScrPrivPtr pScrPriv; | |
57 | int rc; | |
58 | CARD8 *extra; | |
59 | unsigned int extraLen; | |
60 | RRProvider *providers; | |
61 | int total_providers = 0, count_providers = 0; | |
62 | ScreenPtr iter; | |
63 | ||
64 | REQUEST_SIZE_MATCH(xRRGetProvidersReq); | |
65 | rc = dixLookupWindow(&pWin, stuff->window, client, DixGetAttrAccess); | |
66 | if (rc != Success) | |
67 | return rc; | |
68 | ||
69 | pScreen = pWin->drawable.pScreen; | |
70 | ||
71 | pScrPriv = rrGetScrPriv(pScreen); | |
72 | ||
73 | if (pScrPriv->provider) | |
74 | total_providers++; | |
75 | xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { | |
76 | pScrPriv = rrGetScrPriv(iter); | |
77 | total_providers += pScrPriv->provider ? 1 : 0; | |
78 | } | |
79 | xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) { | |
80 | pScrPriv = rrGetScrPriv(iter); | |
81 | total_providers += pScrPriv->provider ? 1 : 0; | |
82 | } | |
83 | xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) { | |
84 | pScrPriv = rrGetScrPriv(iter); | |
85 | total_providers += pScrPriv->provider ? 1 : 0; | |
86 | } | |
87 | ||
88 | pScrPriv = rrGetScrPriv(pScreen); | |
89 | ||
90 | if (!pScrPriv) | |
91 | { | |
92 | rep = (xRRGetProvidersReply) { | |
93 | .type = X_Reply, | |
94 | .sequenceNumber = client->sequence, | |
95 | .length = 0, | |
96 | .timestamp = currentTime.milliseconds, | |
97 | .nProviders = 0 | |
98 | }; | |
99 | extra = NULL; | |
100 | extraLen = 0; | |
101 | } else { | |
102 | rep = (xRRGetProvidersReply) { | |
103 | .type = X_Reply, | |
104 | .sequenceNumber = client->sequence, | |
105 | .timestamp = pScrPriv->lastSetTime.milliseconds, | |
106 | .nProviders = total_providers, | |
107 | .length = total_providers | |
108 | }; | |
109 | extraLen = rep.length << 2; | |
110 | if (extraLen) { | |
111 | extra = malloc(extraLen); | |
112 | if (!extra) | |
113 | return BadAlloc; | |
114 | } else | |
115 | extra = NULL; | |
116 | ||
117 | providers = (RRProvider *)extra; | |
118 | ADD_PROVIDER(pScreen); | |
119 | xorg_list_for_each_entry(iter, &pScreen->output_slave_list, output_head) { | |
120 | ADD_PROVIDER(iter); | |
121 | } | |
122 | xorg_list_for_each_entry(iter, &pScreen->offload_slave_list, offload_head) { | |
123 | ADD_PROVIDER(iter); | |
124 | } | |
125 | xorg_list_for_each_entry(iter, &pScreen->unattached_list, unattached_head) { | |
126 | ADD_PROVIDER(iter); | |
127 | } | |
128 | } | |
129 | ||
130 | if (client->swapped) { | |
131 | swaps(&rep.sequenceNumber); | |
132 | swapl(&rep.length); | |
133 | swapl(&rep.timestamp); | |
134 | swaps(&rep.nProviders); | |
135 | } | |
136 | WriteToClient(client, sizeof(xRRGetProvidersReply), (char *)&rep); | |
137 | if (extraLen) | |
138 | { | |
139 | WriteToClient (client, extraLen, (char *) extra); | |
140 | free(extra); | |
141 | } | |
142 | return Success; | |
143 | } | |
144 | ||
145 | int | |
146 | ProcRRGetProviderInfo (ClientPtr client) | |
147 | { | |
148 | REQUEST(xRRGetProviderInfoReq); | |
149 | xRRGetProviderInfoReply rep; | |
150 | rrScrPrivPtr pScrPriv, pScrProvPriv; | |
151 | RRProviderPtr provider; | |
152 | ScreenPtr pScreen; | |
153 | CARD8 *extra; | |
154 | unsigned int extraLen = 0; | |
155 | RRCrtc *crtcs; | |
156 | RROutput *outputs; | |
157 | int i; | |
158 | char *name; | |
159 | ScreenPtr provscreen; | |
160 | RRProvider *providers; | |
161 | uint32_t *prov_cap; | |
162 | ||
163 | REQUEST_SIZE_MATCH(xRRGetProviderInfoReq); | |
164 | VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); | |
165 | ||
166 | pScreen = provider->pScreen; | |
167 | pScrPriv = rrGetScrPriv(pScreen); | |
168 | ||
169 | rep = (xRRGetProviderInfoReply) { | |
170 | .type = X_Reply, | |
171 | .status = RRSetConfigSuccess, | |
172 | .sequenceNumber = client->sequence, | |
173 | .length = 0, | |
174 | .capabilities = provider->capabilities, | |
175 | .nameLength = provider->nameLength, | |
176 | .timestamp = pScrPriv->lastSetTime.milliseconds, | |
177 | .nCrtcs = pScrPriv->numCrtcs, | |
178 | .nOutputs = pScrPriv->numOutputs, | |
179 | .nAssociatedProviders = 0 | |
180 | }; | |
181 | ||
182 | /* count associated providers */ | |
183 | if (provider->offload_sink) | |
184 | rep.nAssociatedProviders++; | |
185 | if (provider->output_source) | |
186 | rep.nAssociatedProviders++; | |
187 | xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head) | |
188 | rep.nAssociatedProviders++; | |
189 | xorg_list_for_each_entry(provscreen, &pScreen->offload_slave_list, offload_head) | |
190 | rep.nAssociatedProviders++; | |
191 | ||
192 | rep.length = (pScrPriv->numCrtcs + pScrPriv->numOutputs + | |
193 | (rep.nAssociatedProviders * 2) + bytes_to_int32(rep.nameLength)); | |
194 | ||
195 | extraLen = rep.length << 2; | |
196 | if (extraLen) { | |
197 | extra = malloc(extraLen); | |
198 | if (!extra) | |
199 | return BadAlloc; | |
200 | } | |
201 | else | |
202 | extra = NULL; | |
203 | ||
204 | crtcs = (RRCrtc *)extra; | |
205 | outputs = (RROutput *)(crtcs + rep.nCrtcs); | |
206 | providers = (RRProvider *)(outputs + rep.nOutputs); | |
207 | prov_cap = (unsigned int *)(providers + rep.nAssociatedProviders); | |
208 | name = (char *)(prov_cap + rep.nAssociatedProviders); | |
209 | ||
210 | for (i = 0; i < pScrPriv->numCrtcs; i++) { | |
211 | crtcs[i] = pScrPriv->crtcs[i]->id; | |
212 | if (client->swapped) | |
213 | swapl(&crtcs[i]); | |
214 | } | |
215 | ||
216 | for (i = 0; i < pScrPriv->numOutputs; i++) { | |
217 | outputs[i] = pScrPriv->outputs[i]->id; | |
218 | if (client->swapped) | |
219 | swapl(&outputs[i]); | |
220 | } | |
221 | ||
222 | i = 0; | |
223 | if (provider->offload_sink) { | |
224 | providers[i] = provider->offload_sink->id; | |
225 | if (client->swapped) | |
226 | swapl(&providers[i]); | |
227 | prov_cap[i] = RR_Capability_SinkOffload; | |
228 | if (client->swapped) | |
229 | swapl(&prov_cap[i]); | |
230 | i++; | |
231 | } | |
232 | if (provider->output_source) { | |
233 | providers[i] = provider->output_source->id; | |
234 | if (client->swapped) | |
235 | swapl(&providers[i]); | |
236 | prov_cap[i] = RR_Capability_SourceOutput; | |
237 | swapl(&prov_cap[i]); | |
238 | i++; | |
239 | } | |
240 | xorg_list_for_each_entry(provscreen, &pScreen->output_slave_list, output_head) { | |
241 | pScrProvPriv = rrGetScrPriv(provscreen); | |
242 | providers[i] = pScrProvPriv->provider->id; | |
243 | if (client->swapped) | |
244 | swapl(&providers[i]); | |
245 | prov_cap[i] = RR_Capability_SinkOutput; | |
246 | if (client->swapped) | |
247 | swapl(&prov_cap[i]); | |
248 | i++; | |
249 | } | |
250 | xorg_list_for_each_entry(provscreen, &pScreen->offload_slave_list, offload_head) { | |
251 | pScrProvPriv = rrGetScrPriv(provscreen); | |
252 | providers[i] = pScrProvPriv->provider->id; | |
253 | if (client->swapped) | |
254 | swapl(&providers[i]); | |
255 | prov_cap[i] = RR_Capability_SourceOffload; | |
256 | if (client->swapped) | |
257 | swapl(&prov_cap[i]); | |
258 | i++; | |
259 | } | |
260 | ||
261 | ||
262 | memcpy(name, provider->name, rep.nameLength); | |
263 | if (client->swapped) { | |
264 | swaps(&rep.sequenceNumber); | |
265 | swapl(&rep.length); | |
266 | swapl(&rep.capabilities); | |
267 | swaps(&rep.nCrtcs); | |
268 | swaps(&rep.nOutputs); | |
269 | swaps(&rep.nameLength); | |
270 | } | |
271 | WriteToClient(client, sizeof(xRRGetProviderInfoReply), (char *)&rep); | |
272 | if (extraLen) | |
273 | { | |
274 | WriteToClient (client, extraLen, (char *) extra); | |
275 | free(extra); | |
276 | } | |
277 | return Success; | |
278 | } | |
279 | ||
280 | int | |
281 | ProcRRSetProviderOutputSource(ClientPtr client) | |
282 | { | |
283 | REQUEST(xRRSetProviderOutputSourceReq); | |
284 | rrScrPrivPtr pScrPriv; | |
285 | RRProviderPtr provider, source_provider = NULL; | |
286 | ScreenPtr pScreen; | |
287 | ||
288 | REQUEST_AT_LEAST_SIZE(xRRSetProviderOutputSourceReq); | |
289 | ||
290 | VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); | |
291 | ||
292 | if (!(provider->capabilities & RR_Capability_SinkOutput)) | |
293 | return BadValue; | |
294 | ||
295 | if (stuff->source_provider) { | |
296 | VERIFY_RR_PROVIDER(stuff->source_provider, source_provider, DixReadAccess); | |
297 | ||
298 | if (!(source_provider->capabilities & RR_Capability_SourceOutput)) | |
299 | return BadValue; | |
300 | } | |
301 | ||
302 | pScreen = provider->pScreen; | |
303 | pScrPriv = rrGetScrPriv(pScreen); | |
304 | ||
305 | pScrPriv->rrProviderSetOutputSource(pScreen, provider, source_provider); | |
306 | ||
307 | provider->changed = TRUE; | |
308 | RRSetChanged(pScreen); | |
309 | ||
310 | RRTellChanged (pScreen); | |
311 | ||
312 | return Success; | |
313 | } | |
314 | ||
315 | int | |
316 | ProcRRSetProviderOffloadSink(ClientPtr client) | |
317 | { | |
318 | REQUEST(xRRSetProviderOffloadSinkReq); | |
319 | rrScrPrivPtr pScrPriv; | |
320 | RRProviderPtr provider, sink_provider = NULL; | |
321 | ScreenPtr pScreen; | |
322 | ||
323 | REQUEST_AT_LEAST_SIZE(xRRSetProviderOffloadSinkReq); | |
324 | ||
325 | VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); | |
326 | if (!(provider->capabilities & RR_Capability_SourceOffload)) | |
327 | return BadValue; | |
328 | ||
329 | if (stuff->sink_provider) { | |
330 | VERIFY_RR_PROVIDER(stuff->sink_provider, sink_provider, DixReadAccess); | |
331 | if (!(sink_provider->capabilities & RR_Capability_SinkOffload)) | |
332 | return BadValue; | |
333 | } | |
334 | pScreen = provider->pScreen; | |
335 | pScrPriv = rrGetScrPriv(pScreen); | |
336 | ||
337 | pScrPriv->rrProviderSetOffloadSink(pScreen, provider, sink_provider); | |
338 | ||
339 | provider->changed = TRUE; | |
340 | RRSetChanged(pScreen); | |
341 | ||
342 | RRTellChanged (pScreen); | |
343 | ||
344 | return Success; | |
345 | } | |
346 | ||
347 | RRProviderPtr | |
348 | RRProviderCreate(ScreenPtr pScreen, const char *name, | |
349 | int nameLength) | |
350 | { | |
351 | RRProviderPtr provider; | |
352 | rrScrPrivPtr pScrPriv; | |
353 | ||
354 | pScrPriv = rrGetScrPriv(pScreen); | |
355 | ||
356 | provider = calloc(1, sizeof(RRProviderRec) + nameLength + 1); | |
357 | if (!provider) | |
358 | return NULL; | |
359 | ||
360 | provider->id = FakeClientID(0); | |
361 | provider->pScreen = pScreen; | |
362 | provider->name = (char *) (provider + 1); | |
363 | provider->nameLength = nameLength; | |
364 | memcpy(provider->name, name, nameLength); | |
365 | provider->name[nameLength] = '\0'; | |
366 | provider->changed = FALSE; | |
367 | ||
368 | if (!AddResource (provider->id, RRProviderType, (pointer) provider)) | |
369 | return NULL; | |
370 | pScrPriv->provider = provider; | |
371 | return provider; | |
372 | } | |
373 | ||
374 | /* | |
375 | * Destroy a provider at shutdown | |
376 | */ | |
377 | void | |
378 | RRProviderDestroy (RRProviderPtr provider) | |
379 | { | |
380 | FreeResource (provider->id, 0); | |
381 | } | |
382 | ||
383 | void | |
384 | RRProviderSetCapabilities(RRProviderPtr provider, uint32_t capabilities) | |
385 | { | |
386 | provider->capabilities = capabilities; | |
387 | } | |
388 | ||
389 | static int | |
390 | RRProviderDestroyResource (pointer value, XID pid) | |
391 | { | |
392 | RRProviderPtr provider = (RRProviderPtr)value; | |
393 | ScreenPtr pScreen = provider->pScreen; | |
394 | ||
395 | if (pScreen) | |
396 | { | |
397 | rrScrPriv(pScreen); | |
398 | ||
399 | if (pScrPriv->rrProviderDestroy) | |
400 | (*pScrPriv->rrProviderDestroy)(pScreen, provider); | |
401 | pScrPriv->provider = NULL; | |
402 | } | |
403 | free(provider); | |
404 | return 1; | |
405 | } | |
406 | ||
407 | Bool | |
408 | RRProviderInit(void) | |
409 | { | |
410 | RRProviderType = CreateNewResourceType(RRProviderDestroyResource, "Provider"); | |
411 | if (!RRProviderType) | |
412 | return FALSE; | |
413 | ||
414 | return TRUE; | |
415 | } | |
416 | ||
417 | extern _X_EXPORT Bool | |
418 | RRProviderLookup(XID id, RRProviderPtr *provider_p) | |
419 | { | |
420 | int rc = dixLookupResourceByType((void **)provider_p, id, | |
421 | RRProviderType, NullClient, DixReadAccess); | |
422 | if (rc == Success) | |
423 | return TRUE; | |
424 | return FALSE; | |
425 | } | |
426 | ||
427 | void | |
428 | RRDeliverProviderEvent(ClientPtr client, WindowPtr pWin, RRProviderPtr provider) | |
429 | { | |
430 | ScreenPtr pScreen = pWin->drawable.pScreen; | |
431 | ||
432 | rrScrPriv(pScreen); | |
433 | ||
434 | xRRProviderChangeNotifyEvent pe = { | |
435 | .type = RRNotify + RREventBase, | |
436 | .subCode = RRNotify_ProviderChange, | |
437 | .timestamp = pScrPriv->lastSetTime.milliseconds, | |
438 | .window = pWin->drawable.id, | |
439 | .provider = provider->id | |
440 | }; | |
441 | ||
442 | WriteEventsToClient(client, 1, (xEvent *) &pe); | |
443 | } |