270 lines
9.6 KiB
C
270 lines
9.6 KiB
C
// first load the opengl loading functions
|
|
fn b32 w32_load_wgl_fns(void);
|
|
|
|
// then create opengl context for window
|
|
fn b32 w32_create_opengl_context(HDC window_handle_dc, i32 opengl_major, i32 opengl_minor);
|
|
|
|
// then you can use this to load opengl functions -
|
|
// either pass this to glad or load them manually
|
|
fn void *w32_load_opengl_fn(const char *proc);
|
|
|
|
// compile time options
|
|
#define W32_OPENGL_DEBUG 1
|
|
#define W32_ENABLE_MULTISAMPLING 1
|
|
|
|
// Symbols taken from GLFW
|
|
//
|
|
// Executables (but not DLLs) exporting this symbol with this value will be
|
|
// automatically directed to the high-performance GPU on Nvidia Optimus systems
|
|
// with up-to-date drivers
|
|
//
|
|
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
|
|
|
|
// Executables (but not DLLs) exporting this symbol with this value will be
|
|
// automatically directed to the high-performance GPU on AMD PowerXpress systems
|
|
// with up-to-date drivers
|
|
//
|
|
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
|
|
|
typedef HGLRC MU_wglCreateContext(HDC unnamedParam1);
|
|
typedef BOOL MU_wglMakeCurrent(HDC unnamedParam1, HGLRC unnamedParam2);
|
|
typedef BOOL MU_wglDeleteContext(HGLRC unnamedParam1);
|
|
typedef void *MU_glGetProcAddress(const char *);
|
|
typedef const char *MU_wglGetExtensionsStringARB(HDC hdc);
|
|
typedef BOOL MU_wglChoosePixelFormatARB(HDC hdc, const int *piAttribIList, const float *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
|
typedef HGLRC MU_wglCreateContextAttribsARB(HDC hDC, HGLRC hshareContext, const int *attribList);
|
|
typedef BOOL MU_wglSwapIntervalEXT(int interval);
|
|
|
|
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
|
|
#define WGL_SUPPORT_OPENGL_ARB 0x2010
|
|
#define WGL_DOUBLE_BUFFER_ARB 0x2011
|
|
#define WGL_PIXEL_TYPE_ARB 0x2013
|
|
#define WGL_TYPE_RGBA_ARB 0x202B
|
|
#define WGL_COLOR_BITS_ARB 0x2014
|
|
#define WGL_DEPTH_BITS_ARB 0x2022
|
|
#define WGL_STENCIL_BITS_ARB 0x2023
|
|
#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
|
|
#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
|
|
#define WGL_CONTEXT_FLAGS_ARB 0x2094
|
|
#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
|
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
|
|
#define WGL_SAMPLES_ARB 0x2042
|
|
|
|
gb MU_wglChoosePixelFormatARB *wglChoosePixelFormatARB;
|
|
gb MU_wglCreateContextAttribsARB *wglCreateContextAttribsARB;
|
|
gb MU_wglSwapIntervalEXT *wglSwapIntervalEXT;
|
|
|
|
gb MU_glGetProcAddress *wgl_get_proc_address;
|
|
gb void *(*gl_get_proc_address)(const char *str);
|
|
gb HMODULE opengl_hmodule;
|
|
|
|
gb HGLRC(*mu_wglCreateContext)(HDC unnamedParam1);
|
|
gb BOOL(*mu_wglMakeCurrent)(HDC unnamedParam1, HGLRC unnamedParam2);
|
|
gb BOOL(*mu_wglDeleteContext)(HGLRC unnamedParam1);
|
|
|
|
// compares src string with dstlen characters from dst, returns 1 if they are equal, 0 if not
|
|
fn int w32_are_strings_equal(const char *src, const char *dst, size_t dstlen) {
|
|
while (*src && dstlen-- && *dst) {
|
|
if (*src++ != *dst++) {
|
|
return 0;
|
|
}
|
|
}
|
|
return (dstlen && *src == *dst) || (!dstlen && *src == 0);
|
|
}
|
|
|
|
fn void *w32_load_opengl_fn(const char *proc) {
|
|
void *func = wgl_get_proc_address(proc);
|
|
if (!func) {
|
|
func = GetProcAddress(opengl_hmodule, proc);
|
|
}
|
|
return func;
|
|
}
|
|
|
|
fn b32 w32_load_wgl_fns(void) {
|
|
HMODULE opengl32 = LoadLibraryA("opengl32");
|
|
assert(opengl32);
|
|
if (opengl32) {
|
|
opengl_hmodule = opengl32;
|
|
wgl_get_proc_address = (MU_glGetProcAddress *)GetProcAddress(opengl32, "wglGetProcAddress");
|
|
gl_get_proc_address = w32_load_opengl_fn;
|
|
mu_wglCreateContext = (MU_wglCreateContext *)GetProcAddress(opengl32, "wglCreateContext");
|
|
mu_wglMakeCurrent = (MU_wglMakeCurrent *)GetProcAddress(opengl32, "wglMakeCurrent");
|
|
mu_wglDeleteContext = (MU_wglDeleteContext *)GetProcAddress(opengl32, "wglDeleteContext");
|
|
}
|
|
if (opengl32 == NULL || mu_wglCreateContext == NULL || gl_get_proc_address == NULL || mu_wglMakeCurrent == NULL || mu_wglDeleteContext == NULL) {
|
|
assert(!"Failed to load Opengl wgl functions from opengl32.lib");
|
|
}
|
|
|
|
// to get WGL functions we need valid GL context, so create dummy window for dummy GL contetx
|
|
HWND dummy = CreateWindowExW(
|
|
0, L"STATIC", L"DummyWindow", WS_OVERLAPPED,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
NULL, NULL, NULL, NULL);
|
|
assert(dummy && "Failed to create dummy window");
|
|
|
|
HDC dc = GetDC(dummy);
|
|
assert(dc && "Failed to get device context for dummy window");
|
|
|
|
PIXELFORMATDESCRIPTOR desc = {0};
|
|
{
|
|
desc.nSize = sizeof(desc);
|
|
desc.nVersion = 1;
|
|
desc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
|
|
desc.iPixelType = PFD_TYPE_RGBA;
|
|
desc.cColorBits = 24;
|
|
};
|
|
|
|
int format = ChoosePixelFormat(dc, &desc);
|
|
if (!format) {
|
|
assert(!"Cannot choose OpenGL pixel format for dummy window!");
|
|
}
|
|
|
|
int ok = DescribePixelFormat(dc, format, sizeof(desc), &desc);
|
|
assert(ok && "Failed to describe OpenGL pixel format");
|
|
|
|
// reason to create dummy window is that SetPixelFormat can be called only once for the window
|
|
if (!SetPixelFormat(dc, format, &desc)) {
|
|
assert(!"Cannot set OpenGL pixel format for dummy window!");
|
|
}
|
|
|
|
HGLRC rc = mu_wglCreateContext(dc);
|
|
assert(rc && "Failed to create OpenGL context for dummy window");
|
|
|
|
ok = mu_wglMakeCurrent(dc, rc);
|
|
assert(ok && "Failed to make current OpenGL context for dummy window");
|
|
|
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_extensions_string.txt
|
|
MU_wglGetExtensionsStringARB *wglGetExtensionsStringARB = (MU_wglGetExtensionsStringARB *)gl_get_proc_address("wglGetExtensionsStringARB");
|
|
if (!wglGetExtensionsStringARB) {
|
|
assert(!"OpenGL does not support WGL_ARB_extensions_string extension!");
|
|
}
|
|
|
|
const char *ext = wglGetExtensionsStringARB(dc);
|
|
assert(ext && "Failed to get OpenGL WGL extension string");
|
|
|
|
const char *start = ext;
|
|
for (;;) {
|
|
while (*ext != 0 && *ext != ' ') {
|
|
ext++;
|
|
}
|
|
size_t length = ext - start;
|
|
if (w32_are_strings_equal("WGL_ARB_pixel_format", start, length)) {
|
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt
|
|
wglChoosePixelFormatARB = (MU_wglChoosePixelFormatARB *)gl_get_proc_address("wglChoosePixelFormatARB");
|
|
}
|
|
else if (w32_are_strings_equal("WGL_ARB_create_context", start, length)) {
|
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_create_context.txt
|
|
wglCreateContextAttribsARB = (MU_wglCreateContextAttribsARB *)gl_get_proc_address("wglCreateContextAttribsARB");
|
|
}
|
|
else if (w32_are_strings_equal("WGL_EXT_swap_control", start, length)) {
|
|
// https://www.khronos.org/registry/OpenGL/extensions/EXT/WGL_EXT_swap_control.txt
|
|
wglSwapIntervalEXT = (MU_wglSwapIntervalEXT *)gl_get_proc_address("wglSwapIntervalEXT");
|
|
}
|
|
|
|
if (*ext == 0) {
|
|
break;
|
|
}
|
|
|
|
ext++;
|
|
start = ext;
|
|
}
|
|
|
|
if (!wglChoosePixelFormatARB || !wglCreateContextAttribsARB || !wglSwapIntervalEXT) {
|
|
assert(!"OpenGL does not support required WGL extensions for modern context!");
|
|
}
|
|
|
|
BOOL ok_b = mu_wglMakeCurrent(NULL, NULL);
|
|
assert(ok_b);
|
|
|
|
ok_b = mu_wglDeleteContext(rc);
|
|
assert(ok_b);
|
|
|
|
ok = ReleaseDC(dummy, dc);
|
|
assert(ok);
|
|
|
|
ok_b = DestroyWindow(dummy);
|
|
assert(ok_b);
|
|
|
|
return true;
|
|
}
|
|
|
|
fn b32 w32_create_opengl_context(HDC window_handle_dc, i32 opengl_major, i32 opengl_minor) {
|
|
// set pixel format for OpenGL context
|
|
int attrib[] =
|
|
{
|
|
WGL_DRAW_TO_WINDOW_ARB,
|
|
true,
|
|
WGL_SUPPORT_OPENGL_ARB,
|
|
true,
|
|
WGL_DOUBLE_BUFFER_ARB,
|
|
true,
|
|
WGL_PIXEL_TYPE_ARB,
|
|
WGL_TYPE_RGBA_ARB,
|
|
WGL_COLOR_BITS_ARB,
|
|
32,
|
|
WGL_DEPTH_BITS_ARB,
|
|
24,
|
|
WGL_STENCIL_BITS_ARB,
|
|
8,
|
|
|
|
// uncomment for sRGB framebuffer, from WGL_ARB_framebuffer_sRGB extension
|
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_framebuffer_sRGB.txt
|
|
// WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE,
|
|
|
|
// uncomment for multisampeld framebuffer, from WGL_ARB_multisample extension
|
|
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_multisample.txt
|
|
#if W32_ENABLE_MULTISAMPLING
|
|
WGL_SAMPLE_BUFFERS_ARB,
|
|
1,
|
|
WGL_SAMPLES_ARB,
|
|
4, // 4x MSAA
|
|
#endif
|
|
|
|
0,
|
|
};
|
|
|
|
int format;
|
|
UINT formats;
|
|
if (!wglChoosePixelFormatARB(window_handle_dc, attrib, 0, 1, &format, &formats) || formats == 0) {
|
|
assert(!"OpenGL does not support required pixel format!");
|
|
}
|
|
|
|
PIXELFORMATDESCRIPTOR desc = {0};
|
|
desc.nSize = sizeof(desc);
|
|
int ok = DescribePixelFormat(window_handle_dc, format, sizeof(desc), &desc);
|
|
assert(ok && "Failed to describe OpenGL pixel format");
|
|
|
|
if (!SetPixelFormat(window_handle_dc, format, &desc)) {
|
|
assert(!"Cannot set OpenGL selected pixel format!");
|
|
}
|
|
|
|
// create modern OpenGL context
|
|
{
|
|
int attrib[] =
|
|
{
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB,
|
|
opengl_major,
|
|
WGL_CONTEXT_MINOR_VERSION_ARB,
|
|
opengl_minor,
|
|
WGL_CONTEXT_PROFILE_MASK_ARB,
|
|
WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
|
|
#if W32_OPENGL_DEBUG
|
|
WGL_CONTEXT_FLAGS_ARB,
|
|
WGL_CONTEXT_DEBUG_BIT_ARB,
|
|
#endif
|
|
|
|
0,
|
|
};
|
|
|
|
HGLRC rc = wglCreateContextAttribsARB(window_handle_dc, 0, attrib);
|
|
assert(rc && "Cannot create modern OpenGL context! OpenGL version not supported?");
|
|
|
|
BOOL ok = mu_wglMakeCurrent(window_handle_dc, rc);
|
|
assert(ok && "Failed to make current OpenGL context");
|
|
}
|
|
|
|
return true;
|
|
} |