Harbor

branch main
showing the latest snapshot on main
gl_context_windows.odin 3.3 KB · Plain text
gpu/backend/opengl/gl_context_windows.odin 0644 Raw
#+build windows
package opengl_backend

import "core:log"
import win32 "core:sys/windows"
import gl "vendor:OpenGL"

import bk ".."

GL_Context :: struct {
	hwnd:   win32.HWND,
	hdc:    win32.HDC,
	gl_ctx: win32.HGLRC,
	width:  u32,
	height: u32,
}

create_gl_context :: proc(
	surface: bk.Surface_Desc,
	width, height: u32,
	title: cstring,
) -> (
	GL_Context,
	bool,
) {
	if surface.kind != .Win32 || surface.win32.hwnd == nil {
		log.error("gpu/opengl: Windows OpenGL backend requires Win32 surface")
		return {}, false
	}

	hwnd := win32.HWND(surface.win32.hwnd)
	hdc := win32.GetDC(hwnd)
	if hdc == nil {
		log.error("gpu/opengl: GetDC failed")
		return {}, false
	}

	pfd := win32.PIXELFORMATDESCRIPTOR {
		nSize        = size_of(win32.PIXELFORMATDESCRIPTOR),
		nVersion     = 1,
		dwFlags      = win32.PFD_DRAW_TO_WINDOW | win32.PFD_SUPPORT_OPENGL | win32.PFD_DOUBLEBUFFER,
		iPixelType   = win32.PFD_TYPE_RGBA,
		cColorBits   = 32,
		cDepthBits   = 24,
		cStencilBits = 8,
		iLayerType   = win32.PFD_MAIN_PLANE,
	}
	pixel_format := win32.ChoosePixelFormat(hdc, &pfd)
	if pixel_format == 0 || !win32.SetPixelFormat(hdc, pixel_format, &pfd) {
		log.error("gpu/opengl: failed to set Win32 pixel format")
		win32.ReleaseDC(hwnd, hdc)
		return {}, false
	}

	dummy := win32.wglCreateContext(hdc)
	if dummy == nil || !win32.wglMakeCurrent(hdc, dummy) {
		log.error("gpu/opengl: failed to create WGL bootstrap context")
		if dummy != nil do win32.wglDeleteContext(dummy)
		win32.ReleaseDC(hwnd, hdc)
		return {}, false
	}

	gl.load_up_to(4, 5, win32.gl_set_proc_address)
	win32.wglCreateContextAttribsARB = auto_cast win32.wglGetProcAddress(
		"wglCreateContextAttribsARB",
	)
	if win32.wglCreateContextAttribsARB == nil {
		log.error("gpu/opengl: WGL_ARB_create_context unavailable")
		win32.wglMakeCurrent(nil, nil)
		win32.wglDeleteContext(dummy)
		win32.ReleaseDC(hwnd, hdc)
		return {}, false
	}

	attribs := [?]c_int {
		win32.CONTEXT_MAJOR_VERSION_ARB,
		4,
		win32.CONTEXT_MINOR_VERSION_ARB,
		5,
		win32.CONTEXT_PROFILE_MASK_ARB,
		win32.CONTEXT_CORE_PROFILE_BIT_ARB,
		0,
	}
	gl_ctx := win32.wglCreateContextAttribsARB(hdc, nil, &attribs[0])
	win32.wglMakeCurrent(nil, nil)
	win32.wglDeleteContext(dummy)
	if gl_ctx == nil || !win32.wglMakeCurrent(hdc, gl_ctx) {
		log.error("gpu/opengl: failed to create WGL 4.5 core context")
		if gl_ctx != nil do win32.wglDeleteContext(gl_ctx)
		win32.ReleaseDC(hwnd, hdc)
		return {}, false
	}

	gl.load_up_to(4, 5, win32.gl_set_proc_address)
	return {hwnd = hwnd, hdc = hdc, gl_ctx = gl_ctx, width = width, height = height}, true
}

destroy_gl_context :: proc(ctx: ^GL_Context) {
	if ctx == nil || ctx.hdc == nil do return
	win32.wglMakeCurrent(nil, nil)
	if ctx.gl_ctx != nil do win32.wglDeleteContext(ctx.gl_ctx)
	if ctx.hwnd != nil do win32.ReleaseDC(ctx.hwnd, ctx.hdc)
	ctx^ = {}
}

make_gl_context_current :: proc(ctx: ^GL_Context) -> bool {
	if ctx == nil || ctx.hdc == nil || ctx.gl_ctx == nil do return false
	return win32.wglMakeCurrent(ctx.hdc, ctx.gl_ctx)
}

swap_gl_context :: proc(ctx: ^GL_Context) -> bool {
	if ctx == nil || ctx.hdc == nil do return false
	return win32.SwapBuffers(ctx.hdc)
}

resize_gl_context :: proc(ctx: ^GL_Context, width, height: u32) {
	if ctx == nil do return
	ctx.width = width
	ctx.height = height
}

gl_context_set_proc_address :: proc(p: rawptr, name: cstring) {
	win32.gl_set_proc_address(p, name)
}