打开全屏 OpenGL 窗口
Posted
技术标签:
【中文标题】打开全屏 OpenGL 窗口【英文标题】:Opening a fullscreen OpenGL window 【发布时间】:2012-06-09 11:34:33 【问题描述】:我正在尝试在 linux red-hat 上使用 GLFW 打开一个 OpenGL 全屏窗口。我有一个横跨两台显示器的桌面,总分辨率为 3840*1080。
我有两个问题: 1. 仅在一台显示器上打开窗口,最大窗口宽度为 1920(单台显示器的宽度)。 2.窗口最大高度为1003(我认为是屏幕高度减去任务栏和顶栏高度)。
这是我用来打开窗口的代码:
if (glfwInit() == GL_FALSE)
std::cout<< "Unable to initialize GLFW\n";
glfwOpenWindowHint(GLFW_STEREO, GL_FALSE);
if (glfwOpenWindow(3840,1080,8,8,8,0,24,0,GLFW_FULLSCREEN) == GL_FALSE)
std::cout<< "Unable to open window\n";
int width, height;
glfwGetWindowSize(&width, &height);
std::cout << "width = " << width << " height = " << height << "\n";
输出:宽度 = 1920 高度 = 1003
编辑: 我使用 xrandr 检查可用的屏幕模式并得到:
屏幕 0:最小 3840 x 1080,当前 3840 x 1080,最大 3840 x 1080 默认连接 3840x1080+0+0 0mm x 0mm 3840x1080 50.0*
编辑2: 我已更改代码以使用 X11 打开窗口
int doubleBufferAttributes[] =
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_DOUBLEBUFFER, True, /* Request a double-buffered color buffer with */
GLX_RED_SIZE, 1, /* the maximum number of bits per component */
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
None
;
static Bool WaitForNotify( Display *dpy, XEvent *event, XPointer arg )
return (event->type == MapNotify) && (event->xmap.window == (Window) arg);
int main( int argc, char *argv[] )
Display *dpy;
Window xWin;
XEvent event;
XVisualInfo *vInfo;
XSetWindowAttributes swa;
GLXFBConfig *fbConfigs;
GLXContext context;
GLXWindow glxWin;
int swaMask;
int numReturned;
int swapFlag = True;
/* Open a connection to the X server */
dpy = XOpenDisplay( NULL );
if ( dpy == NULL )
printf( "Unable to open a connection to the X server\n" );
exit( EXIT_FAILURE );
/* Request a suitable framebuffer configuration - try for a double
** buffered configuration first */
fbConfigs = glXChooseFBConfig( dpy, DefaultScreen(dpy),
doubleBufferAttributes, &numReturned );
/* Create an X colormap and window with a visual matching the first
** returned framebuffer config */
vInfo = glXGetVisualFromFBConfig( dpy, fbConfigs[0] );
swa.border_pixel = 0;
swa.event_mask = StructureNotifyMask;
swa.colormap = XCreateColormap( dpy, RootWindow(dpy, vInfo->screen),
vInfo->visual, AllocNone );
swaMask = CWBorderPixel | CWColormap | CWEventMask;
xWin = XCreateWindow( dpy, RootWindow(dpy, vInfo->screen), 0, 0, 3840, 1080,
0, vInfo->depth, InputOutput, vInfo->visual,
swaMask, &swa );
XWindowAttributes attt;
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "he = " << attt.height << " wi = " << attt.width << "\n";
/* Create a GLX context for OpenGL rendering */
context = glXCreateNewContext( dpy, fbConfigs[0], GLX_RGBA_TYPE,
NULL, True );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "2he = " << attt.height << " wi = " << attt.width << "\n";
/* Create a GLX window to associate the frame buffer configuration
** with the created X window */
glxWin = glXCreateWindow( dpy, fbConfigs[0], xWin, NULL );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "3he = " << attt.height << " wi = " << attt.width << "\n";
/* Map the window to the screen, and wait for it to appear */
XMapWindow( dpy, xWin );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "4he = " << attt.height << " wi = " << attt.width << "\n";
XIfEvent( dpy, &event, WaitForNotify, (XPointer) xWin );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "5he = " << attt.height << " wi = " << attt.width << "\n";
/* Bind the GLX context to the Window */
glXMakeContextCurrent( dpy, glxWin, glxWin, context );
XGetWindowAttributes( dpy,xWin, &attt);
std::cout << "6he = " << attt.height << " wi = " << attt.width << "\n";
输出是:
he = 1080 wi = 3840
2he = 1080 wi = 3840
3he = 1080 wi = 3840
4he = 1080 wi = 3840
5he = 1003 wi = 1920
6he = 1003 wi = 1920
似乎当窗口被显示时,它的大小会缩小。
【问题讨论】:
您是否尝试过枚举可用的视频模式并检查可用的视频模式? 我使用GLFW打开窗口,所以没有。我使用'xrandr'来查询视频模式:屏幕0:最小3840 x 1080,当前3840 x 1080,最大3840 x 1080。我目前正在将代码更改为使用X直接打开窗口。你能给我一个函数吗枚举可用的视频模式?默认连接 3840x1080+0+0 0mm x 0mm 3840x1080 50.0* @NicolBolas 请查看问题的最新编辑。 如果您的窗口在创建后被调整大小,那么您的窗口管理器认为它比您更清楚该做什么。在这种情况下,我只需更改 WM 或向 WM 开发人员提交错误报告。 【参考方案1】:不知道 GLFW,也许它有问题,但 X11 全屏窗口不能那样工作。任何称职的窗口管理器都会强制窗口适应(单个、非虚拟)屏幕。
你要么完全绕过窗口管理器(使用OverrideRedirect
窗口属性),要么要求你的WM配合(使用窗口属性_NET_WM_STATE_FULLSCREEN
)。第一种方法有很多缺点,所以让我们使用第二种方法。以下程序将在您的显示器上显示一个窗口,然后将其切换到全屏模式:
#include <X11/X.h>
#include <X11/Xlib.h>
#include <strings.h>
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
int main ()
Display* dis = XOpenDisplay(NULL);
Window win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 0, 0, 10, 10,
0, BlackPixel (dis, 0), BlackPixel(dis, 0));
Atom wm_state = XInternAtom(dis, "_NET_WM_STATE", False);
Atom fullscreen = XInternAtom(dis, "_NET_WM_STATE_FULLSCREEN", False);
XEvent xev;
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = win;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 1;
xev.xclient.data.l[1] = fullscreen;
xev.xclient.data.l[2] = 0;
XMapWindow(dis, win);
XSendEvent (dis, DefaultRootWindow(dis), False,
SubstructureRedirectMask | SubstructureNotifyMask, &xev);
XFlush(dis);
/*Sleep 5 seconds before closing.*/
sleep(5);
return(0);
您可能从一开始就为窗口使用真实的屏幕尺寸,以避免任何调整大小的动画效果。
我没有在多头系统上尝试这个,因为我没有,但在单个显示系统上它可以正常工作(覆盖面板,移除窗口装饰等)。请让我知道它是否适合您。
更新他们说要使多头工作,您需要使用_NET_WM_FULLSCREEN_MONITORS
属性(请参阅here)。它是一个由 4 个整数组成的数组,应该像这样设置:
Atom fullmons = XInternAtom(dis, "_NET_WM_FULLSCREEN_MONITORS", False);
XEvent xev;
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = win;
xev.xclient.message_type = fullmons;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 0; /* your topmost monitor number */
xev.xclient.data.l[1] = 0; /* bottommost */
xev.xclient.data.l[2] = 0; /* leftmost */
xev.xclient.data.l[3] = 1; /* rightmost */
xev.xclient.data.l[4] = 0; /* source indication */
XSendEvent (dis, DefaultRootWindow(dis), False,
SubstructureRedirectMask | SubstructureNotifyMask, &xev);
有了这个,您应该能够将全屏窗口设置为占用单个显示器、整个桌面或(对于超过 2 个显示器)两者之间的任何内容。
我没有检查这个,因为我没有多头系统。
【讨论】:
感谢您的详细回答。在看到您的答案之前,我尝试使用 OverrideRedirect (您的第一个建议方法)。最后,我在 xorg.conf 中打开了 Xinerama 模式(这种模式会诱使 WM 认为只有一个大显示器)。 非常感谢,这是解决 X11 全屏问题的唯一答案,此外:xev.xclient.data.l[0] = 1;可以更改为 =0 用于恢复或 =2 用于切换。【参考方案2】:xcb 版本:
xcb_connection_t *xcbConnection = xcb_connect(":0", &screenp);
xcb_intern_atom_cookie_t type = xcb_intern_atom(xcbConnection, false, strlen("_NET_WM_FULLSCREEN_MONITORS"), "_NET_WM_FULLSCREEN_MONITORS");
xcb_intern_atom_reply_t *reply_st = xcb_intern_atom_reply(xcbConnection, type, NULL);
xcb_client_message_event_t event;
memset(&event, 0, sizeof(event));
event.response_type = XCB_CLIENT_MESSAGE;
event.type = reply_st->atom;
event.window = this->winId();
event.format = 32;
event.data.data32[0] = 0; // top
event.data.data32[1] = 0; // bottom
event.data.data32[2] = 0; // left
event.data.data32[3] = 1; // right
event.data.data32[4] = 1;
uint32_t eventMask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT|XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_send_event(xcbConnection, false, pScreen0->root, eventMask, reinterpret_cast<const char*>(&event));
xcb_flush(xcbConnection);
【讨论】:
以上是关于打开全屏 OpenGL 窗口的主要内容,如果未能解决你的问题,请参考以下文章