2017-03-06 82 views
0

我試圖用Xlib,XF86VidMode和OpenGL編寫一些簡單的圖形。我有兩個問題:使用xcb和randr獲取屏幕信息

  1. 的Xlib似乎並不具有WM_TIMER相當於,所以我寫了發送郵件到解鎖消息循環的SIGALRM的處理程序,但由於這種用法是完全線程安全的,程序稍後會掛起。因此我嘗試在xcb中重新編碼。
  2. XF86VidMode很難使用,我不喜歡結果,所以我切換到RandR。

完成上述事情後,事實證明xcb具有相同的掛起,所以我無法編碼阻止消息循環。相反,我每隔一段時間就會進行一次輪詢,程序沒有掛起,但是有些跳幀令人討厭。

雖然我可以使用RandR切換視頻模式,但我想使用xcb版本,但這種模式無效。我剽竊了xcb的一個@datenwolf的例子,但不知何故xcb_randr_get_screen_info_reply不起作用。它應該返回一個指向結構的指針,後面跟着一組屏幕尺寸(mm中的尺寸錯誤),然後是刷新率數據。刷新率數據是垃圾並且大部分爲零。我究竟做錯了什麼?

/* 
gcc rrxcb.c -lxcb-randr -lxcb -lX11 -lX11-xcb -lGL -orrxcb 
*/ 

#include <xcb/randr.h> 
#include <stdio.h> 
#include <X11/Xlib.h> 
#include <X11/Xlib-xcb.h> 
#include <xcb/xcb.h> 
#include <GL/glx.h> 
#include <unistd.h> 

void screen_from_Xlib_Display(
    Display * const display, 
    xcb_connection_t *connection, 
    int * const out_screen_num, 
    xcb_screen_t ** const out_screen) 
{ 
    xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); 
    int screen_num = DefaultScreen(display); 
    while(screen_iter.rem && screen_num > 0) { 
     xcb_screen_next(&screen_iter); 
     --screen_num; 
    } 
    *out_screen_num = screen_num; 
    *out_screen = screen_iter.data; 
} 

