win32_app

This commit is contained in:
krzosa
2025-01-03 07:53:13 +01:00
parent 05d49eefe8
commit 6933566a86
17 changed files with 832 additions and 200 deletions

270
src/app/app_win32_opengl.c Normal file
View File

@@ -0,0 +1,270 @@
// 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
global MU_wglChoosePixelFormatARB *wglChoosePixelFormatARB;
global MU_wglCreateContextAttribsARB *wglCreateContextAttribsARB;
global MU_wglSwapIntervalEXT *wglSwapIntervalEXT;
global MU_glGetProcAddress *wgl_get_proc_address;
global void *(*gl_get_proc_address)(const char *str);
global HMODULE opengl_hmodule;
global HGLRC(*mu_wglCreateContext)(HDC unnamedParam1);
global BOOL(*mu_wglMakeCurrent)(HDC unnamedParam1, HGLRC unnamedParam2);
global 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;
}