Rev 16 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "OpenGLContext.h"
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/Xlib.h>
#include <X11/Xcursor/Xcursor.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// vmode extension for mode settings, gamma control, etc.
#include <X11/extensions/xf86vmode.h>
// XRandR extension for virtual screens, mode setting, etc.
#include <X11/extensions/Xrandr.h>
struct OpenGLContext::OpenGLContextInfo{
Display *display;
Window window;
GLXContext context;
OpenGLContextInfo() : display(NULL), window(0), context(NULL){}
};
std::vector<ScreenInfo> OpenGLContext::GetScreenInfo(){
std::vector<ScreenInfo> ret;
// Connection to default X Server
Display *display = XOpenDisplay(NULL);
RROutput primaryOutput = XRRGetOutputPrimary(display, RootWindow(display, 0));
XRRScreenResources* sr = XRRGetScreenResources(display, RootWindow(display, 0));
// number of virtual (XRandr screens)
unsigned int nVirtualScreens = sr->ncrtc;
for (unsigned int j = 0; j < nVirtualScreens; j++){
XRROutputInfo* oi;
XRRCrtcInfo* ci;
RROutput output;
// check if the crt has outputs
ci = XRRGetCrtcInfo(display, sr, sr->crtcs[j]);
if (ci->noutput == 0){
XRRFreeCrtcInfo(ci);
continue;
}
output = ci->outputs[0];
// if primaryoutput is among outputs, use that instead of the first
for (int k = 0; k < ci->noutput; k++){
if (ci->outputs[k] == primaryOutput){
output = primaryOutput;
break;
}
}
// check that the output is connected
oi = XRRGetOutputInfo(display, sr, output);
if(oi->connection != RR_Connected){
XRRFreeOutputInfo(oi);
XRRFreeCrtcInfo(ci);
continue;
}
ScreenInfo info;
info.name = oi->name;
// get current mode
XRRModeInfo *modeInfo;
for (int k = 0; k < sr->nmode; k++){
if (sr->modes[k].id == ci->mode){
modeInfo = sr->modes + k;
break;
}
}
info.resX = modeInfo->width;
info.resY = modeInfo->height;
info.posX = ci->x;
info.posY = ci->y;
ret.push_back(info);
}
XRRFreeScreenResources(sr);
XCloseDisplay(display);
return ret;
}
OpenGLContext::OpenGLContext(uint _screenNum) : screenNum(_screenNum){
std::vector<ScreenInfo> virtualScreens = GetScreenInfo();
if(screenNum > virtualScreens.size())
std::cerr << "OpenGLContext: cannot open screen no. " << screenNum << "!" << std::endl;
ScreenInfo screen = virtualScreens[screenNum];
screenResX = screen.resX;
screenResY = screen.resY;
contextInfo = new OpenGLContextInfo();
contextInfo->display = XOpenDisplay(NULL);
int attrListDbl[] = {
GLX_RGBA, GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 4,
GLX_GREEN_SIZE, 4,
GLX_BLUE_SIZE, 4,
None
};
XVisualInfo *visualInfo = glXChooseVisual(contextInfo->display, 0, attrListDbl);
int glxMajor, glxMinor = 0;
glXQueryVersion(contextInfo->display, &glxMajor, &glxMinor);
std::cout << "GLX-Version " << glxMajor << "." << glxMinor << std::endl;
// Create a GLX OpenGLContext
bool directRendering = True;
contextInfo->context = glXCreateContext(contextInfo->display, visualInfo, NULL, directRendering);
// Check if OpenGLContext is direct
if (glXIsDirect(contextInfo->display, contextInfo->context))
std::cout << "OpenGLContext is direct." << std::endl;
else
std::cout << "OpenGLContext is not direct." << std::endl;
// Create colormap
Colormap colormap = XCreateColormap(contextInfo->display, RootWindow(contextInfo->display, 0), visualInfo->visual, AllocNone);
// Create the actual window
unsigned long wamask = CWColormap;
XSetWindowAttributes wa;
wa.colormap = colormap;
wa.border_pixel = 0;
wa.event_mask = 0;
// bypass window manager (has no effect here)
wa.override_redirect = True;
// show no cursor
wa.cursor = None;
contextInfo->window = XCreateWindow(contextInfo->display, RootWindow(contextInfo->display, 0), screen.posX, screen.posY, screenResX, screenResY, 0, visualInfo->depth, InputOutput, visualInfo->visual, wamask, &wa);
// move to correct position (necessary when not overriding redirect)
XMoveWindow(contextInfo->display, contextInfo->window, screen.posX, screen.posY);
if(!contextInfo->window)
std::cerr << "Failed to create X window!" << std::endl;
// bypass window manager (actually effects here)
XSetWindowAttributes attributes;
attributes.override_redirect = False;
XChangeWindowAttributes(contextInfo->display, contextInfo->window, CWOverrideRedirect, &attributes);
// Disable mouse cursor over window
XcursorImage *cursorImage = XcursorImageCreate(1, 1);
*cursorImage->pixels = 0;
cursorImage->xhot = 0;
cursorImage->yhot = 0;
Cursor cursor = XcursorImageLoadCursor(contextInfo->display, cursorImage);
XDefineCursor(contextInfo->display, contextInfo->window, cursor);
XFreeCursor(contextInfo->display, cursor);
// Connect the glx-OpenGLContext to the window
glXMakeCurrent(contextInfo->display, contextInfo->window, contextInfo->context);
// Window state
Atom wmNetWmState = XInternAtom(contextInfo->display, "_NET_WM_STATE", 1);
// raise window above most other windows
Atom wmStateAbove = XInternAtom(contextInfo->display, "_NET_WM_STATE_ABOVE", 1);
// define window as fullscreen
Atom wmStateFullScreen = XInternAtom(contextInfo->display, "_NET_WM_STATE_FULLSCREEN", 1);
XEvent event;
memset(&event, 0, sizeof(event));
event.type = ClientMessage;
event.xclient.window = contextInfo->window;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = wmNetWmState;
event.xclient.data.l[0] = 1; // Add the state
event.xclient.data.l[2] = 0; // No secondary property
event.xclient.data.l[3] = 1; // Sender is a normal application
event.xclient.data.l[1] = wmStateAbove;
XSendEvent(contextInfo->display, RootWindow(contextInfo->display, 0), False, SubstructureNotifyMask | SubstructureRedirectMask, &event);
event.xclient.data.l[1] = wmStateFullScreen;
XSendEvent(contextInfo->display, RootWindow(contextInfo->display, 0), False, SubstructureNotifyMask | SubstructureRedirectMask, &event);
// // Set active window
// Atom wmActiveWindow = XInternAtom(contextInfo->display, "_NET_WM_ACTIVE_WINDOW", 1);
// event.xclient.message_type = wmActiveWindow;
// event.xclient.data.l[0] = 1; // Sender is a normal application
// event.xclient.data.l[1] = 0; // We don't really know the timestamp
// XSendEvent(contextInfo->display, RootWindow(contextInfo->display, 0), False, SubstructureNotifyMask | SubstructureRedirectMask, &event);
// Set swap interval to 1 for vsync
const char *glx_extensions = glXQueryExtensionsString(contextInfo->display, 0);
if (strstr(glx_extensions, "GLX_SGI_swap_control")) {
PFNGLXSWAPINTERVALSGIPROC SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalSGI");
SwapIntervalSGI(1);
} else if (strstr(glx_extensions, "GLX_EXT_swap_control")) {
PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT");
SwapIntervalEXT(contextInfo->display, contextInfo->window, 1);
} else {
std::cerr << "OpenGLContext Error: Could not access swap interval extension!" << std::endl;
}
// Raise window (necessary)
XMapRaised(contextInfo->display, contextInfo->window);
XFlush(contextInfo->display);
// Adjust gamma to one
// setGamma(1.9);
}
void OpenGLContext::setGamma(float gamma){
// Adjust gamma
XF86VidModeGamma xf86Gamma = {gamma, gamma, gamma};
XF86VidModeSetGamma(contextInfo->display, screenNum, &xf86Gamma);
}
void OpenGLContext::makeContextCurrent(){
glXMakeCurrent(contextInfo->display, contextInfo->window, contextInfo->context);
}
void OpenGLContext::flush(){
// Swap buffers
glXSwapBuffers(contextInfo->display, contextInfo->window);
// Synchronize CPU with vsync buffer swap
//glFinish();
//glXWaitGL();
}
OpenGLContext::~OpenGLContext(){
std::cout<<"Releasing OpenGL Context\n"<<std::flush;
if(contextInfo->context){
// Release context (None, NULL)
if(!glXMakeCurrent(contextInfo->display, None, NULL))
std::cerr << "Error. Could not release drawing OpenGLContext." << std::endl;
glXDestroyContext(contextInfo->display, contextInfo->context);
XCloseDisplay(contextInfo->display);
delete contextInfo;
}
}