|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "framework.h" |
|
#include "glutil.h" |
|
#include <iostream> |
|
#include <iomanip> |
|
|
|
|
|
#define GLUTIL_EXT(return_type, name, ...) return_type (GLAPIENTRY* name)(__VA_ARGS__) = 0; |
|
#include "glutil_extlist.h" |
|
#undef GLUTIL_EXT |
|
|
|
|
|
static volatile bool s_glExtInitialized = false; |
|
|
|
|
|
const char* getGLErrorString(GLenum err) |
|
{ |
|
switch(err) |
|
{ |
|
case GL_NO_ERROR: return "GL_NO_ERROR"; |
|
case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; |
|
case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; |
|
case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; |
|
case GL_STACK_OVERFLOW: return "GL_STACK_OVERFLOW"; |
|
case GL_STACK_UNDERFLOW: return "GL_STACK_UNDERFLOW"; |
|
case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; |
|
case GL_INVALID_FRAMEBUFFER_OPERATION: return "GL_INVALID_FRAMEBUFFER_OPERATION"; |
|
case GL_TABLE_TOO_LARGE: return "GL_TABLE_TOO_LARGE"; |
|
case GL_CONTEXT_LOST: return "GL_CONTEXT_LOST"; |
|
} |
|
return "Unknown error"; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
static CRITICAL_SECTION getInitializedCriticalSection(void) |
|
{ |
|
CRITICAL_SECTION cs; |
|
InitializeCriticalSection(&cs); |
|
return cs; |
|
} |
|
|
|
static CRITICAL_SECTION s_getProcAddressMutex = getInitializedCriticalSection(); |
|
|
|
static void safeGetProcAddress(const char* name, PROC* pfn) |
|
{ |
|
PROC result = wglGetProcAddress(name); |
|
if (!result) |
|
{ |
|
LeaveCriticalSection(&s_getProcAddressMutex); |
|
LOG(FATAL) << "wglGetProcAddress() failed for '" << name << "'"; |
|
exit(1); |
|
} |
|
*pfn = result; |
|
} |
|
|
|
static void initializeGLExtensions(void) |
|
{ |
|
|
|
EnterCriticalSection(&s_getProcAddressMutex); |
|
|
|
|
|
if (!s_glExtInitialized) |
|
{ |
|
|
|
#define GLUTIL_EXT(return_type, name, ...) safeGetProcAddress(#name, (PROC*)&name); |
|
#include "glutil_extlist.h" |
|
#undef GLUTIL_EXT |
|
|
|
|
|
s_glExtInitialized = true; |
|
} |
|
|
|
|
|
LeaveCriticalSection(&s_getProcAddressMutex); |
|
return; |
|
} |
|
|
|
void setGLContext(GLContext& glctx) |
|
{ |
|
if (!glctx.hglrc) |
|
LOG(FATAL) << "setGLContext() called with null gltcx"; |
|
if (!wglMakeCurrent(glctx.hdc, glctx.hglrc)) |
|
LOG(FATAL) << "wglMakeCurrent() failed when setting GL context"; |
|
|
|
if (glctx.extInitialized) |
|
return; |
|
initializeGLExtensions(); |
|
glctx.extInitialized = 1; |
|
} |
|
|
|
void releaseGLContext(void) |
|
{ |
|
if (!wglMakeCurrent(NULL, NULL)) |
|
LOG(FATAL) << "wglMakeCurrent() failed when releasing GL context"; |
|
} |
|
|
|
extern "C" int set_gpu(const char*); |
|
GLContext createGLContext(int cudaDeviceIdx) |
|
{ |
|
if (cudaDeviceIdx >= 0) |
|
{ |
|
char pciBusId[256] = ""; |
|
LOG(INFO) << "Creating GL context for Cuda device " << cudaDeviceIdx; |
|
if (cudaDeviceGetPCIBusId(pciBusId, 255, cudaDeviceIdx)) |
|
{ |
|
LOG(INFO) << "PCI bus id query failed"; |
|
} |
|
else |
|
{ |
|
int res = set_gpu(pciBusId); |
|
LOG(INFO) << "Selecting device with PCI bus id " << pciBusId << " - " << (res ? "failed, expect crash or major slowdown" : "success"); |
|
} |
|
} |
|
|
|
HINSTANCE hInstance = GetModuleHandle(NULL); |
|
WNDCLASS wc = {}; |
|
wc.style = CS_OWNDC; |
|
wc.lpfnWndProc = DefWindowProc; |
|
wc.hInstance = hInstance; |
|
wc.lpszClassName = "__DummyGLClassCPP"; |
|
int res = RegisterClass(&wc); |
|
|
|
HWND hwnd = CreateWindow( |
|
"__DummyGLClassCPP", |
|
"__DummyGLWindowCPP", |
|
WS_OVERLAPPEDWINDOW, |
|
CW_USEDEFAULT, |
|
CW_USEDEFAULT, |
|
0, 0, |
|
NULL, NULL, |
|
hInstance, |
|
NULL |
|
); |
|
|
|
PIXELFORMATDESCRIPTOR pfd = {}; |
|
pfd.dwFlags = PFD_SUPPORT_OPENGL; |
|
pfd.iPixelType = PFD_TYPE_RGBA; |
|
pfd.iLayerType = PFD_MAIN_PLANE; |
|
pfd.cColorBits = 32; |
|
pfd.cDepthBits = 24; |
|
pfd.cStencilBits = 8; |
|
|
|
HDC hdc = GetDC(hwnd); |
|
int pixelformat = ChoosePixelFormat(hdc, &pfd); |
|
SetPixelFormat(hdc, pixelformat, &pfd); |
|
|
|
HGLRC hglrc = wglCreateContext(hdc); |
|
LOG(INFO) << std::hex << std::setfill('0') |
|
<< "WGL OpenGL context created (hdc: 0x" << std::setw(8) << (uint32_t)(uintptr_t)hdc |
|
<< ", hglrc: 0x" << std::setw(8) << (uint32_t)(uintptr_t)hglrc << ")"; |
|
|
|
GLContext glctx = {hdc, hglrc, 0}; |
|
return glctx; |
|
} |
|
|
|
void destroyGLContext(GLContext& glctx) |
|
{ |
|
if (!glctx.hglrc) |
|
LOG(FATAL) << "destroyGLContext() called with null gltcx"; |
|
|
|
|
|
if (wglGetCurrentContext() == glctx.hglrc) |
|
releaseGLContext(); |
|
|
|
HWND hwnd = WindowFromDC(glctx.hdc); |
|
if (!hwnd) |
|
LOG(FATAL) << "WindowFromDC() failed"; |
|
if (!ReleaseDC(hwnd, glctx.hdc)) |
|
LOG(FATAL) << "ReleaseDC() failed"; |
|
if (!wglDeleteContext(glctx.hglrc)) |
|
LOG(FATAL) << "wglDeleteContext() failed"; |
|
if (!DestroyWindow(hwnd)) |
|
LOG(FATAL) << "DestroyWindow() failed"; |
|
|
|
LOG(INFO) << std::hex << std::setfill('0') |
|
<< "WGL OpenGL context destroyed (hdc: 0x" << std::setw(8) << (uint32_t)(uintptr_t)glctx.hdc |
|
<< ", hglrc: 0x" << std::setw(8) << (uint32_t)(uintptr_t)glctx.hglrc << ")"; |
|
|
|
memset(&glctx, 0, sizeof(GLContext)); |
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
#ifdef __linux__ |
|
|
|
static pthread_mutex_t s_getProcAddressMutex; |
|
|
|
typedef void (*PROCFN)(); |
|
|
|
static void safeGetProcAddress(const char* name, PROCFN* pfn) |
|
{ |
|
PROCFN result = eglGetProcAddress(name); |
|
if (!result) |
|
{ |
|
pthread_mutex_unlock(&s_getProcAddressMutex); |
|
LOG(FATAL) << "wglGetProcAddress() failed for '" << name << "'"; |
|
exit(1); |
|
} |
|
*pfn = result; |
|
} |
|
|
|
static void initializeGLExtensions(void) |
|
{ |
|
pthread_mutex_lock(&s_getProcAddressMutex); |
|
|
|
|
|
if (!s_glExtInitialized) |
|
{ |
|
|
|
#define GLUTIL_EXT(return_type, name, ...) safeGetProcAddress(#name, (PROCFN*)&name); |
|
#include "glutil_extlist.h" |
|
#undef GLUTIL_EXT |
|
|
|
|
|
s_glExtInitialized = true; |
|
} |
|
|
|
pthread_mutex_unlock(&s_getProcAddressMutex); |
|
return; |
|
} |
|
|
|
void setGLContext(GLContext& glctx) |
|
{ |
|
if (!glctx.context) |
|
LOG(FATAL) << "setGLContext() called with null gltcx"; |
|
|
|
if (!eglMakeCurrent(glctx.display, EGL_NO_SURFACE, EGL_NO_SURFACE, glctx.context)) |
|
LOG(ERROR) << "eglMakeCurrent() failed when setting GL context"; |
|
|
|
if (glctx.extInitialized) |
|
return; |
|
initializeGLExtensions(); |
|
glctx.extInitialized = 1; |
|
} |
|
|
|
void releaseGLContext(void) |
|
{ |
|
EGLDisplay display = eglGetCurrentDisplay(); |
|
if (display == EGL_NO_DISPLAY) |
|
LOG(WARNING) << "releaseGLContext() called with no active display"; |
|
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) |
|
LOG(FATAL) << "eglMakeCurrent() failed when releasing GL context"; |
|
} |
|
|
|
static EGLDisplay getCudaDisplay(int cudaDeviceIdx) |
|
{ |
|
typedef EGLBoolean (*eglQueryDevicesEXT_t)(EGLint, EGLDeviceEXT, EGLint*); |
|
typedef EGLBoolean (*eglQueryDeviceAttribEXT_t)(EGLDeviceEXT, EGLint, EGLAttrib*); |
|
typedef EGLDisplay (*eglGetPlatformDisplayEXT_t)(EGLenum, void*, const EGLint*); |
|
|
|
eglQueryDevicesEXT_t eglQueryDevicesEXT = (eglQueryDevicesEXT_t)eglGetProcAddress("eglQueryDevicesEXT"); |
|
if (!eglQueryDevicesEXT) |
|
{ |
|
LOG(INFO) << "eglGetProcAddress(\"eglQueryDevicesEXT\") failed"; |
|
return 0; |
|
} |
|
|
|
eglQueryDeviceAttribEXT_t eglQueryDeviceAttribEXT = (eglQueryDeviceAttribEXT_t)eglGetProcAddress("eglQueryDeviceAttribEXT"); |
|
if (!eglQueryDeviceAttribEXT) |
|
{ |
|
LOG(INFO) << "eglGetProcAddress(\"eglQueryDeviceAttribEXT\") failed"; |
|
return 0; |
|
} |
|
|
|
eglGetPlatformDisplayEXT_t eglGetPlatformDisplayEXT = (eglGetPlatformDisplayEXT_t)eglGetProcAddress("eglGetPlatformDisplayEXT"); |
|
if (!eglGetPlatformDisplayEXT) |
|
{ |
|
LOG(INFO) << "eglGetProcAddress(\"eglGetPlatformDisplayEXT\") failed"; |
|
return 0; |
|
} |
|
|
|
int num_devices = 0; |
|
eglQueryDevicesEXT(0, 0, &num_devices); |
|
if (!num_devices) |
|
return 0; |
|
|
|
EGLDisplay display = 0; |
|
EGLDeviceEXT* devices = (EGLDeviceEXT*)malloc(num_devices * sizeof(void*)); |
|
eglQueryDevicesEXT(num_devices, devices, &num_devices); |
|
for (int i=0; i < num_devices; i++) |
|
{ |
|
EGLDeviceEXT device = devices[i]; |
|
intptr_t value = -1; |
|
if (eglQueryDeviceAttribEXT(device, EGL_CUDA_DEVICE_NV, &value) && value == cudaDeviceIdx) |
|
{ |
|
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, device, 0); |
|
break; |
|
} |
|
} |
|
|
|
free(devices); |
|
return display; |
|
} |
|
|
|
GLContext createGLContext(int cudaDeviceIdx) |
|
{ |
|
EGLDisplay display = 0; |
|
|
|
if (cudaDeviceIdx >= 0) |
|
{ |
|
char pciBusId[256] = ""; |
|
LOG(INFO) << "Creating GL context for Cuda device " << cudaDeviceIdx; |
|
display = getCudaDisplay(cudaDeviceIdx); |
|
if (!display) |
|
LOG(INFO) << "Failed, falling back to default display"; |
|
} |
|
|
|
if (!display) |
|
{ |
|
display = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
|
if (display == EGL_NO_DISPLAY) |
|
LOG(FATAL) << "eglGetDisplay() failed"; |
|
} |
|
|
|
EGLint major; |
|
EGLint minor; |
|
if (!eglInitialize(display, &major, &minor)) |
|
LOG(FATAL) << "eglInitialize() failed"; |
|
|
|
|
|
|
|
const EGLint context_attribs[] = { |
|
EGL_RED_SIZE, 8, |
|
EGL_GREEN_SIZE, 8, |
|
EGL_BLUE_SIZE, 8, |
|
EGL_ALPHA_SIZE, 8, |
|
EGL_DEPTH_SIZE, 24, |
|
EGL_STENCIL_SIZE, 8, |
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, |
|
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, |
|
EGL_NONE |
|
}; |
|
|
|
EGLConfig config; |
|
EGLint num_config; |
|
if (!eglChooseConfig(display, context_attribs, &config, 1, &num_config)) |
|
LOG(FATAL) << "eglChooseConfig() failed"; |
|
|
|
|
|
|
|
if (!eglBindAPI(EGL_OPENGL_API)) |
|
LOG(FATAL) << "eglBindAPI() failed"; |
|
|
|
EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, NULL); |
|
if (context == EGL_NO_CONTEXT) |
|
LOG(FATAL) << "eglCreateContext() failed"; |
|
|
|
|
|
|
|
LOG(INFO) << "EGL " << (int)minor << "." << (int)major << " OpenGL context created (disp: 0x" |
|
<< std::hex << std::setfill('0') |
|
<< std::setw(16) << (uintptr_t)display |
|
<< ", ctx: 0x" << std::setw(16) << (uintptr_t)context << ")"; |
|
|
|
GLContext glctx = {display, context, 0}; |
|
return glctx; |
|
} |
|
|
|
void destroyGLContext(GLContext& glctx) |
|
{ |
|
if (!glctx.context) |
|
LOG(FATAL) << "destroyGLContext() called with null gltcx"; |
|
|
|
|
|
if (eglGetCurrentContext() == glctx.context) |
|
releaseGLContext(); |
|
|
|
if (!eglDestroyContext(glctx.display, glctx.context)) |
|
LOG(ERROR) << "eglDestroyContext() failed"; |
|
|
|
LOG(INFO) << "EGL OpenGL context destroyed (disp: 0x" |
|
<< std::hex << std::setfill('0') |
|
<< std::setw(16) << (uintptr_t)glctx.display |
|
<< ", ctx: 0x" << std::setw(16) << (uintptr_t)glctx.context << ")"; |
|
|
|
memset(&glctx, 0, sizeof(GLContext)); |
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|