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