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 */
36psb_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)
42typedef struct {
43    int flags;
44    int functions;
45    int decorations;
46    int input_mode;
47    int status;
48} MWMHints;
49
50char* 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
71static 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}
86static 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
95static 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
167static 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
212static 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
255static 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
370void 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
488static Bool
489outputChangePredicate(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
499void 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
535Window 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
571int 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
580int 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
589int 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
598int 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
607int 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
616int 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
625int 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
634int 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
647VAStatus 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
671VAStatus 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
721VAStatus 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
764VAStatus 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
785VAStatus 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
796VAStatus 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
837VAStatus 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