int main() 
{ 
    Display *display; 
    xcb_connection_t *connection; 
    xcb_window_t win; 
    const int GLX_TRUE = True; 
    int attrib_list[] = {GLX_X_RENDERABLE,GLX_TRUE, 
     GLX_DRAWABLE_TYPE,GLX_WINDOW_BIT, 
     GLX_RENDER_TYPE,GLX_RGBA_BIT, 
     GLX_CONFIG_CAVEAT,GLX_NONE, 
     GLX_DOUBLEBUFFER,GLX_TRUE, 
     GLX_BUFFER_SIZE,32, 
     GLX_DEPTH_SIZE,24, 
     GLX_STENCIL_SIZE,8, 
     0}; 
    GLXFBConfig *FBConfigs; 
    int nelements; 
    GLXFBConfig fb_config; 
    XVisualInfo *visual; 
    int visualID; 
    GLXContext context; 
    xcb_colormap_t colormap; 
    xcb_void_cookie_t create_color; 
    xcb_void_cookie_t create_win; 
    const uint32_t eventmask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS; 
    const uint32_t valuemask = XCB_CW_EVENT_MASK | XCB_CW_COLORMAP; 
    uint32_t valuelist[] = {eventmask,colormap}; 
    xcb_randr_get_screen_info_cookie_t screen_info; 
    xcb_randr_get_screen_info_reply_t *reply; 
    int screen_num; 
    xcb_screen_t *screen; 
    xcb_generic_error_t *error; 
    xcb_randr_screen_size_t *sizes; 
    int sizes_length; 
    xcb_randr_refresh_rates_iterator_t rates_iter; 
    uint16_t *rates; 
    int rates_length; 
    int i; 

    /* Open Xlib Display */ 
    display = XOpenDisplay(NULL); 
    printf("display = %p\n",display); 
    connection = XGetXCBConnection(display); 
    printf("connection = %p\n",connection); 
    XSetEventQueueOwner(display,XCBOwnsEventQueue); 
    win = xcb_generate_id(connection); 
    printf("win = %d\n",win); 
    screen_from_Xlib_Display(display,connection,&screen_num,&screen); 
    printf("screen_num = %d\n",screen_num); 
    printf("screen->root = %d\n",screen->root); 
    FBConfigs = glXChooseFBConfig(display,screen_num,attrib_list, 
     &nelements); 
    printf("FBConfig = %p\n",FBConfigs); 
    printf("nelements = %d\n",nelements); 
    fb_config = FBConfigs[0]; 
    visual = glXGetVisualFromFBConfig(display,fb_config); 
    printf("visual = %p\n",visual); 
    visualID = visual->visualid; 
    printf("visualID = %d\n",visualID); 
    context = glXCreateNewContext(display,fb_config,GLX_RGBA_TYPE, 
     0,True); 
    printf("context = %p\n",context); 
    colormap = xcb_generate_id(connection); 
    printf("colormap = %d\n",colormap); 
    create_color = xcb_create_colormap_checked(connection, 
    XCB_COLORMAP_ALLOC_NONE,colormap,screen->root,visualID); 
    printf("create_color.sequence = %d\n",create_color.sequence); 
    error = xcb_request_check(connection,create_color); 
    printf("error = %p\n",error); 
    create_win = xcb_create_window_checked(connection, 
     XCB_COPY_FROM_PARENT,win, screen->root,0,0,640,480,2, 
     XCB_WINDOW_CLASS_INPUT_OUTPUT,visualID,valuemask,valuelist); 
    printf("create_win.sequence = %d\n",create_win.sequence); 
    error = xcb_request_check(connection,create_win); 
    printf("error = %p\n",error); 
    screen_info = xcb_randr_get_screen_info_unchecked(connection, screen->root); 
    printf("screen_info.sequence = %d\n",screen_info.sequence); 
    reply = xcb_randr_get_screen_info_reply(connection,screen_info, 
     NULL); 
    printf("reply = %p\n",reply); 
    printf("reply->response_type = %d\n",reply->response_type); 
    printf("reply->rotations = %d\n",reply->rotations); 
    printf("reply->sequence = %d\n",reply->sequence); 
    printf("reply->length = %d\n",reply->length); 
    printf("reply->nSizes = %d\n",reply->nSizes); 
    printf("reply->sizeID = %d\n",reply->sizeID); 
    printf("reply->rotation = %d\n",reply->rotation); 
    printf("reply->rate = %d\n",reply->rate); 
    printf("reply->nInfo = %d\n",reply->nInfo); 
    printf("reply+1 = %p\n",reply+1); 
    sizes = xcb_randr_get_screen_info_sizes(reply); 
    printf("sizes = %p\n",sizes); 
    sizes_length = xcb_randr_get_screen_info_sizes_length(reply); 
    printf("sizes_length = %d\n",sizes_length); 
    rates_iter = xcb_randr_get_screen_info_rates_iterator(reply); 
    printf("rates_iter.data = %p\n",rates_iter.data); 
    printf("rates_iter.rem = %d\n",rates_iter.rem); 
    printf("rates_iter.index = %d\n",rates_iter.index); 
    for(; rates_iter.rem; xcb_randr_refresh_rates_next(&rates_iter)) 
    { 
     rates = xcb_randr_refresh_rates_rates(rates_iter.data); 
     printf("rates = %p\n",rates); 
     rates_length = 
     xcb_randr_refresh_rates_rates_length(rates_iter.data); 
     printf("rates_length = %d\n",rates_length); 
     printf("rates[0] = %d\n",rates[0]); 
/* 
     for(i = 0; i < rates_length; i++) 
     { 
     printf("%d%c",rates[i],(i==rates_length-1)?'\n':' '); 
     } 
*/ 
    } 
    for(i = 0; i < sizes_length; i++) 
    { 
     printf("%d %d %d %d %d\n",i,sizes[i].width,sizes[i].height,sizes[i].mwidth,sizes[i].mheight); 
    } 
    return 0; 
} 

所以我的輸出是

