set up opengl for x11/wasm

This commit is contained in:
Matthew 2026-05-17 15:13:14 +10:00
parent d679e978b1
commit edaacc9665
9 changed files with 3242 additions and 76 deletions

View File

@ -11,8 +11,6 @@
# include <X11/Xatom.h> # include <X11/Xatom.h>
# include <X11/Xutil.h> # include <X11/Xutil.h>
# include <GL/glx.h>
# include <GL/glxext.h>
// # include <ft2build.h> // # include <ft2build.h>
// # include FT_FREETYPE_H // # include FT_FREETYPE_H
// # include FT_GLYPH_H // # include FT_GLYPH_H
@ -31,15 +29,17 @@
#endif #endif
#ifdef BUILD_VULKAN #ifdef BUILD_VULKAN
# define VK_NO_PROTOTYPES # define VK_NO_PROTOTYPES
# include <vulkan/vulkan.h> # include <vulkan/vulkan.h>
# define VMA_STATIC_VULKAN_FUNCTIONS 0 # define VMA_STATIC_VULKAN_FUNCTIONS 0
# define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 # define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
# define VMA_VULKAN_VERSION 1002000 # define VMA_VULKAN_VERSION 1002000
# include "../external/vma/vk_mem_alloc.h" # include "../external/vma/vk_mem_alloc.h"
#endif
#ifdef BUILD_GL
# include <GL/gl.h>
# include <GL/glext.h>
# include <GL/glx.h>
# include <GL/glxext.h>
#endif #endif

View File

