detached cca2b3e

feat(cef): add OpenGL function loader via purego

commit
cca2b3edd39163446bc8ce8e5682242eb486ff62
author
brice · · 2026-03-19 15:22 UTC
committer
brice · · 2026-03-28 04:35 UTC
parent
4f9ffc5
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +157 -0
A internal/infrastructure/cef/gl_loader.go +157 -0
@@ -0,0 +1,157 @@
1+package cef
2+
3+import (
4+ "fmt"
5+ "unsafe"
6+
7+ "github.com/jwijenbergh/purego"
8+)
9+
10+// OpenGL constants for PBO-based texture rendering.
11+const (
12+ glTexture2D = 0x0DE1
13+ glBGRA = 0x80E1
14+ glRGBA = 0x1908
15+ glUnsignedByte = 0x1401
16+
17+ glPixelUnpackBuffer = 0x88EC
18+ glStreamDraw = 0x88E0
19+ glWriteOnly = 0x88B9
20+
21+ glColorBufferBit = 0x00004000
22+ glTriangleStrip = 0x0005
23+
24+ glFragmentShader = 0x8B30
25+ glVertexShader = 0x8B31
26+ glFloat = 0x1406
27+
28+ glArrayBuffer = 0x8892
29+ glStaticDraw = 0x88E4
30+
31+ glLinear = 0x2601
32+ glTextureMinFilter = 0x2801
33+ glTextureMagFilter = 0x2800
34+ glClampToEdge = 0x812F
35+ glTextureWrapS = 0x2802
36+ glTextureWrapT = 0x2803
37+)
38+
39+// glLoader holds dynamically loaded OpenGL function pointers.
40+// All functions are loaded from libGL.so.1 via purego at runtime (no CGo).
41+type glLoader struct {
42+ handle uintptr
43+
44+ // Texture functions
45+ genTextures func(n int32, textures *uint32)
46+ deleteTextures func(n int32, textures *uint32)
47+ bindTexture func(target uint32, texture uint32)
48+ texImage2D func(target uint32, level int32, internalformat int32, width int32, height int32, border int32, format uint32, xtype uint32, pixels unsafe.Pointer)
49+ texSubImage2D func(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels unsafe.Pointer)
50+ texParameteri func(target uint32, pname uint32, param int32)
51+
52+ // PBO / buffer functions
53+ genBuffers func(n int32, buffers *uint32)
54+ deleteBuffers func(n int32, buffers *uint32)
55+ bindBuffer func(target uint32, buffer uint32)
56+ bufferData func(target uint32, size int64, data unsafe.Pointer, usage uint32)
57+ mapBuffer func(target uint32, access uint32) unsafe.Pointer
58+ unmapBuffer func(target uint32) bool
59+
60+ // Shader functions
61+ createShader func(shaderType uint32) uint32
62+ shaderSource func(shader uint32, count int32, source **byte, length *int32)
63+ compileShader func(shader uint32)
64+ deleteShader func(shader uint32)
65+ createProgram func() uint32
66+ attachShader func(program uint32, shader uint32)
67+ linkProgram func(program uint32)
68+ useProgram func(program uint32)
69+ getUniformLocation func(program uint32, name *byte) int32
70+ uniform1i func(location int32, v0 int32)
71+
72+ // VAO / VBO functions
73+ genVertexArrays func(n int32, arrays *uint32)
74+ bindVertexArray func(array uint32)
75+ deleteVertexArrays func(n int32, arrays *uint32)
76+ vertexAttribPointer func(index uint32, size int32, xtype uint32, normalized bool, stride int32, pointer uintptr)
77+ enableVertexAttribArray func(index uint32)
78+
79+ // Draw / state functions
80+ clear func(mask uint32)
81+ clearColor func(red float32, green float32, blue float32, alpha float32)
82+ viewport func(x int32, y int32, width int32, height int32)
83+ drawArrays func(mode uint32, first int32, count int32)
84+ enable func(cap uint32)
85+ disable func(cap uint32)
86+}
87+
88+// newGLLoader opens libGL.so.1 and loads all required OpenGL function pointers.
89+func newGLLoader() (*glLoader, error) {
90+ handle, err := purego.Dlopen("libGL.so.1", purego.RTLD_LAZY)
91+ if err != nil {
92+ return nil, fmt.Errorf("failed to open libGL.so.1: %w", err)
93+ }
94+
95+ gl := &glLoader{handle: handle}
96+
97+ if err := gl.registerAll(); err != nil {
98+ return nil, fmt.Errorf("failed to register GL functions: %w", err)
99+ }
100+
101+ return gl, nil
102+}
103+
104+// registerAll loads every GL function pointer from the shared library.
105+// It wraps RegisterLibFunc panics into errors for graceful handling.
106+func (gl *glLoader) registerAll() (retErr error) {
107+ defer func() {
108+ if r := recover(); r != nil {
109+ retErr = fmt.Errorf("GL symbol lookup failed: %v", r)
110+ }
111+ }()
112+
113+ // Texture
114+ purego.RegisterLibFunc(&gl.genTextures, gl.handle, "glGenTextures")
115+ purego.RegisterLibFunc(&gl.deleteTextures, gl.handle, "glDeleteTextures")
116+ purego.RegisterLibFunc(&gl.bindTexture, gl.handle, "glBindTexture")
117+ purego.RegisterLibFunc(&gl.texImage2D, gl.handle, "glTexImage2D")
118+ purego.RegisterLibFunc(&gl.texSubImage2D, gl.handle, "glTexSubImage2D")
119+ purego.RegisterLibFunc(&gl.texParameteri, gl.handle, "glTexParameteri")
120+
121+ // PBO / buffers
122+ purego.RegisterLibFunc(&gl.genBuffers, gl.handle, "glGenBuffers")
123+ purego.RegisterLibFunc(&gl.deleteBuffers, gl.handle, "glDeleteBuffers")
124+ purego.RegisterLibFunc(&gl.bindBuffer, gl.handle, "glBindBuffer")
125+ purego.RegisterLibFunc(&gl.bufferData, gl.handle, "glBufferData")
126+ purego.RegisterLibFunc(&gl.mapBuffer, gl.handle, "glMapBuffer")
127+ purego.RegisterLibFunc(&gl.unmapBuffer, gl.handle, "glUnmapBuffer")
128+
129+ // Shaders
130+ purego.RegisterLibFunc(&gl.createShader, gl.handle, "glCreateShader")
131+ purego.RegisterLibFunc(&gl.shaderSource, gl.handle, "glShaderSource")
132+ purego.RegisterLibFunc(&gl.compileShader, gl.handle, "glCompileShader")
133+ purego.RegisterLibFunc(&gl.deleteShader, gl.handle, "glDeleteShader")
134+ purego.RegisterLibFunc(&gl.createProgram, gl.handle, "glCreateProgram")
135+ purego.RegisterLibFunc(&gl.attachShader, gl.handle, "glAttachShader")
136+ purego.RegisterLibFunc(&gl.linkProgram, gl.handle, "glLinkProgram")
137+ purego.RegisterLibFunc(&gl.useProgram, gl.handle, "glUseProgram")
138+ purego.RegisterLibFunc(&gl.getUniformLocation, gl.handle, "glGetUniformLocation")
139+ purego.RegisterLibFunc(&gl.uniform1i, gl.handle, "glUniform1i")
140+
141+ // VAO / VBO
142+ purego.RegisterLibFunc(&gl.genVertexArrays, gl.handle, "glGenVertexArrays")
143+ purego.RegisterLibFunc(&gl.bindVertexArray, gl.handle, "glBindVertexArray")
144+ purego.RegisterLibFunc(&gl.deleteVertexArrays, gl.handle, "glDeleteVertexArrays")
145+ purego.RegisterLibFunc(&gl.vertexAttribPointer, gl.handle, "glVertexAttribPointer")
146+ purego.RegisterLibFunc(&gl.enableVertexAttribArray, gl.handle, "glEnableVertexAttribArray")
147+
148+ // Draw / state
149+ purego.RegisterLibFunc(&gl.clear, gl.handle, "glClear")
150+ purego.RegisterLibFunc(&gl.clearColor, gl.handle, "glClearColor")
151+ purego.RegisterLibFunc(&gl.viewport, gl.handle, "glViewport")
152+ purego.RegisterLibFunc(&gl.drawArrays, gl.handle, "glDrawArrays")
153+ purego.RegisterLibFunc(&gl.enable, gl.handle, "glEnable")
154+ purego.RegisterLibFunc(&gl.disable, gl.handle, "glDisable")
155+
156+ return nil
157+}
@@ -0,0 +1,157 @@
1+package cef
2+
3+import (
4+ "fmt"
5+ "unsafe"
6+
7+ "github.com/jwijenbergh/purego"
8+)
9+
10+// OpenGL constants for PBO-based texture rendering.
11+const (
12+ glTexture2D = 0x0DE1
13+ glBGRA = 0x80E1
14+ glRGBA = 0x1908
15+ glUnsignedByte = 0x1401
16+
17+ glPixelUnpackBuffer = 0x88EC
18+ glStreamDraw = 0x88E0
19+ glWriteOnly = 0x88B9
20+
21+ glColorBufferBit = 0x00004000
22+ glTriangleStrip = 0x0005
23+
24+ glFragmentShader = 0x8B30
25+ glVertexShader = 0x8B31
26+ glFloat = 0x1406
27+
28+ glArrayBuffer = 0x8892
29+ glStaticDraw = 0x88E4
30+
31+ glLinear = 0x2601
32+ glTextureMinFilter = 0x2801
33+ glTextureMagFilter = 0x2800
34+ glClampToEdge = 0x812F
35+ glTextureWrapS = 0x2802
36+ glTextureWrapT = 0x2803
37+)
38+
39+// glLoader holds dynamically loaded OpenGL function pointers.
40+// All functions are loaded from libGL.so.1 via purego at runtime (no CGo).
41+type glLoader struct {
42+ handle uintptr
43+
44+ // Texture functions
45+ genTextures func(n int32, textures *uint32)
46+ deleteTextures func(n int32, textures *uint32)
47+ bindTexture func(target uint32, texture uint32)
48+ texImage2D func(target uint32, level int32, internalformat int32, width int32, height int32, border int32, format uint32, xtype uint32, pixels unsafe.Pointer)
49+ texSubImage2D func(target uint32, level int32, xoffset int32, yoffset int32, width int32, height int32, format uint32, xtype uint32, pixels unsafe.Pointer)
50+ texParameteri func(target uint32, pname uint32, param int32)
51+
52+ // PBO / buffer functions
53+ genBuffers func(n int32, buffers *uint32)
54+ deleteBuffers func(n int32, buffers *uint32)
55+ bindBuffer func(target uint32, buffer uint32)
56+ bufferData func(target uint32, size int64, data unsafe.Pointer, usage uint32)
57+ mapBuffer func(target uint32, access uint32) unsafe.Pointer
58+ unmapBuffer func(target uint32) bool
59+
60+ // Shader functions
61+ createShader func(shaderType uint32) uint32
62+ shaderSource func(shader uint32, count int32, source **byte, length *int32)
63+ compileShader func(shader uint32)
64+ deleteShader func(shader uint32)
65+ createProgram func() uint32
66+ attachShader func(program uint32, shader uint32)
67+ linkProgram func(program uint32)
68+ useProgram func(program uint32)
69+ getUniformLocation func(program uint32, name *byte) int32
70+ uniform1i func(location int32, v0 int32)
71+
72+ // VAO / VBO functions
73+ genVertexArrays func(n int32, arrays *uint32)
74+ bindVertexArray func(array uint32)
75+ deleteVertexArrays func(n int32, arrays *uint32)
76+ vertexAttribPointer func(index uint32, size int32, xtype uint32, normalized bool, stride int32, pointer uintptr)
77+ enableVertexAttribArray func(index uint32)
78+
79+ // Draw / state functions
80+ clear func(mask uint32)
81+ clearColor func(red float32, green float32, blue float32, alpha float32)
82+ viewport func(x int32, y int32, width int32, height int32)
83+ drawArrays func(mode uint32, first int32, count int32)
84+ enable func(cap uint32)
85+ disable func(cap uint32)
86+}
87+
88+// newGLLoader opens libGL.so.1 and loads all required OpenGL function pointers.
89+func newGLLoader() (*glLoader, error) {
90+ handle, err := purego.Dlopen("libGL.so.1", purego.RTLD_LAZY)
91+ if err != nil {
92+ return nil, fmt.Errorf("failed to open libGL.so.1: %w", err)
93+ }
94+
95+ gl := &glLoader{handle: handle}
96+
97+ if err := gl.registerAll(); err != nil {
98+ return nil, fmt.Errorf("failed to register GL functions: %w", err)
99+ }
100+
101+ return gl, nil
102+}
103+
104+// registerAll loads every GL function pointer from the shared library.
105+// It wraps RegisterLibFunc panics into errors for graceful handling.
106+func (gl *glLoader) registerAll() (retErr error) {
107+ defer func() {
108+ if r := recover(); r != nil {
109+ retErr = fmt.Errorf("GL symbol lookup failed: %v", r)
110+ }
111+ }()
112+
113+ // Texture
114+ purego.RegisterLibFunc(&gl.genTextures, gl.handle, "glGenTextures")
115+ purego.RegisterLibFunc(&gl.deleteTextures, gl.handle, "glDeleteTextures")
116+ purego.RegisterLibFunc(&gl.bindTexture, gl.handle, "glBindTexture")
117+ purego.RegisterLibFunc(&gl.texImage2D, gl.handle, "glTexImage2D")
118+ purego.RegisterLibFunc(&gl.texSubImage2D, gl.handle, "glTexSubImage2D")
119+ purego.RegisterLibFunc(&gl.texParameteri, gl.handle, "glTexParameteri")
120+
121+ // PBO / buffers
122+ purego.RegisterLibFunc(&gl.genBuffers, gl.handle, "glGenBuffers")
123+ purego.RegisterLibFunc(&gl.deleteBuffers, gl.handle, "glDeleteBuffers")
124+ purego.RegisterLibFunc(&gl.bindBuffer, gl.handle, "glBindBuffer")
125+ purego.RegisterLibFunc(&gl.bufferData, gl.handle, "glBufferData")
126+ purego.RegisterLibFunc(&gl.mapBuffer, gl.handle, "glMapBuffer")
127+ purego.RegisterLibFunc(&gl.unmapBuffer, gl.handle, "glUnmapBuffer")
128+
129+ // Shaders
130+ purego.RegisterLibFunc(&gl.createShader, gl.handle, "glCreateShader")
131+ purego.RegisterLibFunc(&gl.shaderSource, gl.handle, "glShaderSource")
132+ purego.RegisterLibFunc(&gl.compileShader, gl.handle, "glCompileShader")
133+ purego.RegisterLibFunc(&gl.deleteShader, gl.handle, "glDeleteShader")
134+ purego.RegisterLibFunc(&gl.createProgram, gl.handle, "glCreateProgram")
135+ purego.RegisterLibFunc(&gl.attachShader, gl.handle, "glAttachShader")
136+ purego.RegisterLibFunc(&gl.linkProgram, gl.handle, "glLinkProgram")
137+ purego.RegisterLibFunc(&gl.useProgram, gl.handle, "glUseProgram")
138+ purego.RegisterLibFunc(&gl.getUniformLocation, gl.handle, "glGetUniformLocation")
139+ purego.RegisterLibFunc(&gl.uniform1i, gl.handle, "glUniform1i")
140+
141+ // VAO / VBO
142+ purego.RegisterLibFunc(&gl.genVertexArrays, gl.handle, "glGenVertexArrays")
143+ purego.RegisterLibFunc(&gl.bindVertexArray, gl.handle, "glBindVertexArray")
144+ purego.RegisterLibFunc(&gl.deleteVertexArrays, gl.handle, "glDeleteVertexArrays")
145+ purego.RegisterLibFunc(&gl.vertexAttribPointer, gl.handle, "glVertexAttribPointer")
146+ purego.RegisterLibFunc(&gl.enableVertexAttribArray, gl.handle, "glEnableVertexAttribArray")
147+
148+ // Draw / state
149+ purego.RegisterLibFunc(&gl.clear, gl.handle, "glClear")
150+ purego.RegisterLibFunc(&gl.clearColor, gl.handle, "glClearColor")
151+ purego.RegisterLibFunc(&gl.viewport, gl.handle, "glViewport")
152+ purego.RegisterLibFunc(&gl.drawArrays, gl.handle, "glDrawArrays")
153+ purego.RegisterLibFunc(&gl.enable, gl.handle, "glEnable")
154+ purego.RegisterLibFunc(&gl.disable, gl.handle, "glDisable")
155+
156+ return nil
157+}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close