display = 0x563687942010 
connection = 0x563687943410 
win = 54525954 
screen_num = 0 
screen->root = 241 
FBConfig = 0x563687951b20 
nelements = 8 
visual = 0x563687951d30 
visualID = 33 
context = 0x563687951680 
colormap = 54525956 
create_color.sequence = 26 
error = (nil) 
create_win.sequence = 28 
error = (nil) 
screen_info.sequence = 31 
reply = 0x563687abde30 
reply->response_type = 1 
reply->rotations = 63 
reply->sequence = 31 
reply->length = 36 
reply->nSizes = 18 
reply->sizeID = 1 
reply->rotation = 1 
reply->rate = 30 
reply->nInfo = 53 
reply+1 = 0x563687abde50 
sizes = 0x563687abde50 
sizes_length = 18 
rates_iter.data = 0x563687abdee0 
rates_iter.rem = 35 
rates_iter.index = 176 
rates = 0x563687abdee2 
rates_length = 0 
rates[0] = 0 
rates = 0x563687abdee4 
rates_length = 0 
rates[0] = 0 
rates = 0x563687abdee6 
rates_length = 0 
... 
rates = 0x563687add7a8 
rates_length = 0 
rates[0] = 0 
0 4096 2160 1872 1053 
1 3840 2160 1872 1053 
2 1920 1080 1872 1053 
3 1680 1050 1872 1053 
4 1600 900 1872 1053 
5 1280 1024 1872 1053 
6 1440 900 1872 1053 
7 1366 768 1872 1053 
8 1280 800 1872 1053 
9 1152 864 1872 1053 
10 1280 720 1872 1053 
11 1024 768 1872 1053 
12 832 624 1872 1053 
13 800 600 1872 1053 
14 720 576 1872 1053 
15 720 480 1872 1053 
16 640 480 1872 1053 
17 720 400 1872 1053 

任何人都可以發現什麼,我做錯了什麼?

回答

0

好吧,在Linux休息一天後,我的頭撞在這堵磚牆上,我回答了我的大部分問題。 xcb_randr_get_screen_info_reply沒有完全起作用的原因是,在調用xcb_randr_get_screen_info_unchecked之前,必須首先調用xcb_randr_query_version,並將major_version和minor_version設置爲至少1,或者xcb認爲您的版本低於1.1或更低版本,並且您沒有刷新率數據結構正確設置。

然後,當我得到了那麼遠,我發現在我安裝的XCB/randr.h可怕的事情:

/** 
* Get the next element of the iterator 
* @param i Pointer to a xcb_randr_refresh_rates_iterator_t 
* 
* Get the next element in the iterator. The member rem is 
* decreased by one. The member data points to the next 
* element. The member index is increased by  sizeof(xcb_randr_refresh_rates_t) 
*/ 
void 
xcb_randr_refresh_rates_next (xcb_randr_refresh_rates_iterator_t *i /**< */); 

看到了嗎?成員rem減1,而不是數據 - > nRates,所以rem通過調用這個函數失效。這僅僅是xcb第一個規範中存在的錯誤,現在被凍結了,或者是有原因的嗎?因此,即使第一個問題得到解決,依賴於rem計數到零也不會起作用。

我甚至發現了爲什麼RandR爲我的屏幕獲取了錯誤的物理尺寸:物理尺寸在EDID字節21:22中以cm表示,並且對於我的電視是正確的。然而,它們也以毫米描述符1和描述符2在EDID字節66:68和字節84:86中給出,並且這些數字對應於TV中的84!當然,三星應該通過向我發送一個與他們的EDID數據相匹配的電視來解決這個問題:)

還有一個問題是EDID表示首選視頻模式是3840x2150 @ 60 Hz,即使只有計算機和電視擁有HDMI 1.4,因此指定的像素時鐘速率非常快。我想這就是爲什麼Windows 8.1很難用這臺電視啓動,爲什麼Linux和OSX都跳過本機模式並且啓動到4096x2160 @ 24 Hz,所以當Unity外殼沒有啓動時,128像素會被切斷。然而,Windows 10在電視上沒有問題。

我希望回答我自己的問題是正確的做法;我從來沒有在這個論壇上嘗試過。