@ -404,7 +404,6 @@ import core.sys.posix.pthread : PThread = pthread_t,
import core.stdc.string : strlen; import core.stdc.string : strlen;
const u32 X11_CB_TRANSFER_SIZE_DEFAULT = 1048576; const u32 X11_CB_TRANSFER_SIZE_DEFAULT = 1048576;
const u32 X11_TIMEOUT_DEFAULT = 1500; const u32 X11_TIMEOUT_DEFAULT = 1500;
@ -635,8 +634,15 @@ WindowError()
return WINDOW_ERR_MSG; return WINDOW_ERR_MSG;
} }
enum i32 GL_CORE_PROFILE = 0x00000001;
bool bool
CreateWindow(PlatformWindow* window, string name, u32 width, u32 height, XVisualInfo* visual_info = null) CreateWindow(
bool create_gl_context = false,
i32 gl_major_version = 4,
i32 gl_minor_version = 6,
i32 gl_profile = GL_CORE_PROFILE
)(PlatformWindow* window, string name, u32 width, u32 height)
{ {
PlatformWindow wnd = { PlatformWindow wnd = {
w: width, w: width,
@ -671,18 +677,58 @@ CreateWindow(PlatformWindow* window, string name, u32 width, u32 height, XVisual
window.screen_id = XDefaultScreen(window.display); window.screen_id = XDefaultScreen(window.display);
i64 value_mask = CWBackPixmap | CWBackPixel; const i64 value_mask = CWBackPixmap | CWBackPixel;
const i64 event_mask = KeyPressMask |
KeyReleaseMask |
ExposureMask |
ButtonPressMask |
ButtonReleaseMask |
PointerMotionMask |
StructureNotifyMask |
PropertyChangeMask;
if(visual_info) static if(create_gl_context)
{ {
XSetWindowAttributes attrs = { import opengl;
background_pixmap: None, const i32[] visual_attributes = [
border_pixel: 0, GLX_X_RENDERABLE, true,
event_mask: StructureNotifyMask, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
}; GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_STENCIL_SIZE, 8,
GLX_DOUBLEBUFFER, true,
None,
];
value_mask |= CWColormap; i32 fb_count;
auto copy = CopyFromParent; GLXFBConfig* fb_config = glXChooseFBConfig(window.display, window.screen_id, visual_attributes.ptr, &fb_count);
if(fb_config == null || fb_count == 0)
{
Errf("Failed to retrieve GL framebuffer config");
return false;
}
GLXFBConfig chosen_fb_config = fb_config[0];
XFree(fb_config);
XVisualInfo* visual_info = glXGetVisualFromFBConfig(window.display, chosen_fb_config);
if(visual_info == null)
{
Errf("Failed to get GL visual");
return false;
}
XSetWindowAttributes set_window_attrs = {
colormap: XCreateColormap(window.display, RootWindow(window.display, visual_info.screen), visual_info.visual, AllocNone),
border_pixel: 0,
event_mask: event_mask,
};
window.window = XCreateWindow( window.window = XCreateWindow(
window.display, window.display,
@ -695,8 +741,8 @@ CreateWindow(PlatformWindow* window, string name, u32 width, u32 height, XVisual
visual_info.depth, visual_info.depth,
InputOutput, InputOutput,
visual_info.visual, visual_info.visual,
value_mask, value_mask | CWColormap,
&attrs &set_window_attrs
); );
XFree(visual_info); XFree(visual_info);
@ -721,15 +767,6 @@ CreateWindow(PlatformWindow* window, string name, u32 width, u32 height, XVisual
WINDOW_ERR_MSG = "Failed to create X11 window"; WINDOW_ERR_MSG = "Failed to create X11 window";
return false; return false;
} }
i64 event_mask = KeyPressMask |
KeyReleaseMask |
ExposureMask |
ButtonPressMask |
ButtonReleaseMask |
PointerMotionMask |
StructureNotifyMask |
PropertyChangeMask;
XSelectInput(window.display, window.window, event_mask); XSelectInput(window.display, window.window, event_mask);
@ -774,8 +811,41 @@ CreateWindow(PlatformWindow* window, string name, u32 width, u32 height, XVisual
XFlush(window.display); XFlush(window.display);
static if(create_gl_context)
{
import opengl;
glXCreateContextAttribsARB = cast(typeof(glXCreateContextAttribsARB))glXGetProcAddressARB(cast(u8*)r"glXCreateContexAttribsARB");
if(!glXCreateContextAttribsARB)
{
Errf("glXCreateContextAttribsARB function not found");
return false;
}
enum GLX_CONTEXT_MAJOR_VERSION = 0x2091;
enum GLX_CONTEXT_MINOR_VERSION = 0x2092;
enum GLX_CONTEXT_PROFILE_MASK_ARB = 0x9126;
const(i32[]) context_attributes = [
GLX_CONTEXT_MAJOR_VERSION, gl_major_version,
GLX_CONTEXT_MINOR_VERSION, gl_minor_version,
GLX_CONTEXT_PROFILE_MASK_ARB, gl_profile,
None,
];
GLXContext context = glXCreateContextAttribsARB(window.display, chosen_fb_config, null, True, context_attributes.ptr);
if(!context)
{
Errf("Failed to create OpenGL context");
return false;
}
glXMakeCurrent(window.display, window.window, context);
}
return true; return true;
}; }
void void
StartPlatformThread(PlatformWindow* window) StartPlatformThread(PlatformWindow* window)
@ -1813,6 +1883,11 @@ version(DLIB_TEST) unittest
assert(events[2].type == WET.FileDeleted); assert(events[2].type == WET.FileDeleted);
assert(events[2].names[0] == r"test_file.txt"); assert(events[2].names[0] == r"test_file.txt");
version(COMPILE_TEST)
{
CreateWindow!(true)(null, "GL", 1920, 1080);
}
} }
} }

1253
opengl/glenum.d Normal file

File diff suppressed because it is too large Load Diff

81
opengl/opengl.d Normal file
View File

@ -0,0 +1,81 @@
import dlib.aliases;
import dlib.util;
import dlib.alloc;
static if(NativeTarget)
{
import dlibincludes;
public import opengl_native;
}
else
{
public import opengl_wasm;
}
public import glenum;
u32
GLCreateShader(GLEnum shader_type, string[] shader_src)
{
i32[32] src_lengths;
immutable(char)*[32] src_ptrs;
for(usize i = 0; i < shader_src.length; i += 1)
{
src_ptrs[i] = shader_src[i].ptr;
src_lengths[i] = cast(i32)shader_src[i].length;
}
u32 shader = glCreateShader(shader_type);
glShaderSource(shader, cast(u32)shader_src.length, src_ptrs.ptr, src_lengths.ptr);
i32 success;
glGetShaderiv(shader, GLE.COMPILE_STATUS, &success);
if(!success)
{
char[512] info_log;
i32 log_length;
glGetShaderInfoLog(shader, cast(u32)info_log.length, &log_length, info_log.ptr);
Errf("Error compiling shader: %s", Str(info_log[0 .. log_length]));
shader = 0;
}
return shader;
}
u32
GLCreateProgramFromSources(string[] vertex_src, string[] fragment_src)
{
u32 program;
u32 vertex_shader = GLCreateShader(GLE.VERTEX_SHADER, vertex_src);
u32 fragment_shader = GLCreateShader(GLE.FRAGMENT_SHADER, fragment_src);
if(vertex_shader && fragment_shader)
{
program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
i32 success;
glGetProgramiv(program, GLE.LINK_STATUS, &success);
if(!success)
{
char[512] info_log;
i32 log_length;
glGetProgramInfoLog(program, cast(u32)info_log.length, &log_length, info_log.ptr);
Errf("Error compiling program: %s", Str(info_log[0 .. log_length]));
program = 0;
}
}
if(!program)
{
Errf("Failed to create program!");
}
return program;
}

50
opengl/opengl_native.d Normal file
View File

@ -0,0 +1,50 @@
import dlibincludes;
// TODO: fix on js side
alias PFNGLXCREATECONTEXTATTRIBSARBPROC = extern(C) GLXContext function(Display*, GLXFBConfig, GLXContext, int, const int*);
PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB;
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLGENBUFFERSPROC glGenBuffers;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
PFNGLBINDBUFFERBASEPROC glBindBufferBase;
PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLBUFFERSUBDATAPROC glBufferSubData;
PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced;
PFNGLDRAWELEMENTSINSTANCEDPROC glDrawElementsInstanced;
PFNGLACTIVETEXTUREPROC glActiveTexture;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLUNIFORM1FPROC glUniform1f;
PFNGLUNIFORM2FPROC glUniform2f;
PFNGLUNIFORM3FPROC glUniform3f;
PFNGLUNIFORM4FPROC glUniform4f;
PFNGLUNIFORM1IPROC glUniform1i;
PFNGLUNIFORM2IPROC glUniform2i;
PFNGLUNIFORM3IPROC glUniform3i;
PFNGLUNIFORM4IPROC glUniform4i;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLLINKPROGRAMPROC glLinkProgram;

216
opengl/opengl_wasm.d Normal file
View File

@ -0,0 +1,216 @@
import ldc.attributes;
import dlib.aliases;
import glenum;
version(WebAssembly):
enum WebGLAttributes
{
None = 0<<0,
NoAlpha = 1<<0,
NoAntiAliasing = 1<<1,
NoDepth = 1<<2,
FailIfMajorPerformanceCaveat = 1<<3,
NoPremultipliedAlpha = 1<<4,
PreserveDrawingBuffer = 1<<5,
Stencil = 1<<6,
Desynchronized = 1<<7,
} alias WGLA = WebGLAttributes;
import wasm;
extern(C) @llvmAttr("wasm-import-module", "gl"):
@WasmName!("GenRenderbuffers") void
glGenRenderbuffers(usize n, u32* renderbuffers);
@WasmName!("DeleteBuffers") void
glDeleteBuffers(usize n, const u32* buffers);
@WasmName!("DeleteFramebuffers") void
glDeleteFramebuffers(usize n, const u32* framebuffers);
@WasmName!("GenBuffers") u32
glGenBuffers(usize n, u32* buffers);
@WasmName!("DeleteRenderbuffers") void
glDeleteRenderbuffers(usize n, const u32* renderbuffers);
@WasmName!("GenTextures") u32
glCreateTextures(usize n, u32* textures);
@WasmName!("GenVertexArrays") void
glGenVertexArrays(usize n, u32* vaos);
@WasmName!("DeleteVertexArrays") void
glDeleteVertexArrays(usize n, const u32* vaos);
@WasmName!("DeleteTextures") void
glDeleteTextures(usize n, const u32* textures);
@WasmName!("SetCurrentContextById") b32
glSetCurrentContextByID(string id);
@WasmName!("CreateCurrentContextById") b32
glCreateCurrentContextByID(string id, WebGLAttributes);
@WasmName!("Clear") void
glClear(u32 bits);
@WasmName!("ClearColor") void
glClearColor(f32 red, f32 green, f32 blue, f32 alpha);
@WasmName!("ClearDepth") void
glClearDepth(f32 depth);
@WasmName!("ClearStencil") void
glClearStencil(i32 s);
@WasmName!("ColorMask") void
glColorMask(u32 red, u32 green, u32 blue, u32 alpha);
@WasmName!("CompileShader") void
glCompileShader(u32 shader);
@WasmName!("UseProgram") void
glUseProgram(u32 program);
@WasmName!("ValidateProgram") void
glValidateProgram(u32 program);
@WasmName!("BindBufferBase") void
glBindBufferBase(GLEnum target, u32 index, u32 buffer);
@WasmName!("GetUniformBlockIndex") u32
glGetUniformBlockIndex(u32 program, const char* uniform_block_name);
@WasmName!("CullFace") void
glCullFace(GLEnum mode);
@WasmName!("Enable") void
glEnable(GLEnum cap);
@WasmName!("Disable") void
glDisable(GLEnum cap);
@WasmName!("EnableVertexAttribArray") void
glEnableVertexAttribArray(u32 index);
@WasmName!("DisableVertexAttribArray") void
glDisableVertexAttribArray(u32 index);
@WasmName!("FrontFace") void
glFrontFace(GLEnum mode);
@WasmName!("BlendFuncSeparate") void
glBlendFuncSeparate(GLEnum src_rgb, GLEnum dst_rgb, GLEnum src_alpha, GLEnum dst_alpha);
@WasmName!("BindTexture") void
glBindTexture(GLEnum target, u32 texture);
@WasmName!("TexParameterf") void
glTexParameterf(GLEnum target, GLEnum pname, f32 param);
@WasmName!("TexParameteri") void
glTexParameteri(GLEnum target, GLEnum pname, i32 param);
@WasmName!("TexImage2D") void
glTexImage2D(GLEnum target, i32 level, i32 internal_format, usize width, usize height, i32 border, GLEnum format, GLEnum type, const void* data);
@WasmName!("BindVertexArray") void
glBindVertexArray(u32 vao);
@WasmName!("BlendFunc") void
glBlendFunc(GLEnum sfactor, GLEnum dfactor);
@WasmName!("BindBuffer") void
glBindBuffer(GLEnum target, u32 buffer);
@WasmName!("BufferData") void
glBufferData(GLEnum target, usize size, const void* data, GLEnum usage);
@WasmName!("BufferSubData") void
glBufferSubData(GLEnum target, usize offset, usize size, const void* data);
@WasmName!("VertexAttribDivisor") void
glVertexAttribDivisor(u32 index, u32 divisor);
@WasmName!("VertexAttribPointer") void
glVertexAttribPointer(u32 index, i32 size, GLEnum type, b32 normalized, usize stride, const void* pointer);
@WasmName!("Viewport") void
glViewport(i32 x, i32 y, usize width, usize height);
@WasmName!("DrawArraysInstanced") void
glDrawArraysInstanced(GLEnum mode, i32 first, usize count, usize instance_count);
@WasmName!("DrawElementsInstanced") void
glDrawElementsInstanced(GLEnum mode, usize count, GLEnum type, const void* indices, usize instance_count);
@WasmName!("ActiveTexture") void
glActiveTexture(GLEnum texture);
@WasmName!("GetUniformLocation") i32
glGetUniformLocation(u32 program, const char* name);
@WasmName!("Uniform1f") void
glUniform1f(i32 location, f32 v0);
@WasmName!("Uniform2f") void
glUniform2f(i32 location, f32 v0, f32 v1);
@WasmName!("Uniform3f") void
glUniform3f(i32 location, f32 v0, f32 v1, f32 v2);
@WasmName!("Uniform4f") void
glUniform4f(i32 location, f32 v0, f32 v1, f32 v2, f32 v3);
@WasmName!("Uniform1i") void
glUniform1i(i32 location, i32 v0);
@WasmName!("Uniform2i") void
glUniform2i(i32 location, i32 v0, i32 v1);
@WasmName!("Uniform3i") void
glUniform3i(i32 location, i32 v0, i32 v1, i32 v2);
@WasmName!("Uniform4i") void
glUniform4i(i32 location, i32 v0, i32 v1, i32 v2, i32 v3);
@WasmName!("CreateProgram") u32
glCreateProgram();
@WasmName!("CreateShader") u32
glCreateShader(GLEnum shader_type);
@WasmName!("DeleteProgram") void
glDeleteProgram(u32 program);
@WasmName!("DeleteShader") void
glDeleteShader(u32 shader);
@WasmName!("ShaderSource") void
glShaderSource(u32 shader, usize count, const char** string, const i32* length);
@WasmName!("Scissor") void
glScissor(i32 x, i32 y, usize width, usize height);
@WasmName!("GetProgramiv") void
glGetProgramiv(u32 program, GLEnum pname, i32* params);
@WasmName!("GetProgramInfoLog") void
glGetProgramInfoLog(u32 program, i32 max_length, i32* length, char* info_log);
@WasmName!("GetShaderiv") void
glGetShaderiv(u32 shader, GLEnum pname, i32* params);
@WasmName!("GetShaderInfoLog") void
glGetShaderInfoLog(u32 shader, i32 max_length, i32* length, char* info_log);
@WasmName!("AttachShader") void
glAttachShader(u32 program, u32 shader);
@WasmName!("LinkProgram") void
glLinkProgram(u32 program);

16
test.sh
View File

@ -32,7 +32,12 @@ if [ "$1" == "wasm" ]; then
-gcc=clang -gcc=clang
"--of=$out" "--of=$out"
) )
declare -a wasm_src=(wasm/runtime/object.d) declare -a wasm_src=(
wasm/runtime/object.d
opengl/opengl_wasm.d
opengl/opengl.d
opengl/glenum.d
)
ldc2 "${flags[@]}" "${shared_src[@]}" "${wasm_src[@]}" ldc2 "${flags[@]}" "${shared_src[@]}" "${wasm_src[@]}"
@ -66,16 +71,25 @@ else
native_src+=( native_src+=(
vulkan/vulkan.d vulkan/vulkan.d
vulkan/vulkan_funcs.d vulkan/vulkan_funcs.d
opengl/opengl.d
opengl/opengl_native.d
opengl/glenum.d
build/libvma.a build/libvma.a
) )
flags+=( flags+=(
-L-lvulkan -L-lvulkan
-L-lstdc++ -L-lstdc++
-L-lGL
-L-lX11
-L-lXfixes
-Jbuild -Jbuild
-d-version=VULKAN_RENDERER_TEST -d-version=VULKAN_RENDERER_TEST
-d-version=DLIB_ASSETS -d-version=DLIB_ASSETS
-d-version=COMPILE_TEST
-d-version=BUILD_GL
-Xcc=-DBUILD_VULKAN -Xcc=-DBUILD_VULKAN
-Xcc=-DBUILD_ASSETS -Xcc=-DBUILD_ASSETS
-Xcc=-DBUILD_GL
) )
# Test for compilation # Test for compilation

