1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#+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)
}