/* * Copyright (c) 2011 Intel Corporation. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Authors: * Jason Hu <jason.hu@intel.com> * Zhaohan Ren <zhaohan.ren@intel.com> * */ #include <unistd.h> #include "psb_xrandr.h" #include "psb_x11.h" #include "psb_drv_debug.h" /* Global variable for xrandr */ psb_xrandr_info_p psb_xrandr_info; #define INIT_DRIVER_DATA psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData #define INIT_OUTPUT_PRIV psb_x11_output_p output = (psb_x11_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv) #define MWM_HINTS_DECORATIONS (1L << 1) typedef struct { int flags; int functions; int decorations; int input_mode; int status; } MWMHints; char* location2string(psb_xrandr_location location) { switch (location) { case ABOVE: return "ABOVE"; break; case BELOW: return "BELOW"; break; case LEFT_OF: return "LEFT_OF"; break; case RIGHT_OF: return "RIGHT_OF"; break; default: return "NORMAL"; break; } } static int RRrotation2VArotation(Rotation rotation) { switch (rotation) { case RR_Rotate_0: return VA_ROTATION_NONE; case RR_Rotate_90: return VA_ROTATION_270; case RR_Rotate_180: return VA_ROTATION_180; case RR_Rotate_270: return VA_ROTATION_90; } return 0; } static psb_xrandr_crtc_p get_crtc_by_id(RRCrtc crtc_id) { psb_xrandr_crtc_p p_crtc; for (p_crtc = psb_xrandr_info->crtc_head; p_crtc; p_crtc = p_crtc->next) if (p_crtc->crtc_id == crtc_id) return p_crtc; return NULL; } static void psb_xrandr_hdmi_property(VADriverContextP ctx) { INIT_DRIVER_DATA; Atom *props; Atom actual_type; XRRPropertyInfo *propinfo; int i, nprop, actual_format; unsigned long nitems, bytes_after; char* prop_name; unsigned char* prop; /* Check HDMI properties */ props = XRRListOutputProperties(psb_xrandr_info->dpy, psb_xrandr_info->extend_output->output_id, &nprop); if (!props) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: XRRListOutputProperties failed\n", psb_xrandr_info->extend_output->output_id); return; } drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: extend output %08x has %d properties\n", psb_xrandr_info->extend_output->output_id, nprop); for (i = 0; i < nprop; i++) { XRRGetOutputProperty(psb_xrandr_info->dpy, psb_xrandr_info->extend_output->output_id, props[i], 0, 100, False, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); propinfo = XRRQueryOutputProperty(psb_xrandr_info->dpy, psb_xrandr_info->extend_output->output_id, props[i]); if (!propinfo) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: get output %08x prop %08x failed\n", psb_xrandr_info->extend_output->output_id, props[i]); return; } prop_name = XGetAtomName(psb_xrandr_info->dpy, props[i]); /* Currently all properties are XA_INTEGER, 32 */ if (!strcmp(prop_name, "ExtVideoMode")) { psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode); } else if (!strcmp(prop_name, "ExtVideoMode_Xres")) { psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_XRes = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_XRes (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_XRes); } else if (!strcmp(prop_name, "ExtVideoMode_Yres")) { psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_YRes = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_YRes (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_YRes); } else if (!strcmp(prop_name, "ExtVideoMode_X_Offset")) { psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_X_Offset = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_X_Offset (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_X_Offset); } else if (!strcmp(prop_name, "ExtVideoMode_Y_Offset")) { psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Y_Offset = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_Y_Offset (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Y_Offset); } else if (!strcmp(prop_name, "ExtVideoMode_Center")) { psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Center = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_Center (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Center); } else if (!strcmp(prop_name, "ExtVideoMode_SubTitle")) { psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_SubTitle = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtVideoMode_SubTitle (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_SubTitle); } else if (!strcmp(prop_name, "ExtDesktopMode")) { if ((psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode != EXTENDEDVIDEO) && ((int)((INT32*)prop)[0] == EXTENDEDVIDEO)) { driver_data->xrandr_dirty |= PSB_NEW_EXTVIDEO; } psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: ExtDesktopMode (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode); } else if (!strcmp(prop_name, "OverscanMode")) { psb_xrandr_info->hdmi_extvideo_prop->OverscanMode = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: OverscanMode (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->OverscanMode); } else if (!strcmp(prop_name, "PANELFITTING")) { psb_xrandr_info->hdmi_extvideo_prop->PANELFITTING = (int)((INT32*)prop)[0]; drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: PANELFITTING (%08x)\n", psb_xrandr_info->hdmi_extvideo_prop->PANELFITTING); } } } static void psb_xrandr_mipi_location_init(psb_output_device_mode output_device_mode) { psb_xrandr_crtc_p local_crtc = NULL, extend_crtc = NULL; switch (output_device_mode) { case SINGLE_MIPI0: psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = SINGLE; psb_xrandr_info->local_crtc[0]->location = NORMAL; return; case SINGLE_MIPI1: psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = SINGLE; psb_xrandr_info->local_crtc[1]->location = NORMAL; return; case MIPI0_MIPI1: local_crtc = psb_xrandr_info->local_crtc[0]; extend_crtc = psb_xrandr_info->local_crtc[1]; break; default: break; } if (!local_crtc || !extend_crtc) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to get crtc info\n"); return; } /* MIPI1 clone MIPI0 */ if (local_crtc->x == 0 && local_crtc->y == 0 && extend_crtc->x == 0 && extend_crtc->y == 0) { psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = CLONE; extend_crtc->location = NORMAL; } else { /* MIPI1 entend MIPI0 */ psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = EXTENDED; if (local_crtc->y == extend_crtc->height) extend_crtc->location = ABOVE; else if (extend_crtc->y == local_crtc->height) extend_crtc->location = BELOW; else if (local_crtc->x == extend_crtc->width) extend_crtc->location = LEFT_OF; else if (extend_crtc->x == local_crtc->width) extend_crtc->location = RIGHT_OF; } } static void psb_xrandr_hdmi_location_init(psb_output_device_mode output_device_mode) { psb_xrandr_crtc_p local_crtc = NULL, extend_crtc = NULL; switch (output_device_mode) { case SINGLE_HDMI: psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = SINGLE; psb_xrandr_info->extend_crtc->location = NORMAL; return; case MIPI0_HDMI: case MIPI0_MIPI1_HDMI: local_crtc = psb_xrandr_info->local_crtc[0]; extend_crtc = psb_xrandr_info->extend_crtc; break; case MIPI1_HDMI: local_crtc = psb_xrandr_info->local_crtc[1]; extend_crtc = psb_xrandr_info->extend_crtc; break; default: break; } if (!local_crtc || !extend_crtc) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to get crtc info\n"); return; } if (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == CLONE) psb_xrandr_info->extend_crtc->location = NORMAL; if (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == EXTENDED || psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == EXTENDEDVIDEO) { if (local_crtc->y == extend_crtc->height) psb_xrandr_info->extend_crtc->location = ABOVE; else if (extend_crtc->y == local_crtc->height) psb_xrandr_info->extend_crtc->location = BELOW; else if (local_crtc->x == extend_crtc->width) psb_xrandr_info->extend_crtc->location = LEFT_OF; else if (extend_crtc->x == local_crtc->width) psb_xrandr_info->extend_crtc->location = RIGHT_OF; } } static void psb_xrandr_coordinate_init(VADriverContextP ctx) { INIT_DRIVER_DATA; psb_xrandr_output_p p_output; psb_xrandr_info->output_changed = 1; for (p_output = psb_xrandr_info->output_head; p_output; p_output = p_output->next) { if (p_output->connection == RR_Connected) { if (!strcmp(p_output->name, "MIPI0")) { if (p_output->crtc) { psb_xrandr_info->mipi0_enabled = 1; psb_xrandr_info->local_output[0] = p_output; psb_xrandr_info->local_crtc[0] = p_output->crtc; if (psb_xrandr_info->mipi0_rotation != p_output->crtc->rotation) { psb_xrandr_info->mipi0_rotation = p_output->crtc->rotation; driver_data->mipi0_rotation = RRrotation2VArotation(psb_xrandr_info->mipi0_rotation); driver_data->xrandr_dirty |= PSB_NEW_ROTATION; } } else { psb_xrandr_info->mipi0_enabled = 0; psb_xrandr_info->local_output[0] = NULL; psb_xrandr_info->local_crtc[0] = NULL; } } else if (!strcmp(p_output->name, "MIPI1")) { if (p_output->crtc) { psb_xrandr_info->mipi1_enabled = 1; psb_xrandr_info->local_output[1] = p_output; psb_xrandr_info->local_crtc[1] = p_output->crtc; if (psb_xrandr_info->mipi1_rotation != p_output->crtc->rotation) { psb_xrandr_info->mipi1_rotation = p_output->crtc->rotation; driver_data->mipi1_rotation = RRrotation2VArotation(psb_xrandr_info->mipi1_rotation); driver_data->xrandr_dirty |= PSB_NEW_ROTATION; } } else { psb_xrandr_info->mipi1_enabled = 0; psb_xrandr_info->local_output[1] = NULL; psb_xrandr_info->local_crtc[1] = NULL; } } else if (!strcmp(p_output->name, "TMDS0-1")) { if (p_output->crtc) { psb_xrandr_info->hdmi_enabled = 1; psb_xrandr_info->extend_output = p_output; psb_xrandr_info->extend_crtc = p_output->crtc; if (psb_xrandr_info->hdmi_rotation != p_output->crtc->rotation) { psb_xrandr_info->hdmi_rotation = p_output->crtc->rotation; driver_data->hdmi_rotation = RRrotation2VArotation(psb_xrandr_info->hdmi_rotation); driver_data->xrandr_dirty |= PSB_NEW_ROTATION; } } else { psb_xrandr_info->hdmi_enabled = 0; psb_xrandr_info->extend_output = NULL; psb_xrandr_info->extend_crtc = NULL; } } else if (!strcmp(p_output->name, "LVDS0") && IS_MRST(driver_data)) { if (p_output->crtc) { psb_xrandr_info->lvds0_enabled = 1; psb_xrandr_info->local_output[0] = p_output; psb_xrandr_info->local_crtc[0] = p_output->crtc; } else { psb_xrandr_info->lvds0_enabled = 0; psb_xrandr_info->local_output[0] = NULL; psb_xrandr_info->local_crtc[0] = NULL; } } } } /* for MRST */ if (IS_MRST(driver_data) && psb_xrandr_info->lvds0_enabled) { psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode = SINGLE; psb_xrandr_info->output_device_mode = SINGLE_LVDS0; psb_xrandr_info->local_crtc[0]->location = NORMAL; return; } /* HDMI + either MIPI0 or MIPI1 */ if (psb_xrandr_info->hdmi_enabled) { /* Get HDMI properties if it is enabled*/ psb_xrandr_hdmi_property(ctx); /* Only HDMI */ if (!psb_xrandr_info->mipi0_enabled && !psb_xrandr_info->mipi1_enabled) psb_xrandr_info->output_device_mode = SINGLE_HDMI; /* HDMI + MIPI0 */ if (psb_xrandr_info->mipi0_enabled && !psb_xrandr_info->mipi1_enabled) psb_xrandr_info->output_device_mode = MIPI0_HDMI; /* HDMI + MIPI1 */ if (!psb_xrandr_info->mipi0_enabled && psb_xrandr_info->mipi1_enabled) psb_xrandr_info->output_device_mode = MIPI1_HDMI; /* HDMI + MIPI0 + MIPI1 */ if (psb_xrandr_info->mipi0_enabled && psb_xrandr_info->mipi1_enabled) psb_xrandr_info->output_device_mode = MIPI0_MIPI1_HDMI; psb_xrandr_hdmi_location_init(psb_xrandr_info->output_device_mode); } else { /* MIPI0 + MIPI1 */ if (psb_xrandr_info->mipi0_enabled && psb_xrandr_info->mipi1_enabled) { psb_xrandr_info->output_device_mode = MIPI0_MIPI1; } else { /* MIPI0/MIPI1 */ if (psb_xrandr_info->mipi0_enabled) psb_xrandr_info->output_device_mode = SINGLE_MIPI0; else if (psb_xrandr_info->mipi1_enabled) psb_xrandr_info->output_device_mode = SINGLE_MIPI1; } psb_xrandr_mipi_location_init(psb_xrandr_info->output_device_mode); } } void psb_xrandr_refresh(VADriverContextP ctx) { int i; XRROutputInfo *output_info; XRRCrtcInfo *crtc_info; psb_xrandr_crtc_p p_crtc; psb_xrandr_output_p p_output; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); //deinit crtc if (psb_xrandr_info->crtc_head) { while (psb_xrandr_info->crtc_head) { psb_xrandr_info->crtc_tail = psb_xrandr_info->crtc_head->next; free(psb_xrandr_info->crtc_head); psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail; } psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail = NULL; } for (i = 0; i < psb_xrandr_info->res->ncrtc; i++) { crtc_info = XRRGetCrtcInfo(psb_xrandr_info->dpy, psb_xrandr_info->res, psb_xrandr_info->res->crtcs[i]); if (crtc_info) { p_crtc = (psb_xrandr_crtc_p)calloc(1, sizeof(psb_xrandr_crtc_s)); if (!p_crtc) { drv_debug_msg(VIDEO_DEBUG_ERROR, "output of memory\n"); return; } if (i == 0) psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail = p_crtc; p_crtc->crtc_id = psb_xrandr_info->res->crtcs[i]; p_crtc->x = crtc_info->x; p_crtc->y = crtc_info->y; p_crtc->width = crtc_info->width; p_crtc->height = crtc_info->height; p_crtc->crtc_mode = crtc_info->mode; p_crtc->noutput = crtc_info->noutput; p_crtc->rotation = crtc_info->rotation; psb_xrandr_info->crtc_tail->next = p_crtc; p_crtc->next = NULL; psb_xrandr_info->crtc_tail = p_crtc; } else { drv_debug_msg(VIDEO_DEBUG_ERROR, "failed to get crtc_info\n"); pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return; } } //deinit output if (psb_xrandr_info->output_head) { while (psb_xrandr_info->output_head) { psb_xrandr_info->output_tail = psb_xrandr_info->output_head->next; free(psb_xrandr_info->output_head); psb_xrandr_info->output_head = psb_xrandr_info->output_tail; } psb_xrandr_info->output_head = psb_xrandr_info->output_tail = NULL; } #if 0 //destroy the full-screen window //FIXME: commited out for X Error message: BadDrawable, need more investigation if (va_output) { if (va_output->extend_drawable) { XDestroyWindow(ctx->native_dpy, va_output->extend_drawable); va_output->extend_drawable = 0; texture_priv->extend_dri_init_flag = 0; } } #endif for (i = 0; i < psb_xrandr_info->res->noutput; i++) { output_info = XRRGetOutputInfo(psb_xrandr_info->dpy, psb_xrandr_info->res, psb_xrandr_info->res->outputs[i]); if (output_info) { p_output = (psb_xrandr_output_p)calloc(1, sizeof(psb_xrandr_output_s)); if (!p_output) { drv_debug_msg(VIDEO_DEBUG_ERROR, "output of memory\n"); return; } if (i == 0) psb_xrandr_info->output_head = psb_xrandr_info->output_tail = p_output; p_output->output_id = psb_xrandr_info->res->outputs[i]; p_output->connection = output_info->connection; if (p_output->connection == RR_Connected) psb_xrandr_info->nconnected_output++; strcpy(p_output->name, output_info->name); if (output_info->crtc) p_output->crtc = get_crtc_by_id(output_info->crtc); else p_output->crtc = NULL; psb_xrandr_info->output_tail->next = p_output; p_output->next = NULL; psb_xrandr_info->output_tail = p_output; } else { drv_debug_msg(VIDEO_DEBUG_ERROR, "failed to get output_info\n"); pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return; } } psb_xrandr_coordinate_init(ctx); psb_RecalcRotate(ctx); pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); } static Bool outputChangePredicate(Display *display, XEvent *event, char *args) { int event_base, error_base; XRRQueryExtension(psb_xrandr_info->dpy, &event_base, &error_base); return ((event->type == event_base + RRNotify_OutputChange) || ((event->type == ClientMessage) && (((XClientMessageEvent*)event)->message_type == psb_xrandr_info->psb_exit_atom))); } void psb_xrandr_thread(void* arg) { VADriverContextP ctx = (VADriverContextP)arg; INIT_DRIVER_DATA; int event_base, error_base; XEvent event; XRRQueryExtension(psb_xrandr_info->dpy, &event_base, &error_base); XRRSelectInput(psb_xrandr_info->dpy, psb_xrandr_info->root, RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask | RROutputChangeNotifyMask | RROutputPropertyNotifyMask); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: psb xrandr thread start\n"); while (1) { if (XCheckIfEvent(psb_xrandr_info->dpy, (XEvent *)&event, outputChangePredicate, NULL)) { if (event.type == ClientMessage) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: receive ClientMessage event, thread should exit\n"); XClientMessageEvent *evt; evt = (XClientMessageEvent*) & event; if (evt->message_type == psb_xrandr_info->psb_exit_atom) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: xrandr thread exit safely\n"); pthread_exit(NULL); } } switch (event.type - event_base) { case RRNotify_OutputChange: XRRUpdateConfiguration(&event); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: receive RRNotify_OutputChange event, refresh output/crtc info\n"); driver_data->xrandr_update = 1; psb_xrandr_refresh(ctx); break; default: break; } } usleep(200000); } } Window psb_xrandr_create_full_screen_window(unsigned int destx, unsigned int desty, unsigned int destw, unsigned int desth) { int x, y, width, height; Window win; x = psb_xrandr_info->extend_crtc->x; y = psb_xrandr_info->extend_crtc->y; width = psb_xrandr_info->extend_crtc->width; height = psb_xrandr_info->extend_crtc->height; if (destw == 0 || desth == 0) { destw = width; desth = height; } win = XCreateSimpleWindow(psb_xrandr_info->dpy, DefaultRootWindow(psb_xrandr_info->dpy), destx, desty, destw, desth, 0, 0, 0); MWMHints mwmhints; Atom MOTIF_WM_HINTS; mwmhints.flags = MWM_HINTS_DECORATIONS; mwmhints.decorations = 0; /* MWM_DECOR_BORDER */ MOTIF_WM_HINTS = XInternAtom(psb_xrandr_info->dpy, "_MOTIF_WM_HINTS", False); XChangeProperty(psb_xrandr_info->dpy, win, MOTIF_WM_HINTS, MOTIF_WM_HINTS, sizeof(long) * 8, PropModeReplace, (unsigned char*) &mwmhints, sizeof(mwmhints) / sizeof(long)); XSetWindowAttributes attributes; attributes.override_redirect = 1; unsigned long valuemask; valuemask = CWOverrideRedirect ; XChangeWindowAttributes(psb_xrandr_info->dpy, win, valuemask, &attributes); XMapWindow(psb_xrandr_info->dpy, win); XFlush(psb_xrandr_info->dpy); return win; } int psb_xrandr_hdmi_enabled() { int ret; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); ret = psb_xrandr_info->hdmi_enabled; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return ret; } int psb_xrandr_mipi0_enabled() { int ret; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); ret = psb_xrandr_info->mipi0_enabled; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return ret; } int psb_xrandr_mipi1_enabled() { int ret; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); ret = psb_xrandr_info->mipi1_enabled; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return ret; } int psb_xrandr_single_mode() { int ret; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); ret = (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == SINGLE) ? 1 : 0; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return ret; } int psb_xrandr_clone_mode() { int ret; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); ret = (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == CLONE) ? 1 : 0; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return ret; } int psb_xrandr_extend_mode() { int ret; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); ret = (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == EXTENDED) ? 1 : 0; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return ret; } int psb_xrandr_extvideo_mode() { int ret; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); ret = (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode == EXTENDEDVIDEO) ? 1 : 0; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return ret; } int psb_xrandr_outputchanged() { int ret; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); if (psb_xrandr_info->output_changed) { psb_xrandr_info->output_changed = 0; ret = 1; } else ret = 0; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return ret; } VAStatus psb_xrandr_extvideo_prop(unsigned int *xres, unsigned int *yres, unsigned int *xoffset, unsigned int *yoffset, psb_extvideo_center *center, psb_extvideo_subtitle *subtitle, unsigned int *overscanmode, unsigned int *pannelfitting) { pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); if (psb_xrandr_info->hdmi_extvideo_prop->ExtDesktopMode != EXTENDEDVIDEO) { pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return VA_STATUS_ERROR_UNKNOWN; } *xres = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_XRes; *yres = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_YRes; *xoffset = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_X_Offset; *yoffset = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Y_Offset; *center = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_Center; *subtitle = psb_xrandr_info->hdmi_extvideo_prop->ExtVideoMode_SubTitle; *pannelfitting = psb_xrandr_info->hdmi_extvideo_prop->PANELFITTING; *overscanmode = psb_xrandr_info->hdmi_extvideo_prop->OverscanMode; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return VA_STATUS_SUCCESS; } VAStatus psb_xrandr_local_crtc_coordinate(psb_output_device *local_device_enabled, int *x, int *y, int *width, int *height, Rotation *rotation) { psb_xrandr_crtc_p p_crtc; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); switch (psb_xrandr_info->output_device_mode) { case SINGLE_LVDS0: *local_device_enabled = LVDS0; p_crtc = psb_xrandr_info->local_crtc[0]; break; case SINGLE_MIPI0: case MIPI0_MIPI1: case MIPI0_HDMI: case MIPI0_MIPI1_HDMI: *local_device_enabled = MIPI0; p_crtc = psb_xrandr_info->local_crtc[0]; break; case SINGLE_MIPI1: case MIPI1_HDMI: *local_device_enabled = MIPI1; p_crtc = psb_xrandr_info->local_crtc[1]; break; case SINGLE_HDMI: *local_device_enabled = HDMI; p_crtc = psb_xrandr_info->extend_crtc; break; default: drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: Unknown statue\n"); pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return VA_STATUS_ERROR_UNKNOWN; break; } if (p_crtc) { *x = p_crtc->x; *y = p_crtc->y; *width = p_crtc->width; *height = p_crtc->height; *rotation = p_crtc->rotation; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: device %08x enabled, crtc %08x coordinate: x = %d, y = %d, widht = %d, height = %d, rotate = %08x\n", *local_device_enabled, p_crtc->crtc_id, *x, *y, *width + 1, *height + 1, *rotation); return VA_STATUS_SUCCESS; } else { drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: local device is not available\n"); pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return VA_STATUS_ERROR_UNKNOWN; } } VAStatus psb_xrandr_extend_crtc_coordinate(psb_output_device *extend_device_enabled, int *x, int *y, int *width, int *height, psb_xrandr_location *location, Rotation *rotation) { psb_xrandr_crtc_p p_crtc; pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); switch (psb_xrandr_info->output_device_mode) { case MIPI0_MIPI1: *extend_device_enabled = MIPI1; p_crtc = psb_xrandr_info->local_crtc[1]; break; case MIPI0_HDMI: case MIPI0_MIPI1_HDMI: case MIPI1_HDMI: *extend_device_enabled = HDMI; p_crtc = psb_xrandr_info->extend_crtc; break; default: drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: Unknown status, may be extend device is not available\n"); pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return VA_STATUS_ERROR_UNKNOWN; break; } if (p_crtc) { *x = p_crtc->x; *y = p_crtc->y; *width = p_crtc->width; *height = p_crtc->height; *location = p_crtc->location; *rotation = p_crtc->rotation; pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); 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", *extend_device_enabled, p_crtc->crtc_id, *x, *y, *width + 1, *height + 1, location2string(p_crtc->location), *rotation); } else { drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: extend device is not available\n"); pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); return VA_STATUS_ERROR_UNKNOWN; } return VA_STATUS_SUCCESS; } VAStatus psb_xrandr_thread_exit() { int ret; XSelectInput(psb_xrandr_info->dpy, psb_xrandr_info->root, StructureNotifyMask); XClientMessageEvent xevent; xevent.type = ClientMessage; xevent.message_type = psb_xrandr_info->psb_exit_atom; xevent.window = psb_xrandr_info->root; xevent.format = 32; ret = XSendEvent(psb_xrandr_info->dpy, psb_xrandr_info->root, 0, StructureNotifyMask, (XEvent*) & xevent); XFlush(psb_xrandr_info->dpy); if (!ret) { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: send thread exit event to drawable: failed\n"); return VA_STATUS_ERROR_UNKNOWN; } else { drv_debug_msg(VIDEO_DEBUG_GENERAL, "Xrandr: send thread exit event to drawable: success\n"); return VA_STATUS_SUCCESS; } } VAStatus psb_xrandr_thread_create(VADriverContextP ctx) { pthread_t id; INIT_DRIVER_DATA; psb_xrandr_info->psb_exit_atom = XInternAtom(psb_xrandr_info->dpy, "psb_exit_atom", 0); pthread_create(&id, NULL, (void*)psb_xrandr_thread, ctx); driver_data->xrandr_thread_id = id; return VA_STATUS_SUCCESS; } VAStatus psb_xrandr_deinit() { #ifdef _FOR_FPGA_ return VA_STATUS_SUCCESS; #endif pthread_mutex_lock(&psb_xrandr_info->psb_extvideo_mutex); //free crtc if (psb_xrandr_info->crtc_head) { while (psb_xrandr_info->crtc_head) { psb_xrandr_info->crtc_tail = psb_xrandr_info->crtc_head->next; free(psb_xrandr_info->crtc_head); psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail; } psb_xrandr_info->crtc_head = psb_xrandr_info->crtc_tail = NULL; } //free output if (psb_xrandr_info->output_head) { while (psb_xrandr_info->output_head) { psb_xrandr_info->output_tail = psb_xrandr_info->output_head->next; free(psb_xrandr_info->output_head); psb_xrandr_info->output_head = psb_xrandr_info->output_tail; } psb_xrandr_info->output_head = psb_xrandr_info->output_tail = NULL; } if (psb_xrandr_info->hdmi_extvideo_prop) { free(psb_xrandr_info->hdmi_extvideo_prop); } pthread_mutex_unlock(&psb_xrandr_info->psb_extvideo_mutex); pthread_mutex_destroy(&psb_xrandr_info->psb_extvideo_mutex); free(psb_xrandr_info); return VA_STATUS_SUCCESS; } VAStatus psb_xrandr_init(VADriverContextP ctx) { int major, minor; int screen; psb_xrandr_info = (psb_xrandr_info_p)calloc(1, sizeof(psb_xrandr_info_s)); if (!psb_xrandr_info) { drv_debug_msg(VIDEO_DEBUG_ERROR, "output of memory\n"); return VA_STATUS_ERROR_UNKNOWN; } memset(psb_xrandr_info, 0, sizeof(psb_xrandr_info_s)); psb_xrandr_info->mipi0_rotation = RR_Rotate_0; psb_xrandr_info->mipi1_rotation = RR_Rotate_0; psb_xrandr_info->hdmi_rotation = RR_Rotate_0; psb_xrandr_info->hdmi_extvideo_prop = (psb_extvideo_prop_p)calloc(1, sizeof(psb_extvideo_prop_s)); if (!psb_xrandr_info->hdmi_extvideo_prop) { drv_debug_msg(VIDEO_DEBUG_ERROR, "output of memory\n"); return VA_STATUS_ERROR_ALLOCATION_FAILED; } memset(psb_xrandr_info->hdmi_extvideo_prop, 0, sizeof(psb_extvideo_prop_s)); psb_xrandr_info->dpy = (Display *)ctx->native_dpy; screen = DefaultScreen(psb_xrandr_info->dpy); if (screen >= ScreenCount(psb_xrandr_info->dpy)) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: Invalid screen number %d (display has %d)\n", screen, ScreenCount(psb_xrandr_info->dpy)); return VA_STATUS_ERROR_UNKNOWN; } psb_xrandr_info->root = RootWindow(psb_xrandr_info->dpy, screen); if (!XRRQueryVersion(psb_xrandr_info->dpy, &major, &minor)) { drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: RandR extension missing\n"); return VA_STATUS_ERROR_UNKNOWN; } psb_xrandr_info->res = XRRGetScreenResources(psb_xrandr_info->dpy, psb_xrandr_info->root); if (!psb_xrandr_info->res) drv_debug_msg(VIDEO_DEBUG_ERROR, "Xrandr: failed to get screen resources\n"); pthread_mutex_init(&psb_xrandr_info->psb_extvideo_mutex, NULL); psb_xrandr_refresh(ctx); return VA_STATUS_SUCCESS; }