View File

@ -36,35 +36,43 @@ enum SprintfType : size_t
Pointer, Pointer,
} }
template WasmModule(string _module)
{
enum WasmModule = llvmAttr("wasm-import-module", _module);
}
template WasmName(string name)
{
enum WasmName = llvmAttr("wasm-import-name", name);
}
extern extern(C) @llvmAttr("wasm-import-module", "env"): extern extern(C) @WasmModule!("env"):
@llvmAttr("wasm-import-name", "Console") void @WasmName!("Console") void
Console(string str, bool write_line); Console(string str, bool write_line);
@llvmAttr("wasm-import-name", "Console2") void @WasmName!("Console2") void
Console2(size_t length, const(void)* ptr, bool write_line); Console2(size_t length, const(void)* ptr, bool write_line);
@llvmAttr("wasm-import-name", "Abort") void @WasmName!("Abort") void
Abort(string message) @nogc; Abort(string message) @nogc;
@llvmAttr("wasm-import-name", "SprintfLoadValue") void @WasmName!("SprintfLoadValue") void
SprintfLoadValue(const(void)* ptr, SprintfType type) @nogc; SprintfLoadValue(const(void)* ptr, SprintfType type) @nogc;
@llvmAttr("wasm-import-name", "SprintfLoadArray") void @WasmName!("SprintfLoadArray") void
SprintfLoadArray(size_t length, const(void)* ptr, SprintfType type) @nogc; SprintfLoadArray(size_t length, const(void)* ptr, SprintfType type) @nogc;
@llvmAttr("wasm-import-name", "SprintfEnd") size_t @WasmName!("SprintfEnd") size_t
SprintfEnd(char[] buffer, string format) @nogc; SprintfEnd(char[] buffer, string format) @nogc;
@llvmAttr("wasm-import-name", "pow") double @WasmName!("pow") double
pow(double base, double exponent) @nogc; pow(double base, double exponent) @nogc;
@llvmAttr("wasm-import-name", "cos") double @WasmName!("cos") double
cos(double x) @nogc; cos(double x) @nogc;
@llvmAttr("wasm-import-name", "acos") double @WasmName!("acos") double
acos(double x) @nogc; acos(double x) @nogc;
void void

File diff suppressed because it is too large Load Diff