1 /*
2  * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sub license, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial portions
14  * of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * Authors:
25  *    Jason Hu  <jason.hu@intel.com>
26  *    Zhaohan Ren  <zhaohan.ren@intel.com>
27  *
28  */
29 
30 #include <unistd.h>
31 #include "psb_xrandr.h"
32 #include "psb_x11.h"
33 #include "psb_drv_debug.h"
34 
35 /* Global variable for xrandr */
36 psb_xrandr_info_p psb_xrandr_info;
37 
38 #define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData
39 #define INIT_OUTPUT_PRIV    psb_x11_output_p output = (psb_x11_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
40 
41 #define MWM_HINTS_DECORATIONS (1L << 1)
42 typedef struct {
43     int flags;
44     int functions;
45     int decorations;
46     int input_mode;
47     int status;
48 } MWMHints;
49 
location2string(psb_xrandr_location location)50 char* location2string(psb_xrandr_location location)
51 {
52     switch (location) {
53     case ABOVE:
54         return "ABOVE";
55         break;
56     case BELOW:
57         return "BELOW";
58         break;
59     case LEFT_OF:
60         return "LEFT_OF";
61         break;
62     case RIGHT_OF:
63         return "RIGHT_OF";
64         break;
65     default:
66         return "NORMAL";
67         break;
68     }
69 }
70 
RRrotation2VArotation(Rotation rotation)71 static int RRrotation2VArotation(Rotation rotation)
72 {
73     switch (rotation) {
74     case RR_Rotate_0:
75         return VA_ROTATION_NONE;
76     case RR_Rotate_90:
77         return VA_ROTATION_270;
78     case RR_Rotate_180:
79         return VA_ROTATION_180;
80     case RR_Rotate_270:
81         return VA_ROTATION_90;
82     }
83 
84     return 0;
85 }
get_crtc_by_id(RRCrtc crtc_id)86 static psb_xrandr_crtc_p get_crtc_by_id(RRCrtc crtc_id)
87 {
88     psb_xrandr_crtc_p p_crtc;
89     for (p_crtc = psb_xrandr_info->crtc_head; p_crtc; p_crtc = p_crtc->next)
90         if (p_crtc->crtc_id == crtc_id)
91             return p_crtc;
92     return NULL;
93 }
94 
psb_xrandr_hdmi_property(VADriverContextP ctx)95 static void psb_xrandr_hdmi_property(VADriverContextP ctx)
96 {
97     INIT_DRIVER_DATA;
98     Atom *props;
99     Atom actual_type;
100     XRRPropertyInfo *propinfo;
101     int i, nprop, actual_format;
102     unsigned long nitems, bytes_after;
103     char* prop_name;
104     unsigned char* prop;
105 
106     /* Check HDMI properties */
107     props = XRRListOutputProperties(psb_xrandr_info->dpy, psb_xrandr_info->extend_output->output_id, &nprop);
108     if (!props) {
109         drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: XRRListOutputProperties failed\n", psb_xrandr_info->extend_output->output_id);
110         return;
111     }
112 
113     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: extend output %08x has %d properties\n", psb_xrandr_info->extend_output->output_id, nprop);
114 
115     for (i = 0; i < nprop; i++) {
116         XRRGetOutputProperty(psb_xrandr_info->dpy, psb_xrandr_info->extend_output->output_id, props[i],
117                              0, 100, False, False, AnyPropertyType, &actual_type, &actual_format,
118                              &nitems, &bytes_after, &prop);
119 
120         propinfo = XRRQueryOutputProperty(psb_xrandr_info->dpy, psb_xrandr_info->extend_output->output_id, props[i]);
121         if (!propinfo) {
122             drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: get output %08x prop %08x failed\n", psb_xrandr_info->extend_output->output_id, props[i]);
123             return;
124         }
125 
126         prop_name = XGetAtomName(psb_xrandr_info->dpy, props[i]);
127 
128         /* Currently all properties are XA_INTEGER, 32 */
129         if (!strcmp(prop_name, "ExtVideoMode")) {
130             psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode = (int)((INT32*)prop)[0];
131             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode);
132         } else if (!strcmp(prop_name, "ExtVideoMode_Xres")) {
133             psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_XRes = (int)((INT32*)prop)[0];
134             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_XRes (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_XRes);
135         } else if (!strcmp(prop_name, "ExtVideoMode_Yres")) {
136             psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_YRes = (int)((INT32*)prop)[0];
137             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_YRes (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_YRes);
138         } else if (!strcmp(prop_name, "ExtVideoMode_X_Offset")) {
139             psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_X_Offset = (int)((INT32*)prop)[0];
140             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_X_Offset (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_X_Offset);
141         } else if (!strcmp(prop_name, "ExtVideoMode_Y_Offset")) {
142             psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Y_Offset = (int)((INT32*)prop)[0];
143             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_Y_Offset (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Y_Offset);
144         } else if (!strcmp(prop_name, "ExtVideoMode_Center")) {
145             psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Center = (int)((INT32*)prop)[0];
146             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_Center (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Center);
147         } else if (!strcmp(prop_name, "ExtVideoMode_SubTitle")) {
148             psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_SubTitle = (int)((INT32*)prop)[0];
149             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_SubTitle (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_SubTitle);
150         } else if (!strcmp(prop_name, "ExtDesktopMode")) {
151             if ((psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode != EXTENDEDVIDEO) &&
152                 ((int)((INT32*)prop)[0] == EXTENDEDVIDEO)) {
153                 driver_data->xrandr_dirty |= PSB_NEW_EXTVIDEO;
154             }
155             psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = (int)((INT32*)prop)[0];
156             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtDesktopMode (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode);
157         } else if (!strcmp(prop_name, "OverscanMode")) {
158             psb_xrandr_info->hdmi_extvideo_prop->OverscanMode = (int)((INT32*)prop)[0];
159             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: OverscanMode (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->OverscanMode);
160         } else if (!strcmp(prop_name, "PANELFITTING")) {
161             psb_xrandr_info->hdmi_extvideo_prop->PANELFITTING = (int)((INT32*)prop)[0];
162             drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: PANELFITTING (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->PANELFITTING);
163         }
164     }
165 }
166 
psb_xrandr_mipi_location_init(psb_output_device_mode output_device_mode)167 static void psb_xrandr_mipi_location_init(psb_output_device_mode output_device_mode)
168 {
169     psb_xrandr_crtc_p local_crtc = NULL, extend_crtc = NULL;
170 
171     switch (output_device_mode) {
172     case SINGLE_MIPI0:
173         psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = SINGLE;
174         psb_xrandr_info->local_crtc[0]->location = NORMAL;
175         return;
176     case SINGLE_MIPI1:
177         psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = SINGLE;
178         psb_xrandr_info->local_crtc[1]->location = NORMAL;
179         return;
180     case MIPI0_MIPI1:
181         local_crtc = psb_xrandr_info->local_crtc[0];
182         extend_crtc = psb_xrandr_info->local_crtc[1];
183         break;
184     default:
185         break;
186     }
187 
188     if (!local_crtc || !extend_crtc) {
189         drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to get crtc info\n");
190         return;
191     }
192 
193     /* MIPI1 clone MIPI0 */
194     if (local_crtc->x == 0 && local_crtc->y == 0 &&
195         extend_crtc->x == 0 && extend_crtc->y == 0) {
196         psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = CLONE;
197         extend_crtc->location = NORMAL;
198     } else {
199         /* MIPI1 entend MIPI0 */
200         psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = EXTENDED;
201         if (local_crtc->y == extend_crtc->height)
202             extend_crtc->location = ABOVE;
203         else if (extend_crtc->y == local_crtc->height)
204             extend_crtc->location = BELOW;
205         else if (local_crtc->x == extend_crtc->width)
206             extend_crtc->location = LEFT_OF;
207         else if (extend_crtc->x == local_crtc->width)
208             extend_crtc->location = RIGHT_OF;
209     }
210 }
211 
psb_xrandr_hdmi_location_init(psb_output_device_mode output_device_mode)212 static void psb_xrandr_hdmi_location_init(psb_output_device_mode output_device_mode)
213 {
214     psb_xrandr_crtc_p local_crtc = NULL, extend_crtc = NULL;
215 
216     switch (output_device_mode) {
217     case SINGLE_HDMI:
218         psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = SINGLE;
219         psb_xrandr_info->extend_crtc->location = NORMAL;
220         return;
221     case MIPI0_HDMI:
222     case MIPI0_MIPI1_HDMI:
223         local_crtc = psb_xrandr_info->local_crtc[0];
224         extend_crtc = psb_xrandr_info->extend_crtc;
225         break;
226     case MIPI1_HDMI:
227         local_crtc = psb_xrandr_info->local_crtc[1];
228         extend_crtc = psb_xrandr_info->extend_crtc;
229         break;
230     default:
231         break;
232     }
233 
234     if (!local_crtc || !extend_crtc) {
235         drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to get crtc info\n");
236         return;
237     }
238 
239     if (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == CLONE)
240         psb_xrandr_info->extend_crtc->location = NORMAL;
241 
242     if (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == EXTENDED
243         || psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == EXTENDEDVIDEO) {
244         if (local_crtc->y == extend_crtc->height)
245             psb_xrandr_info->extend_crtc->location = ABOVE;
246         else if (extend_crtc->y == local_crtc->height)
247             psb_xrandr_info->extend_crtc->location = BELOW;
248         else if (local_crtc->x == extend_crtc->width)
249             psb_xrandr_info->extend_crtc->location = LEFT_OF;
250         else if (extend_crtc->x == local_crtc->width)
251             psb_xrandr_info->extend_crtc->location = RIGHT_OF;
252     }
253 }
254 
psb_xrandr_coordinate_init(VADriverContextP ctx)255 static void psb_xrandr_coordinate_init(VADriverContextP ctx)
256 {
257     INIT_DRIVER_DATA;
258     psb_xrandr_output_p p_output;
259 
260     psb_xrandr_info->output_changed = 1;
261 
262     for (p_output = psb_xrandr_info->output_head; p_output; p_output = p_output->next) {
263         if (p_output->connection == RR_Connected) {
264             if (!strcmp(p_output->name, "MIPI0")) {
265                 if (p_output->crtc) {
266                     psb_xrandr_info->mipi0_enabled = 1;
267                     psb_xrandr_info->local_output[0] = p_output;
268                     psb_xrandr_info->local_crtc[0] = p_output->crtc;
269                     if (psb_xrandr_info->mipi0_rotation != p_output->crtc->rotation) {
270                         psb_xrandr_info->mipi0_rotation = p_output->crtc->rotation;
271                         driver_data->mipi0_rotation = RRrotation2VArotation(psb_xrandr_info->mipi0_rotation);
272                         driver_data->xrandr_dirty |= PSB_NEW_ROTATION;
273                     }
274                 } else {
275                     psb_xrandr_info->mipi0_enabled = 0;
276                     psb_xrandr_info->local_output[0] = NULL;
277                     psb_xrandr_info->local_crtc[0] = NULL;
278                 }
279             } else if (!strcmp(p_output->name, "MIPI1")) {
280                 if (p_output->crtc) {
281                     psb_xrandr_info->mipi1_enabled = 1;
282                     psb_xrandr_info->local_output[1] = p_output;
283                     psb_xrandr_info->local_crtc[1] = p_output->crtc;
284                     if (psb_xrandr_info->mipi1_rotation != p_output->crtc->rotation) {
285                         psb_xrandr_info->mipi1_rotation = p_output->crtc->rotation;
286                         driver_data->mipi1_rotation = RRrotation2VArotation(psb_xrandr_info->mipi1_rotation);
287                         driver_data->xrandr_dirty |= PSB_NEW_ROTATION;
288                     }
289                 } else {
290                     psb_xrandr_info->mipi1_enabled = 0;
291                     psb_xrandr_info->local_output[1] = NULL;
292                     psb_xrandr_info->local_crtc[1] = NULL;
293                 }
294             } else if (!strcmp(p_output->name, "TMDS0-1")) {
295                 if (p_output->crtc) {
296                     psb_xrandr_info->hdmi_enabled = 1;
297                     psb_xrandr_info->extend_output = p_output;
298                     psb_xrandr_info->extend_crtc = p_output->crtc;
299                     if (psb_xrandr_info->hdmi_rotation != p_output->crtc->rotation) {
300                         psb_xrandr_info->hdmi_rotation = p_output->crtc->rotation;
301                         driver_data->hdmi_rotation = RRrotation2VArotation(psb_xrandr_info->hdmi_rotation);
302                         driver_data->xrandr_dirty |= PSB_NEW_ROTATION;
303                     }
304                 } else {
305                     psb_xrandr_info->hdmi_enabled = 0;
306                     psb_xrandr_info->extend_output = NULL;
307                     psb_xrandr_info->extend_crtc = NULL;
308                 }
309             } else if (!strcmp(p_output->name, "LVDS0") && IS_MRST(driver_data)) {
310                 if (p_output->crtc) {
311                     psb_xrandr_info->lvds0_enabled = 1;
312                     psb_xrandr_info->local_output[0] = p_output;
313                     psb_xrandr_info->local_crtc[0] = p_output->crtc;
314                 } else {
315                     psb_xrandr_info->lvds0_enabled = 0;
316                     psb_xrandr_info->local_output[0] = NULL;
317                     psb_xrandr_info->local_crtc[0] = NULL;
318                 }
319             }
320         }
321     }
322 
323     /* for MRST */
324     if (IS_MRST(driver_data) && psb_xrandr_info->lvds0_enabled) {
325         psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = SINGLE;
326         psb_xrandr_info->output_device_mode = SINGLE_LVDS0;
327         psb_xrandr_info->local_crtc[0]->location = NORMAL;
328         return;
329     }
330 
331     /* HDMI + either MIPI0 or MIPI1 */
332     if (psb_xrandr_info->hdmi_enabled) {
333 
334         /* Get HDMI properties if it is enabled*/
335         psb_xrandr_hdmi_property(ctx);
336 
337         /* Only HDMI */
338         if (!psb_xrandr_info->mipi0_enabled && !psb_xrandr_info->mipi1_enabled)
339             psb_xrandr_info->output_device_mode = SINGLE_HDMI;
340 
341         /* HDMI + MIPI0 */
342         if (psb_xrandr_info->mipi0_enabled && !psb_xrandr_info->mipi1_enabled)
343             psb_xrandr_info->output_device_mode = MIPI0_HDMI;
344 
345         /* HDMI + MIPI1 */
346         if (!psb_xrandr_info->mipi0_enabled && psb_xrandr_info->mipi1_enabled)
347             psb_xrandr_info->output_device_mode = MIPI1_HDMI;
348 
349         /* HDMI + MIPI0 + MIPI1 */
350         if (psb_xrandr_info->mipi0_enabled && psb_xrandr_info->mipi1_enabled)
351             psb_xrandr_info->output_device_mode = MIPI0_MIPI1_HDMI;
352 
353         psb_xrandr_hdmi_location_init(psb_xrandr_info->output_device_mode);
354     } else {
355         /* MIPI0 + MIPI1 */
356         if (psb_xrandr_info->mipi0_enabled && psb_xrandr_info->mipi1_enabled) {
357             psb_xrandr_info->output_device_mode = MIPI0_MIPI1;
358         } else {
359             /* MIPI0/MIPI1 */
360             if (psb_xrandr_info->mipi0_enabled)
361                 psb_xrandr_info->output_device_mode = SINGLE_MIPI0;
362             else if (psb_xrandr_info->mipi1_enabled)
363                 psb_xrandr_info->output_device_mode = SINGLE_MIPI1;
364         }
365 
366         psb_xrandr_mipi_location_init(psb_xrandr_info->output_device_mode);
367     }
368 }
369 
psb_xrandr_refresh(VADriverContextP ctx)370 void psb_xrandr_refresh(VADriverContextP ctx)
371 {
372     int i;
373 
374     XRROutputInfo *output_info;
375     XRRCrtcInfo *crtc_info;
376 
377     psb_xrandr_crtc_p p_crtc;
378     psb_xrandr_output_p p_output;
379 
380     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
381 
382     //deinit crtc
383     if (psb_xrandr_info->crtc_head) {
384         while (psb_xrandr_info->crtc_head) {
385             psb_xrandr_info->crtc_tail = psb_xrandr_info->crtc_head->next;
386 
387             free(psb_xrandr_info->crtc_head);
388 
389             psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail;
390         }
391         psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail = NULL;
392     }
393 
394     for (i = 0; i < psb_xrandr_info->res->ncrtc; i++) {
395         crtc_info = XRRGetCrtcInfo(psb_xrandr_info->dpy, psb_xrandr_info->res, psb_xrandr_info->res->crtcs[i]);
396         if (crtc_info) {
397             p_crtc = (psb_xrandr_crtc_p)calloc(1, sizeof(psb_xrandr_crtc_s));
398             if (!p_crtc) {
399                 drv_debug_msg(VIDEO_DEBUG_ERROR, "output of memory\n");
400                 return;
401             }
402 
403             if (i == 0)
404                 psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail = p_crtc;
405 
406             p_crtc->crtc_id = psb_xrandr_info->res->crtcs[i];
407             p_crtc->x = crtc_info->x;
408             p_crtc->y = crtc_info->y;
409             p_crtc->width = crtc_info->width;
410             p_crtc->height = crtc_info->height;
411             p_crtc->crtc_mode = crtc_info->mode;
412             p_crtc->noutput = crtc_info->noutput;
413             p_crtc->rotation = crtc_info->rotation;
414 
415             psb_xrandr_info->crtc_tail->next = p_crtc;
416             p_crtc->next = NULL;
417             psb_xrandr_info->crtc_tail = p_crtc;
418         } else {
419             drv_debug_msg(VIDEO_DEBUG_ERROR, "failed to get crtc_info\n");
420             pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
421             return;
422         }
423     }
424 
425     //deinit output
426     if (psb_xrandr_info->output_head) {
427         while (psb_xrandr_info->output_head) {
428             psb_xrandr_info->output_tail = psb_xrandr_info->output_head->next;
429 
430             free(psb_xrandr_info->output_head);
431 
432             psb_xrandr_info->output_head = psb_xrandr_info->output_tail;
433         }
434         psb_xrandr_info->output_head = psb_xrandr_info->output_tail = NULL;
435     }
436 #if 0
437     //destroy the full-screen window
438     //FIXME: commited out for X Error message: BadDrawable, need more investigation
439     if (va_output) {
440         if (va_output->extend_drawable) {
441             XDestroyWindow(ctx->native_dpy, va_output->extend_drawable);
442             va_output->extend_drawable = 0;
443             texture_priv->extend_dri_init_flag = 0;
444         }
445     }
446 #endif
447     for (i = 0; i < psb_xrandr_info->res->noutput; i++) {
448         output_info = XRRGetOutputInfo(psb_xrandr_info->dpy, psb_xrandr_info->res, psb_xrandr_info->res->outputs[i]);
449         if (output_info) {
450             p_output = (psb_xrandr_output_p)calloc(1, sizeof(psb_xrandr_output_s));
451             if (!p_output) {
452                 drv_debug_msg(VIDEO_DEBUG_ERROR, "output of memory\n");
453                 return;
454             }
455 
456             if (i == 0)
457                 psb_xrandr_info->output_head = psb_xrandr_info->output_tail = p_output;
458 
459             p_output->output_id = psb_xrandr_info->res->outputs[i];
460 
461             p_output->connection = output_info->connection;
462             if (p_output->connection == RR_Connected)
463                 psb_xrandr_info->nconnected_output++;
464 
465             strcpy(p_output->name, output_info->name);
466 
467             if (output_info->crtc)
468                 p_output->crtc = get_crtc_by_id(output_info->crtc);
469             else
470                 p_output->crtc = NULL;
471 
472             psb_xrandr_info->output_tail->next = p_output;
473             p_output->next = NULL;
474             psb_xrandr_info->output_tail = p_output;
475         } else {
476             drv_debug_msg(VIDEO_DEBUG_ERROR, "failed to get output_info\n");
477             pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
478             return;
479         }
480     }
481 
482     psb_xrandr_coordinate_init(ctx);
483 
484     psb_RecalcRotate(ctx);
485     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
486 }
487 
488 static Bool
outputChangePredicate(Display * display,XEvent * event,char * args)489 outputChangePredicate(Display *display, XEvent *event, char *args)
490 {
491     int event_base, error_base;
492 
493     XRRQueryExtension(psb_xrandr_info->dpy, &event_base, &error_base);
494     return ((event->type == event_base + RRNotify_OutputChange) ||
495             ((event->type == ClientMessage) &&
496              (((XClientMessageEvent*)event)->message_type == psb_xrandr_info->psb_exit_atom)));
497 }
498 
psb_xrandr_thread(void * arg)499 void psb_xrandr_thread(void* arg)
500 {
501     VADriverContextP ctx = (VADriverContextP)arg;
502     INIT_DRIVER_DATA;
503     int event_base, error_base;
504     XEvent event;
505     XRRQueryExtension(psb_xrandr_info->dpy, &event_base, &error_base);
506     XRRSelectInput(psb_xrandr_info->dpy, psb_xrandr_info->root, RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RROutputPropertyNotifyMask);
507     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: psb xrandr thread start\n");
508 
509     while (1) {
510         if (XCheckIfEvent(psb_xrandr_info->dpy, (XEvent *)&event, outputChangePredicate, NULL)) {
511             if (event.type == ClientMessage) {
512                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: receive ClientMessage event, thread should exit\n");
513                 XClientMessageEvent *evt;
514                 evt = (XClientMessageEvent*) & event;
515                 if (evt->message_type == psb_xrandr_info->psb_exit_atom) {
516                     drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: xrandr thread exit safely\n");
517                     pthread_exit(NULL);
518                 }
519             }
520             switch (event.type - event_base) {
521             case RRNotify_OutputChange:
522                 XRRUpdateConfiguration(&event);
523                 drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: receive RRNotify_OutputChange event, refresh output/crtc info\n");
524                 driver_data->xrandr_update = 1;
525                 psb_xrandr_refresh(ctx);
526                 break;
527             default:
528                 break;
529             }
530         }
531         usleep(200000);
532     }
533 }
534 
psb_xrandr_create_full_screen_window(unsigned int destx,unsigned int desty,unsigned int destw,unsigned int desth)535 Window psb_xrandr_create_full_screen_window(unsigned int destx, unsigned int desty, unsigned int destw, unsigned int desth)
536 {
537     int x, y, width, height;
538     Window win;
539 
540     x = psb_xrandr_info->extend_crtc->x;
541     y = psb_xrandr_info->extend_crtc->y;
542     width = psb_xrandr_info->extend_crtc->width;
543     height = psb_xrandr_info->extend_crtc->height;
544 
545     if (destw == 0 || desth == 0) {
546         destw = width;
547         desth = height;
548     }
549     win = XCreateSimpleWindow(psb_xrandr_info->dpy, DefaultRootWindow(psb_xrandr_info->dpy), destx, desty, destw, desth, 0, 0, 0);
550 
551     MWMHints mwmhints;
552     Atom MOTIF_WM_HINTS;
553 
554     mwmhints.flags = MWM_HINTS_DECORATIONS;
555     mwmhints.decorations = 0; /* MWM_DECOR_BORDER */
556     MOTIF_WM_HINTS = XInternAtom(psb_xrandr_info->dpy, "_MOTIF_WM_HINTS", False);
557     XChangeProperty(psb_xrandr_info->dpy, win, MOTIF_WM_HINTS, MOTIF_WM_HINTS, sizeof(long) * 8,
558                     PropModeReplace, (unsigned char*) &mwmhints, sizeof(mwmhints) / sizeof(long));
559 
560     XSetWindowAttributes attributes;
561     attributes.override_redirect = 1;
562     unsigned long valuemask;
563     valuemask = CWOverrideRedirect ;
564     XChangeWindowAttributes(psb_xrandr_info->dpy, win, valuemask, &attributes);
565 
566     XMapWindow(psb_xrandr_info->dpy, win);
567     XFlush(psb_xrandr_info->dpy);
568     return win;
569 }
570 
psb_xrandr_hdmi_enabled()571 int psb_xrandr_hdmi_enabled()
572 {
573     int ret;
574     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
575     ret = psb_xrandr_info->hdmi_enabled;
576     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
577     return ret;
578 }
579 
psb_xrandr_mipi0_enabled()580 int psb_xrandr_mipi0_enabled()
581 {
582     int ret;
583     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
584     ret = psb_xrandr_info->mipi0_enabled;
585     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
586     return ret;
587 }
588 
psb_xrandr_mipi1_enabled()589 int psb_xrandr_mipi1_enabled()
590 {
591     int ret;
592     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
593     ret = psb_xrandr_info->mipi1_enabled;
594     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
595     return ret;
596 }
597 
psb_xrandr_single_mode()598 int psb_xrandr_single_mode()
599 {
600     int ret;
601     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
602     ret = (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == SINGLE) ? 1 : 0;
603     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
604     return ret;
605 }
606 
psb_xrandr_clone_mode()607 int psb_xrandr_clone_mode()
608 {
609     int ret;
610     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
611     ret = (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == CLONE) ? 1 : 0;
612     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
613     return ret;
614 }
615 
psb_xrandr_extend_mode()616 int psb_xrandr_extend_mode()
617 {
618     int ret;
619     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
620     ret = (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == EXTENDED) ? 1 : 0;
621     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
622     return ret;
623 }
624 
psb_xrandr_extvideo_mode()625 int psb_xrandr_extvideo_mode()
626 {
627     int ret;
628     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
629     ret = (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == EXTENDEDVIDEO) ? 1 : 0;
630     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
631     return ret;
632 }
633 
psb_xrandr_outputchanged()634 int psb_xrandr_outputchanged()
635 {
636     int ret;
637     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
638     if (psb_xrandr_info->output_changed) {
639         psb_xrandr_info->output_changed = 0;
640         ret = 1;
641     } else
642         ret = 0;
643     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
644     return ret;
645 }
646 
psb_xrandr_extvideo_prop(unsigned int * xres,unsigned int * yres,unsigned int * xoffset,unsigned int * yoffset,psb_extvideo_center * center,psb_extvideo_subtitle * subtitle,unsigned int * overscanmode,unsigned int * pannelfitting)647 VAStatus psb_xrandr_extvideo_prop(unsigned int *xres, unsigned int *yres, unsigned int *xoffset,
648                                   unsigned int *yoffset, psb_extvideo_center *center, psb_extvideo_subtitle *subtitle,
649                                   unsigned int *overscanmode, unsigned int *pannelfitting)
650 {
651     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
652 
653     if (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode != EXTENDEDVIDEO) {
654         pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
655         return VA_STATUS_ERROR_UNKNOWN;
656     }
657 
658     *xres = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_XRes;
659     *yres = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_YRes;
660     *xoffset = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_X_Offset;
661     *yoffset = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Y_Offset;
662     *center = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Center;
663     *subtitle = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_SubTitle;
664     *pannelfitting = psb_xrandr_info->hdmi_extvideo_prop->PANELFITTING;
665     *overscanmode = psb_xrandr_info->hdmi_extvideo_prop->OverscanMode;
666 
667     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
668     return VA_STATUS_SUCCESS;
669 }
670 
psb_xrandr_local_crtc_coordinate(psb_output_device * local_device_enabled,int * x,int * y,int * width,int * height,Rotation * rotation)671 VAStatus psb_xrandr_local_crtc_coordinate(psb_output_device *local_device_enabled, int *x, int *y, int *width, int *height, Rotation *rotation)
672 {
673     psb_xrandr_crtc_p p_crtc;
674     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
675 
676     switch (psb_xrandr_info->output_device_mode) {
677     case SINGLE_LVDS0:
678         *local_device_enabled = LVDS0;
679         p_crtc = psb_xrandr_info->local_crtc[0];
680         break;
681     case SINGLE_MIPI0:
682     case MIPI0_MIPI1:
683     case MIPI0_HDMI:
684     case MIPI0_MIPI1_HDMI:
685         *local_device_enabled = MIPI0;
686         p_crtc = psb_xrandr_info->local_crtc[0];
687         break;
688     case SINGLE_MIPI1:
689     case MIPI1_HDMI:
690         *local_device_enabled = MIPI1;
691         p_crtc = psb_xrandr_info->local_crtc[1];
692         break;
693     case SINGLE_HDMI:
694         *local_device_enabled = HDMI;
695         p_crtc = psb_xrandr_info->extend_crtc;
696         break;
697     default:
698         drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: Unknown statue\n");
699         pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
700         return VA_STATUS_ERROR_UNKNOWN;
701         break;
702     }
703 
704     if (p_crtc) {
705         *x = p_crtc->x;
706         *y = p_crtc->y;
707         *width = p_crtc->width;
708         *height = p_crtc->height;
709         *rotation = p_crtc->rotation;
710         pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
711         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: device %08x enabled, crtc %08x coordinate: x = %d, y = %d, widht = %d, height = %d, rotate = %08x\n",
712                                  *local_device_enabled, p_crtc->crtc_id, *x, *y, *width + 1, *height + 1, *rotation);
713         return VA_STATUS_SUCCESS;
714     } else {
715         drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: local device is not available\n");
716         pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
717         return VA_STATUS_ERROR_UNKNOWN;
718     }
719 }
720 
psb_xrandr_extend_crtc_coordinate(psb_output_device * extend_device_enabled,int * x,int * y,int * width,int * height,psb_xrandr_location * location,Rotation * rotation)721 VAStatus psb_xrandr_extend_crtc_coordinate(psb_output_device *extend_device_enabled, int *x, int *y, int *width, int *height, psb_xrandr_location *location, Rotation *rotation)
722 {
723     psb_xrandr_crtc_p p_crtc;
724 
725     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
726 
727     switch (psb_xrandr_info->output_device_mode) {
728     case MIPI0_MIPI1:
729         *extend_device_enabled = MIPI1;
730         p_crtc = psb_xrandr_info->local_crtc[1];
731         break;
732     case MIPI0_HDMI:
733     case MIPI0_MIPI1_HDMI:
734     case MIPI1_HDMI:
735         *extend_device_enabled = HDMI;
736         p_crtc = psb_xrandr_info->extend_crtc;
737         break;
738     default:
739         drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: Unknown status, may be extend device is not available\n");
740         pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
741         return VA_STATUS_ERROR_UNKNOWN;
742         break;
743     }
744 
745     if (p_crtc) {
746         *x = p_crtc->x;
747         *y = p_crtc->y;
748         *width = p_crtc->width;
749         *height = p_crtc->height;
750         *location = p_crtc->location;
751         *rotation = p_crtc->rotation;
752         pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
753         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: extend device %08x enabled, crtc %08x coordinate: x = %d, y = %d, widht = %d, height = %d, location = %s, rotation = %08x\n",
754                                  *extend_device_enabled, p_crtc->crtc_id, *x, *y, *width + 1, *height + 1, location2string(p_crtc->location), *rotation);
755     } else {
756         drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: extend device is not available\n");
757         pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
758         return VA_STATUS_ERROR_UNKNOWN;
759     }
760 
761     return VA_STATUS_SUCCESS;
762 }
763 
psb_xrandr_thread_exit()764 VAStatus psb_xrandr_thread_exit()
765 {
766     int ret;
767 
768     XSelectInput(psb_xrandr_info->dpy, psb_xrandr_info->root, StructureNotifyMask);
769     XClientMessageEvent xevent;
770     xevent.type = ClientMessage;
771     xevent.message_type = psb_xrandr_info->psb_exit_atom;
772     xevent.window = psb_xrandr_info->root;
773     xevent.format = 32;
774     ret = XSendEvent(psb_xrandr_info->dpy, psb_xrandr_info->root, 0, StructureNotifyMask, (XEvent*) & xevent);
775     XFlush(psb_xrandr_info->dpy);
776     if (!ret) {
777         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: send thread exit event to drawable: failed\n");
778         return VA_STATUS_ERROR_UNKNOWN;
779     } else {
780         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: send thread exit event to drawable: success\n");
781         return VA_STATUS_SUCCESS;
782     }
783 }
784 
psb_xrandr_thread_create(VADriverContextP ctx)785 VAStatus psb_xrandr_thread_create(VADriverContextP ctx)
786 {
787     pthread_t id;
788     INIT_DRIVER_DATA;
789 
790     psb_xrandr_info->psb_exit_atom = XInternAtom(psb_xrandr_info->dpy, "psb_exit_atom", 0);
791     pthread_create(&id, NULL, (void*)psb_xrandr_thread, ctx);
792     driver_data->xrandr_thread_id = id;
793     return VA_STATUS_SUCCESS;
794 }
795 
psb_xrandr_deinit()796 VAStatus psb_xrandr_deinit()
797 {
798 #ifdef _FOR_FPGA_
799     return VA_STATUS_SUCCESS;
800 #endif
801     pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex);
802     //free crtc
803     if (psb_xrandr_info->crtc_head) {
804         while (psb_xrandr_info->crtc_head) {
805             psb_xrandr_info->crtc_tail = psb_xrandr_info->crtc_head->next;
806 
807             free(psb_xrandr_info->crtc_head);
808 
809             psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail;
810         }
811         psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail = NULL;
812     }
813 
814     //free output
815     if (psb_xrandr_info->output_head) {
816         while (psb_xrandr_info->output_head) {
817             psb_xrandr_info->output_tail = psb_xrandr_info->output_head->next;
818 
819             free(psb_xrandr_info->output_head);
820 
821             psb_xrandr_info->output_head = psb_xrandr_info->output_tail;
822         }
823         psb_xrandr_info->output_head = psb_xrandr_info->output_tail = NULL;
824     }
825 
826     if (psb_xrandr_info->hdmi_extvideo_prop) {
827         free(psb_xrandr_info->hdmi_extvideo_prop);
828     }
829 
830     pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex);
831     pthread_mutex_destroy(&psb_xrandr_info->psb_extvideo_mutex);
832 
833     free(psb_xrandr_info);
834     return VA_STATUS_SUCCESS;
835 }
836 
psb_xrandr_init(VADriverContextP ctx)837 VAStatus psb_xrandr_init(VADriverContextP ctx)
838 {
839     int major, minor;
840     int screen;
841 
842     psb_xrandr_info = (psb_xrandr_info_p)calloc(1, sizeof(psb_xrandr_info_s));
843 
844     if (!psb_xrandr_info) {
845         drv_debug_msg(VIDEO_DEBUG_ERROR, "output of memory\n");
846         return VA_STATUS_ERROR_UNKNOWN;
847     }
848     memset(psb_xrandr_info, 0, sizeof(psb_xrandr_info_s));
849     psb_xrandr_info->mipi0_rotation = RR_Rotate_0;
850     psb_xrandr_info->mipi1_rotation = RR_Rotate_0;
851     psb_xrandr_info->hdmi_rotation = RR_Rotate_0;
852 
853     psb_xrandr_info->hdmi_extvideo_prop = (psb_extvideo_prop_p)calloc(1, sizeof(psb_extvideo_prop_s));
854     if (!psb_xrandr_info->hdmi_extvideo_prop) {
855         drv_debug_msg(VIDEO_DEBUG_ERROR, "output of memory\n");
856         return VA_STATUS_ERROR_ALLOCATION_FAILED;
857     }
858     memset(psb_xrandr_info->hdmi_extvideo_prop, 0, sizeof(psb_extvideo_prop_s));
859 
860     psb_xrandr_info->dpy = (Display *)ctx->native_dpy;
861     screen = DefaultScreen(psb_xrandr_info->dpy);
862 
863     if (screen >= ScreenCount(psb_xrandr_info->dpy)) {
864         drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: Invalid screen number %d (display has %d)\n",
865                            screen, ScreenCount(psb_xrandr_info->dpy));
866         return VA_STATUS_ERROR_UNKNOWN;
867     }
868 
869     psb_xrandr_info->root = RootWindow(psb_xrandr_info->dpy, screen);
870 
871     if (!XRRQueryVersion(psb_xrandr_info->dpy, &major, &minor)) {
872         drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: RandR extension missing\n");
873         return VA_STATUS_ERROR_UNKNOWN;
874     }
875 
876     psb_xrandr_info->res = XRRGetScreenResources(psb_xrandr_info->dpy, psb_xrandr_info->root);
877     if (!psb_xrandr_info->res)
878         drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: failed to get screen resources\n");
879 
880     pthread_mutex_init(&psb_xrandr_info->psb_extvideo_mutex, NULL);
881 
882     psb_xrandr_refresh(ctx);
883 
884     return VA_STATUS_SUCCESS;
885 }
886