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