Compare commits

...

27 Commits

Author SHA1 Message Date
Sebastian Dawid
9b8778653e
Merge fb0828d828 into dbadda2683 2025-12-07 04:04:48 +13:00
Camilla Löwy
dbadda2683 Formatting 2025-12-05 13:33:10 +01:00
Camilla Löwy
08449b7183 Linux: Add missing header for ioctl
Fixes #2778
2025-12-04 20:30:12 +01:00
Camilla Löwy
1ce855b0b1 Wayland: Fix missing checks for optional protocol 2025-12-04 20:30:12 +01:00
Camilla Löwy
ebff6606ee Simplify test for shared library build 2025-11-17 22:57:23 +01:00
Sebastian Emanuel Dawid
fb0828d828 Add option to enable building the WebGPU example
The example is now not built by default. Move code to fetch pre-compiled
`wgpu_native` library to `CMake/modules/FindWebGPU.cmake`.
2025-11-14 15:18:14 +01:00
Sebastian Emanuel Dawid
0e80ca651b Create universal WebGPU library during project configuration on macOS 2025-11-13 10:40:00 +01:00
Sebastian Emanuel Dawid
4e1fbfbf92 Fix IMPLIB naming for MinGW 2025-11-12 16:35:38 +01:00
Sebastian Emanuel Dawid
db5fc21072 Switch back to linking against shared library version of wgpu_native 2025-11-12 16:31:08 +01:00
Sebastian Emanuel Dawid
c8c7405f37 Fix typo in URL for secondary wgpu_native ARCH on macOS 2025-11-12 15:45:51 +01:00
Sebastian Emanuel Dawid
15693a1bde Inline code to fetch prebuilt wgpu_native static library 2025-11-12 15:43:49 +01:00
Sebastian Emanuel Dawid
3fe235fb56 Remove unnecessary CMake message printing the CMAKE_SYSTEM_PROCESSOR variable 2025-10-29 11:01:41 +01:00
Sebastian Emanuel Dawid
95e1dcce2e Add metal layer creation that was previously missing. 2025-10-01 09:06:03 +02:00
Sebastian Dawid
0111a5977e Implement rendering a red triangle in the triangle-webgpu example 2025-09-30 11:42:16 +02:00
Sebastian Emanuel Dawid
1471e07ceb Partially Revert "Remove function to pass address of wgpuInstanceCreateSurface."
This reverts commit 8c2f255906.
2025-09-29 15:30:00 +02:00
Sebastian Emanuel Dawid
044774dcee Provide weak default implementation for wgpuInstanceCreateSurface 2025-09-29 14:40:31 +02:00
Sebastian Emanuel Dawid
b0b39d678e Remove now unused wgpu member of _glfw 2025-09-29 11:41:35 +02:00
Sebastian Emanuel Dawid
8c2f255906 Remove function to pass address of wgpuInstanceCreateSurface.
I use an extern function with the `weak` attribute and an assert
to ensure that the function is available at runtime instead.

I also started to add an example using WebGPU.
2025-09-29 11:35:26 +02:00
Sebastian Dawid
a80acffdba
Merge branch 'glfw:master' into webgpu 2025-09-29 09:59:30 +02:00
Sebastian Emanuel Dawid
54fcbc8220 Adjust formatting of new code to fit in with the rest of the code 2025-08-27 00:46:35 +02:00
Sebastian Emanuel Dawid
44f8a80ade Add WebGPU support for MacOS 2025-08-16 00:46:54 +02:00
Sebastian Dawid
4cbb4db70c Add WebGPU support for Windows 2025-08-16 00:30:16 +02:00
Sebastian Emanuel Dawid
205bf6c768 Add WebGPU support to X11 2025-08-15 23:57:40 +02:00
Sebastian Emanuel Dawid
37812b7e36 Revert "Try loading surface creation function via dlsym instead"
This reverts commit cb0c28908f.
2025-08-15 23:39:30 +02:00
Sebastian Emanuel Dawid
cb0c28908f Try loading surface creation function via dlsym instead 2025-08-15 23:38:04 +02:00
Sebastian Emanuel Dawid
8dc6a1f00b Add surface creation function to wl platform initialization 2025-08-15 23:12:47 +02:00
Sebastian Emanuel Dawid
2f44430536 Added native support for creating WebGPU surfaces
Note that this commit only adds support when running on Wayland.
2025-08-15 23:08:51 +02:00
24 changed files with 892 additions and 24 deletions

View File

@ -0,0 +1,84 @@
set(WebGPU_FOUND True) # since we fetch the depencency it will always be found
set(URL_ARCH)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
set(URL_ARCH "x86_64")
elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
set(URL_ARCH "i686")
endif ()
elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|armv8|arm)$")
set(URL_ARCH "aarch64")
else ()
message(FATAL_ERROR "Unsopported CPU architecture: ${CMAKE_SYSTEM_PROCESSOR}")
endif ()
set(URL_OS)
set(WEBGPU_LIBNAME "libwgpu_native.so")
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(URL_OS "windows")
set(WEBGPU_LIBNAME "wgpu_native.dll")
if (MSVC)
set(URL_ARCH "${URL_ARCH}-msvc")
else ()
set(URL_ARCH "${URL_ARCH}-gnu")
endif ()
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(WEBGPU_LIBNAME "libwgpu_native.dylib")
set(URL_OS "macos")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(URL_OS "linux")
else ()
message(FATAL_ERROR "Unsopported OS: ${CMAKE_SYSTEM_NAME}")
endif ()
set(WEBGPU_URL "https://github.com/gfx-rs/wgpu-native/releases/download/v24.0.3.1/wgpu-${URL_OS}-${URL_ARCH}-release.zip")
include(FetchContent)
FetchContent_Declare(webgpu_bins
URL ${WEBGPU_URL}
)
FetchContent_MakeAvailable(webgpu_bins)
add_library(WebGPU::WebGPU SHARED IMPORTED GLOBAL)
set(WEBGPU_RUNTIME_LIB "${webgpu_bins_SOURCE_DIR}/lib/${WEBGPU_LIBNAME}")
set_target_properties(WebGPU::WebGPU PROPERTIES
IMPORTED_LOCATION "${WEBGPU_RUNTIME_LIB}"
)
target_include_directories(WebGPU::WebGPU INTERFACE
"${webgpu_bins_SOURCE_DIR}/include"
"${webgpu_bins_SOURCE_DIR}/include/webgpu"
)
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
if (MSVC)
set_target_properties(WebGPU::WebGPU PROPERTIES
IMPORTED_IMPLIB ${webgpu_bins_SOURCE_DIR}/lib/${WEBGPU_LIBNAME}.lib
)
else ()
set_target_properties(WebGPU::WebGPU PROPERTIES
IMPORTED_IMPLIB ${webgpu_bins_SOURCE_DIR}/lib/lib${WEBGPU_LIBNAME}.a
)
endif ()
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set_target_properties(WebGPU::WebGPU PROPERTIES IMPORTED_NO_SONAME True)
else () # macOS
if (URL_ARCH STREQUAL "aarch64")
set(URL_ARCH "x86_64")
else ()
set(URL_ARCH "aarch64")
endif ()
set(WEBGPU_URL "https://github.com/gfx-rs/wgpu-native/releases/download/v24.0.3.1/wgpu-macos-${URL_ARCH}-release.zip")
FetchContent_Declare(webgpu_other_bins
URL ${WEBGPU_URL}
)
FetchContent_MakeAvailable(webgpu_other_bins)
set(WEBGPU_RUNTIME_LIB_OTHER "${webgpu_other_bins_SOURCE_DIR}/lib/${WEBGPU_LIBNAME}")
execute_process(COMMAND lipo -create ${WEBGPU_RUNTIME_LIB} ${WEBGPU_RUNTIME_LIB_OTHER} -output ${WEBGPU_RUNTIME_LIB})
endif ()
unset(URL_ARCH)
unset(URL_OS)
unset(WEBGPU_URL)
unset(WEBGPU_RUNTIME_LIB)
unset(WEBGPU_RUNTIME_LIB_OTHER)

View File

@ -38,11 +38,7 @@ set(GLFW_LIBRARY_TYPE "${GLFW_LIBRARY_TYPE}" CACHE STRING
"Library type override for GLFW (SHARED, STATIC, OBJECT, or empty to follow BUILD_SHARED_LIBS)")
if (GLFW_LIBRARY_TYPE)
if (GLFW_LIBRARY_TYPE STREQUAL "SHARED")
set(GLFW_BUILD_SHARED_LIBRARY TRUE)
else()
set(GLFW_BUILD_SHARED_LIBRARY FALSE)
endif()
string(COMPARE EQUAL "${GLFW_LIBRARY_TYPE}" "SHARED" GLFW_BUILD_SHARED_LIBRARY)
else()
set(GLFW_BUILD_SHARED_LIBRARY ${BUILD_SHARED_LIBS})
endif()

View File

@ -162,6 +162,7 @@ video tutorials.
- Marcel Metz
- Liam Middlebrook
- mightgoyardstill
- Mihail
- Ave Milia
- Icyllis Milica
- Jonathan Miller

View File

@ -146,11 +146,14 @@ information on what to include when reporting a bug.
from a modal to the content area
- [Wayland] Bugfix: free modules at end of terminate function to resolve
potential segmentation fault (#2744)
- [Wayland] Bugfix: Confining or disabling the cursor could segfault on
compositors without `pointer-constraints-unstable-v1`
- [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631)
- [X11] Bugfix: Occasional crash when an idle display awakes (#2766)
- [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale
less than 1 (#2754)
- [X11] Bugfix: Clamp width and height to >= 1 to prevent BadValue error and app exit
- [Linux] Bugfix: The header for `ioctl` was only implicitly included (#2778)
- [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface`
- [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`
- [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to

View File

@ -25,6 +25,11 @@ set(GETOPT "${GLFW_SOURCE_DIR}/deps/getopt.h"
set(TINYCTHREAD "${GLFW_SOURCE_DIR}/deps/tinycthread.h"
"${GLFW_SOURCE_DIR}/deps/tinycthread.c")
option(BUILD_WEBGPU_EXAMPLE "Build WebGPU example" False)
if (BUILD_WEBGPU_EXAMPLE)
find_package(WebGPU)
endif ()
add_executable(boing WIN32 MACOSX_BUNDLE boing.c ${ICON} ${GLAD_GL})
add_executable(gears WIN32 MACOSX_BUNDLE gears.c ${ICON} ${GLAD_GL})
add_executable(heightmap WIN32 MACOSX_BUNDLE heightmap.c ${ICON} ${GLAD_GL})
@ -34,6 +39,9 @@ add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c ${ICON} ${GLAD_GL})
add_executable(splitview WIN32 MACOSX_BUNDLE splitview.c ${ICON} ${GLAD_GL})
add_executable(triangle-opengl WIN32 MACOSX_BUNDLE triangle-opengl.c ${ICON} ${GLAD_GL})
add_executable(triangle-opengles WIN32 MACOSX_BUNDLE triangle-opengles.c ${ICON} ${GLAD_GLES2})
if (BUILD_WEBGPU_EXAMPLE AND WebGPU_FOUND)
add_executable(triangle-webgpu WIN32 MACOSX_BUNDLE triangle-webgpu.c ${ICON})
endif ()
add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD_GL})
add_executable(windows WIN32 MACOSX_BUNDLE windows.c ${ICON} ${GLAD_GL})
@ -42,8 +50,15 @@ if (RT_LIBRARY)
target_link_libraries(particles "${RT_LIBRARY}")
endif()
if (BUILD_WEBGPU_EXAMPLE AND WebGPU_FOUND)
target_link_libraries(triangle-webgpu WebGPU::WebGPU)
endif ()
set(GUI_ONLY_BINARIES boing gears heightmap particles sharing splitview
triangle-opengl triangle-opengles wave windows)
if (BUILD_WEBGPU_EXAMPLE AND WebGPU_FOUND)
list(APPEND GUI_ONLY_BINARIES triangle-webgpu)
endif ()
set(CONSOLE_BINARIES offscreen)
set_target_properties(${GUI_ONLY_BINARIES} ${CONSOLE_BINARIES} PROPERTIES
@ -68,6 +83,9 @@ if (APPLE)
set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing")
set_target_properties(triangle-opengl PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "OpenGL Triangle")
set_target_properties(triangle-opengles PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "OpenGL ES Triangle")
if (BUILD_WEBGPU_EXAMPLE AND WebGPU_FOUND)
set_target_properties(triangle-webgpu PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "WebGPU Triangle")
endif ()
set_target_properties(splitview PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "SplitView")
set_target_properties(wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave")
set_target_properties(windows PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Windows")

463
examples/triangle-webgpu.c Normal file
View File

@ -0,0 +1,463 @@
//========================================================================
// WebGPU triangle example
// Copyright (c) Sebastian Dawid <sebdawid@gmail.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
//! [code]
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <webgpu/webgpu.h>
#include <webgpu/wgpu.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#define SHADER_SOURCE(...) #__VA_ARGS__
static const char* CODE = SHADER_SOURCE(
@vertex
fn vert(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
var p = vec2f(0.0, 0.0);
if (index == 0u) {
p = vec2f(-0.5, -0.5);
} else if (index == 1u) {
p = vec2f(0.5, -0.5);
} else {
p = vec2f(0.0, 0.5);
}
return vec4f(p, 0.0, 1.0);
}
@fragment
fn frag() -> @location(0) vec4f {
return vec4f(1.0, 0.0, 0.0, 1.0);
}
);
static void error_callback(int error, const char* description);
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);
static WGPULimits get_required_limits(WGPULimits* supported_limits);
static void adapter_callback(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void* userdata1, void* userdata2);
static void device_callback(WGPURequestDeviceStatus status, WGPUDevice device, WGPUStringView message, void* userdata1, void* userdata2);
static void device_lost_callback(const WGPUDevice* device, WGPUDeviceLostReason reason, WGPUStringView message, void* userdata1, void* userdata2);
static void uncaptured_error_callback(const WGPUDevice* device, WGPUErrorType error, WGPUStringView message, void* userdata1, void* userdata2);
int main(void)
{
glfwSetErrorCallback(error_callback);
if (!glfwInit())
exit(EXIT_FAILURE);
glfwSetWGPUInstanceCreateSurfaceAddr(wgpuInstanceCreateSurface);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
GLFWwindow* window = glfwCreateWindow(800, 600, "WebGPU Triangle", NULL, NULL);
if (!window)
{
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwSetKeyCallback(window, key_callback);
WGPUInstance instance = wgpuCreateInstance(NULL);
if (!instance)
{
fprintf(stderr, "Error: Failed to create WebGPU instance.\n");
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_FAILURE);
}
WGPUSurface surface = glfwCreateWindowWGPUSurface(instance, window);
if (!surface)
{
fprintf(stderr, "Error: Failed to create WebGPU surface.\n");
wgpuInstanceRelease(instance);
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_FAILURE);
}
WGPUAdapter adapter;
WGPUDevice device;
WGPUQueue queue;
bool success = false;
WGPURequestAdapterOptions adapter_options = {0};
adapter_options.nextInChain = NULL;
adapter_options.compatibleSurface = surface;
WGPURequestAdapterCallbackInfo adapter_callback_info = {0};
adapter_callback_info.nextInChain = NULL;
adapter_callback_info.mode = WGPUCallbackMode_AllowSpontaneous;
adapter_callback_info.callback = adapter_callback;
adapter_callback_info.userdata1 = &adapter;
adapter_callback_info.userdata2 = &success;
wgpuInstanceRequestAdapter(instance, &adapter_options, adapter_callback_info);
while (!success); // spin until we get the adapter
success = false;
WGPULimits supported_limits = {0};
wgpuAdapterGetLimits(adapter, &supported_limits);
WGPULimits required_limits = get_required_limits(&supported_limits);
WGPUDeviceDescriptor device_descriptor = {0};
device_descriptor.nextInChain = NULL;
device_descriptor.label = (WGPUStringView) { "device", 6 };
device_descriptor.requiredFeatureCount = 0;
device_descriptor.requiredFeatures = NULL;
device_descriptor.requiredLimits = &required_limits;
device_descriptor.defaultQueue.nextInChain = NULL;
device_descriptor.defaultQueue.label = (WGPUStringView) { "queue", 5 };
device_descriptor.deviceLostCallbackInfo.nextInChain = NULL;
device_descriptor.deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous;
device_descriptor.deviceLostCallbackInfo.callback = device_lost_callback;
device_descriptor.deviceLostCallbackInfo.userdata1 = NULL;
device_descriptor.deviceLostCallbackInfo.userdata2 = NULL;
WGPURequestDeviceCallbackInfo device_callback_info = {0};
device_callback_info.nextInChain = NULL;
device_callback_info.mode = WGPUCallbackMode_AllowSpontaneous;
device_callback_info.callback = device_callback;
device_callback_info.userdata1 = &device;
device_callback_info.userdata2 = &success;
wgpuAdapterRequestDevice(adapter, &device_descriptor, device_callback_info);
while (!success); // spin until we get the dvice
success = false;
queue = wgpuDeviceGetQueue(device);
WGPUSurfaceCapabilities surface_capabilities = {0};
surface_capabilities.nextInChain = NULL;
if (wgpuSurfaceGetCapabilities(surface, adapter, &surface_capabilities) != WGPUStatus_Success)
{
fprintf(stderr, "Error: Failed to get surface capabilities.\n");
wgpuQueueRelease(queue);
wgpuDeviceRelease(device);
wgpuSurfaceRelease(surface);
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_FAILURE);
}
WGPUTextureFormat format = {0};
for (size_t i = 0; i < surface_capabilities.formatCount; ++i)
{
WGPUTextureFormat f = surface_capabilities.formats[i];
if (f == WGPUTextureFormat_BGRA8UnormSrgb || f == WGPUTextureFormat_RGBA8UnormSrgb)
{
format = f;
break;
}
}
WGPUSurfaceConfiguration surface_configuration = {0};
surface_configuration.nextInChain = NULL;
surface_configuration.width = 800;
surface_configuration.height = 600;
surface_configuration.format = format;
surface_configuration.viewFormatCount = 0;
surface_configuration.viewFormats = NULL;
surface_configuration.usage = WGPUTextureUsage_RenderAttachment;
surface_configuration.presentMode = WGPUPresentMode_Fifo;
surface_configuration.alphaMode = WGPUCompositeAlphaMode_Auto;
surface_configuration.device = device;
wgpuSurfaceConfigure(surface, &surface_configuration);
wgpuAdapterRelease(adapter);
wgpuInstanceRelease(instance);
WGPUShaderSourceWGSL shader_source = {0};
shader_source.chain.next = NULL;
shader_source.chain.sType = WGPUSType_ShaderSourceWGSL;
shader_source.code = (WGPUStringView) { CODE, strlen(CODE) };
WGPUShaderModuleDescriptor module_descriptor = {0};
module_descriptor.nextInChain = &shader_source.chain;
module_descriptor.label = (WGPUStringView) { NULL, SIZE_MAX };
WGPUShaderModule module = wgpuDeviceCreateShaderModule(device, &module_descriptor);
WGPURenderPipelineDescriptor pipeline_descriptor = {0};
pipeline_descriptor.nextInChain = NULL;
pipeline_descriptor.label = (WGPUStringView) { NULL, SIZE_MAX };
pipeline_descriptor.layout = NULL;
pipeline_descriptor.vertex.nextInChain = NULL;
pipeline_descriptor.vertex.entryPoint = (WGPUStringView) { "vert", 4 };
pipeline_descriptor.vertex.module = module;
pipeline_descriptor.vertex.bufferCount = 0;
pipeline_descriptor.vertex.buffers = NULL;
pipeline_descriptor.vertex.constantCount = 0;
pipeline_descriptor.vertex.constants = NULL;
pipeline_descriptor.primitive.nextInChain = NULL;
pipeline_descriptor.primitive.topology = WGPUPrimitiveTopology_TriangleList;
pipeline_descriptor.primitive.stripIndexFormat = WGPUIndexFormat_Undefined;
pipeline_descriptor.primitive.frontFace = WGPUFrontFace_CCW;
pipeline_descriptor.primitive.cullMode = WGPUCullMode_None;
WGPUBlendState blend_state = {0};
blend_state.color.srcFactor = WGPUBlendFactor_SrcAlpha;
blend_state.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
blend_state.color.operation = WGPUBlendOperation_Add;
blend_state.alpha.srcFactor = WGPUBlendFactor_Zero;
blend_state.alpha.dstFactor = WGPUBlendFactor_One;
blend_state.alpha.operation = WGPUBlendOperation_Add;
WGPUColorTargetState color_target_state = {0};
color_target_state.nextInChain = NULL;
color_target_state.format = format;
color_target_state.blend = &blend_state;
color_target_state.writeMask = WGPUColorWriteMask_All;
WGPUFragmentState fragment_state = {0};
fragment_state.nextInChain = NULL;
fragment_state.module = module;
fragment_state.entryPoint = (WGPUStringView) { "frag", 4 };
fragment_state.constantCount = 0;
fragment_state.constants = NULL;
fragment_state.targetCount = 1;
fragment_state.targets = &color_target_state;
pipeline_descriptor.fragment = &fragment_state;
pipeline_descriptor.multisample.count = 1;
pipeline_descriptor.multisample.mask = ~0u;
pipeline_descriptor.multisample.alphaToCoverageEnabled = false;
pipeline_descriptor.depthStencil = NULL;
WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(device, &pipeline_descriptor);
wgpuShaderModuleRelease(module);
WGPUSurfaceTexture surface_texture = {0};
WGPUTextureView target_view = {0};
while (!glfwWindowShouldClose(window))
{
wgpuDevicePoll(device, false, NULL);
glfwPollEvents();
wgpuSurfaceGetCurrentTexture(surface, &surface_texture);
if (surface_texture.status == WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal)
{
WGPUTextureViewDescriptor view_descriptor = {0};
view_descriptor.nextInChain = NULL;
view_descriptor.label = (WGPUStringView) { NULL, SIZE_MAX };
view_descriptor.format = wgpuTextureGetFormat(surface_texture.texture);
view_descriptor.dimension = WGPUTextureViewDimension_2D;
view_descriptor.baseMipLevel = 0;
view_descriptor.mipLevelCount = 1;
view_descriptor.baseArrayLayer = 0;
view_descriptor.arrayLayerCount = 1;
view_descriptor.aspect = WGPUTextureAspect_All;
view_descriptor.usage = WGPUTextureUsage_RenderAttachment;
target_view = wgpuTextureCreateView(surface_texture.texture, &view_descriptor);
}
if (target_view == NULL)
continue;
WGPURenderPassDescriptor render_pass_descriptor = {0};
render_pass_descriptor.nextInChain = NULL;
WGPURenderPassColorAttachment color_attachment = {0};
color_attachment.view = target_view;
color_attachment.resolveTarget = NULL;
color_attachment.loadOp = WGPULoadOp_Clear;
color_attachment.storeOp = WGPUStoreOp_Store;
color_attachment.clearValue = (WGPUColor) { 0.0f, 0.0f, 0.0f, 1.0f };
render_pass_descriptor.colorAttachmentCount = 1;
render_pass_descriptor.colorAttachments = &color_attachment;
render_pass_descriptor.depthStencilAttachment = NULL;
render_pass_descriptor.timestampWrites = NULL;
WGPUCommandEncoderDescriptor encoder_descriptor = {0};
encoder_descriptor.nextInChain = NULL;
encoder_descriptor.label = (WGPUStringView) { NULL, SIZE_MAX };
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, &encoder_descriptor);
WGPURenderPassEncoder render_pass = wgpuCommandEncoderBeginRenderPass(encoder, &render_pass_descriptor);
wgpuRenderPassEncoderSetPipeline(render_pass, pipeline);
wgpuRenderPassEncoderDraw(render_pass, 3, 1, 0, 0);
wgpuRenderPassEncoderEnd(render_pass);
wgpuRenderPassEncoderRelease(render_pass);
WGPUCommandBufferDescriptor command_buffer_descriptor = {0};
command_buffer_descriptor.nextInChain = NULL;
command_buffer_descriptor.label = (WGPUStringView) { NULL, SIZE_MAX };
WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(encoder, &command_buffer_descriptor);
wgpuQueueSubmit(queue, 1, &command_buffer);
wgpuCommandBufferRelease(command_buffer);
wgpuTextureViewRelease(target_view);
target_view = NULL;
wgpuSurfacePresent(surface);
}
wgpuQueueRelease(queue);
wgpuDeviceRelease(device);
wgpuSurfaceRelease(surface);
glfwDestroyWindow(window);
glfwTerminate();
exit(EXIT_SUCCESS);
}
void error_callback(int error, const char* description)
{
fprintf(stderr, "Error: %s\n", description);
}
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
static const WGPULimits DEFAULT_LIMITS = {
.nextInChain = NULL,
.maxTextureDimension1D = WGPU_LIMIT_U32_UNDEFINED,
.maxTextureDimension2D = WGPU_LIMIT_U32_UNDEFINED,
.maxTextureDimension3D = WGPU_LIMIT_U32_UNDEFINED,
.maxTextureArrayLayers = WGPU_LIMIT_U32_UNDEFINED,
.maxBindGroups = WGPU_LIMIT_U32_UNDEFINED,
.maxBindGroupsPlusVertexBuffers = WGPU_LIMIT_U32_UNDEFINED,
.maxBindingsPerBindGroup = WGPU_LIMIT_U32_UNDEFINED,
.maxDynamicUniformBuffersPerPipelineLayout = WGPU_LIMIT_U32_UNDEFINED,
.maxDynamicStorageBuffersPerPipelineLayout = WGPU_LIMIT_U32_UNDEFINED,
.maxSampledTexturesPerShaderStage = WGPU_LIMIT_U32_UNDEFINED,
.maxSamplersPerShaderStage = WGPU_LIMIT_U32_UNDEFINED,
.maxStorageBuffersPerShaderStage = WGPU_LIMIT_U32_UNDEFINED,
.maxStorageTexturesPerShaderStage = WGPU_LIMIT_U32_UNDEFINED,
.maxUniformBuffersPerShaderStage = WGPU_LIMIT_U32_UNDEFINED,
.maxUniformBufferBindingSize = WGPU_LIMIT_U64_UNDEFINED,
.maxStorageBufferBindingSize = WGPU_LIMIT_U64_UNDEFINED,
.minUniformBufferOffsetAlignment = WGPU_LIMIT_U32_UNDEFINED,
.minStorageBufferOffsetAlignment = WGPU_LIMIT_U32_UNDEFINED,
.maxVertexBuffers = WGPU_LIMIT_U32_UNDEFINED,
.maxBufferSize = WGPU_LIMIT_U64_UNDEFINED,
.maxVertexAttributes = WGPU_LIMIT_U32_UNDEFINED,
.maxVertexBufferArrayStride = WGPU_LIMIT_U32_UNDEFINED,
.maxInterStageShaderVariables = WGPU_LIMIT_U32_UNDEFINED,
.maxColorAttachments = WGPU_LIMIT_U32_UNDEFINED,
.maxColorAttachmentBytesPerSample = WGPU_LIMIT_U32_UNDEFINED,
.maxComputeWorkgroupStorageSize = WGPU_LIMIT_U32_UNDEFINED,
.maxComputeInvocationsPerWorkgroup = WGPU_LIMIT_U32_UNDEFINED,
.maxComputeWorkgroupSizeX = WGPU_LIMIT_U32_UNDEFINED,
.maxComputeWorkgroupSizeY = WGPU_LIMIT_U32_UNDEFINED,
.maxComputeWorkgroupSizeZ = WGPU_LIMIT_U32_UNDEFINED,
.maxComputeWorkgroupsPerDimension = WGPU_LIMIT_U32_UNDEFINED
};
WGPULimits get_required_limits(WGPULimits* supported_limits) {
WGPULimits required_limits = DEFAULT_LIMITS;
required_limits.maxVertexAttributes = 3;
required_limits.maxVertexBuffers = 1;
required_limits.maxBufferSize = 256 * 1024 * 1024; // 256 MiB
required_limits.maxVertexBufferArrayStride = sizeof(float) * 8;
required_limits.maxInterStageShaderVariables = 6;
required_limits.maxBindGroups = 2;
required_limits.maxUniformBuffersPerShaderStage = 2;
required_limits.maxUniformBufferBindingSize = 4 * 16 * sizeof(float);
required_limits.maxSampledTexturesPerShaderStage = 1;
required_limits.maxSamplersPerShaderStage = 1;
// require default maximum value for 2D textures
required_limits.maxTextureDimension1D = 8192;
required_limits.maxTextureDimension2D = 8192;
required_limits.maxTextureArrayLayers = 1;
// explicitly forward minimum limits, since they may cause issues otherwise
required_limits.minStorageBufferOffsetAlignment = supported_limits->minStorageBufferOffsetAlignment;
required_limits.minUniformBufferOffsetAlignment = supported_limits->minUniformBufferOffsetAlignment;
return required_limits;
}
void adapter_callback(
WGPURequestAdapterStatus status, WGPUAdapter adapter,
WGPUStringView message, void* userdata1, void* userdata2
) {
if (status == WGPURequestAdapterStatus_Success) {
*(WGPUAdapter*)userdata1 = adapter;
} else {
fprintf(stderr, "Failed to get WebGPU adapter: %s\n", message.data);
return;
}
*(bool*)userdata2 = true;
}
void device_callback(
WGPURequestDeviceStatus status, WGPUDevice device,
WGPUStringView message, void* userdata1, void* userdata2
) {
if (status == WGPURequestDeviceStatus_Success) {
*(WGPUDevice*)userdata1 = device;
} else {
fprintf(stderr, "Failed to get WebGPU device: %s\n", message.data);
return;
}
*(bool*)userdata2 = true;
}
void device_lost_callback(
const WGPUDevice* device, WGPUDeviceLostReason reason,
WGPUStringView message, void* userdata1, void* userdata2
) {
(void)userdata1;
(void)userdata2;
fprintf(stderr, "Device 0x%zx lost with reason 0x%zx: %s\n", (size_t)*device, (size_t)reason, message.data);
}
void uncaptured_error_callback(
const WGPUDevice* device, WGPUErrorType error,
WGPUStringView message, void* userdata1, void* userdata2
) {
(void)userdata1;
(void)userdata2;
fprintf(stderr, "Device 0x%zx has uncaptured error 0x%zx: %s\n", (size_t)*device, (size_t)error, message.data);
}

View File

@ -115,6 +115,10 @@ extern "C" {
* VK_USE_PLATFORM_WIN32_KHR) so we offer our replacement symbols after it.
*/
#if defined(GLFW_INCLUDE_WEBGPU)
#include <webgpu/webgpu.h>
#endif /* WebGPU header */
/* It is customary to use APIENTRY for OpenGL function pointer declarations on
* all platforms. Additionally, the Windows OpenGL header needs APIENTRY.
*/
@ -6530,6 +6534,41 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window
#endif /*VK_VERSION_1_0*/
#if defined(WEBGPU_H_)
/*! @brief Provide the address of the `wgpuInstanceCreateSurface` function to GLFW.
*
* This function passes the address provided for the `wgpuInstanceCreateSurface` function
* to GLFW.
*
* @param[in] addr The address of the `wgpuInstanceCreateSurface` function.
*
* @since Added in version 3.5
*
* @ingroup webgpu
*/
GLFWAPI void glfwSetWGPUInstanceCreateSurfaceAddr(WGPUSurface (*addr)(WGPUInstance, const WGPUSurfaceDescriptor*));
/*! @brief Creates a WebGPU surface for the specified window.
*
* This function creates a WebGPU surface for the specified window.
*
* If the surface could not be created this function returns `NULL`.
*
* It is the callers responsibility to destroy the surface. The surface
* must be destroyed using `wgpuSurfaceRelease`.
*
* @param[in] instance The WebGPU instance to create the surface in.
* @param[in] window The window to create the surface for.
* @return The handle of the surface. This is `NULL` if an error occurred.
*
* @since Added in version 3.5
*
* @ingroup webgpu
*/
GLFWAPI WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* window);
#endif /*WEBGPU_H_*/
/*************************************************************************
* Global definition cleanup

View File

@ -3,9 +3,10 @@ add_library(glfw ${GLFW_LIBRARY_TYPE}
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3.h"
"${GLFW_SOURCE_DIR}/include/GLFW/glfw3native.h"
internal.h platform.h mappings.h
context.c init.c input.c monitor.c platform.c vulkan.c window.c
egl_context.c osmesa_context.c null_platform.h null_joystick.h
null_init.c null_monitor.c null_window.c null_joystick.c)
context.c init.c input.c monitor.c platform.c vulkan.c webgpu.c
window.c egl_context.c osmesa_context.c null_platform.h
null_joystick.h null_init.c null_monitor.c null_window.c
null_joystick.c)
# The time, thread and module code is shared between all backends on a given OS,
# including the null backend, which still needs those bits to be functional
@ -128,7 +129,8 @@ set_target_properties(glfw PROPERTIES
C_STANDARD 99
C_EXTENSIONS OFF
DEFINE_SYMBOL _GLFW_BUILD_DLL
FOLDER "GLFW3")
FOLDER "GLFW3"
EXPORT_COMPILE_COMMANDS ON)
target_include_directories(glfw PUBLIC
"$<BUILD_INTERFACE:${GLFW_SOURCE_DIR}/include>"

View File

@ -564,7 +564,8 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform)
.getEGLNativeWindow = _glfwGetEGLNativeWindowCocoa,
.getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsCocoa,
.getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportCocoa,
.createWindowSurface = _glfwCreateWindowSurfaceCocoa
.createWindowSurface = _glfwCreateWindowSurfaceCocoa,
.createWindowWGPUSurface = _glfwCreateWindowWGPUSurfaceCocoa
};
*platform = cocoa;

View File

@ -276,6 +276,8 @@ void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions);
GLFWbool _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
WGPUSurface _glfwCreateWindowWGPUSurfaceCocoa(WGPUInstance instance, _GLFWwindow* window);
void _glfwFreeMonitorCocoa(_GLFWmonitor* monitor);
void _glfwGetMonitorPosCocoa(_GLFWmonitor* monitor, int* xpos, int* ypos);
void _glfwGetMonitorContentScaleCocoa(_GLFWmonitor* monitor, float* xscale, float* yscale);

View File

@ -2020,6 +2020,39 @@ VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance,
} // autoreleasepool
}
typedef struct WGPUSurfaceSourceMetalLayer
{
WGPUChainedStruct chain;
void * layer;
} WGPUSurfaceSourceMetalLayer;
WGPUSurface _glfwCreateWindowWGPUSurfaceCocoa(WGPUInstance instance, _GLFWwindow* window)
{
window->ns.layer = [CAMetalLayer layer];
if (!window->ns.layer)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to create layer for view");
return NULL;
}
if (window->ns.scaleFramebuffer)
[window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];
[window->ns.view setLayer:window->ns.layer];
[window->ns.view setWantsLayer:YES];
WGPUSurfaceSourceMetalLayer metalSurface;
metalSurface.chain.next = NULL;
metalSurface.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
metalSurface.layer = window->ns.layer;
WGPUSurfaceDescriptor surfaceDescriptor;
surfaceDescriptor.nextInChain = &metalSurface.chain;
surfaceDescriptor.label = (WGPUStringView){ NULL, SIZE_MAX };
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////

View File

@ -331,6 +331,45 @@ typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,con
typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*);
#define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr
// forward declare WebGPU types
typedef struct WGPUInstanceImpl* WGPUInstance;
typedef struct WGPUSurfaceImpl* WGPUSurface;
typedef struct WGPUStringView
{
char const * data;
size_t length;
} WGPUStringView;
typedef enum WGPUSType
{
WGPUSType_ShaderSourceSPIRV = 0x00000001,
WGPUSType_ShaderSourceWGSL = 0x00000002,
WGPUSType_RenderPassMaxDrawCount = 0x00000003,
WGPUSType_SurfaceSourceMetalLayer = 0x00000004,
WGPUSType_SurfaceSourceWindowsHWND = 0x00000005,
WGPUSType_SurfaceSourceXlibWindow = 0x00000006,
WGPUSType_SurfaceSourceWaylandSurface = 0x00000007,
WGPUSType_SurfaceSourceAndroidNativeWindow = 0x00000008,
WGPUSType_SurfaceSourceXCBWindow = 0x00000009,
WGPUSType_Force32 = 0x7FFFFFFF
} WGPUSType;
typedef struct WGPUChainedStruct
{
struct WGPUChainedStruct const * next;
WGPUSType sType;
} WGPUChainedStruct;
typedef struct WGPUSurfaceDescriptor
{
WGPUChainedStruct const * nextInChain;
WGPUStringView label;
} WGPUSurfaceDescriptor;
typedef WGPUSurface (*PFN_wgpuInstanceCreateSurface)(WGPUInstance, const WGPUSurfaceDescriptor*);
#define wgpuInstanceCreateSurface _glfw.wgpu.instanceCreateSurface
#include "platform.h"
#define GLFW_NATIVE_INCLUDE_NONE
@ -758,6 +797,8 @@ struct _GLFWplatform
void (*getRequiredInstanceExtensions)(char**);
GLFWbool (*getPhysicalDevicePresentationSupport)(VkInstance,VkPhysicalDevice,uint32_t);
VkResult (*createWindowSurface)(VkInstance,_GLFWwindow*,const VkAllocationCallbacks*,VkSurfaceKHR*);
// webgpu
WGPUSurface (*createWindowWGPUSurface)(WGPUInstance, _GLFWwindow*);
};
// Library global data
@ -874,6 +915,10 @@ struct _GLFWlibrary
GLFWbool EXT_headless_surface;
} vk;
struct {
PFN_wgpuInstanceCreateSurface instanceCreateSurface;
} wgpu;
struct {
GLFWmonitorfun monitor;
GLFWjoystickfun joystick;

View File

@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>

56
src/webgpu.c Normal file
View File

@ -0,0 +1,56 @@
//========================================================================
// GLFW 3.5 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) Sebastian Dawid <sebdawid@gmail.com>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <stdlib.h>
GLFWAPI void glfwSetWGPUInstanceCreateSurfaceAddr(WGPUSurface (*addr)(WGPUInstance, const WGPUSurfaceDescriptor*))
{
_GLFW_REQUIRE_INIT()
_glfw.wgpu.instanceCreateSurface = addr;
}
GLFWAPI WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* handle)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL)
_GLFWwindow* window = (_GLFWwindow*)handle;
assert(window != NULL);
assert(instance != NULL);
assert(_glfw.wgpu.instanceCreateSurface != NULL);
if (window->context.client != GLFW_NO_API)
{
_glfwInputError(GLFW_INVALID_VALUE,
"WebGPU: Window surface creation requires the window to have the client API set to GLFW_NO_API");
return NULL;
};
return _glfw.platform.createWindowWGPUSurface(instance, window);
}

View File

@ -528,7 +528,8 @@ void _glfwUpdateKeyNamesWin32(void)
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD)
{
const UINT vks[] = {
const UINT vks[] =
{
VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3,
VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7,
VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE,
@ -669,7 +670,8 @@ GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform)
.getEGLNativeWindow = _glfwGetEGLNativeWindowWin32,
.getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsWin32,
.getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportWin32,
.createWindowSurface = _glfwCreateWindowSurfaceWin32
.createWindowSurface = _glfwCreateWindowSurfaceWin32,
.createWindowWGPUSurface = _glfwCreateWindowWGPUSurfaceWin32
};
*platform = win32;

View File

@ -544,6 +544,8 @@ void _glfwGetRequiredInstanceExtensionsWin32(char** extensions);
GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
WGPUSurface _glfwCreateWindowWGPUSurfaceWin32(WGPUInstance instance, _GLFWwindow* window);
void _glfwFreeMonitorWin32(_GLFWmonitor* monitor);
void _glfwGetMonitorPosWin32(_GLFWmonitor* monitor, int* xpos, int* ypos);
void _glfwGetMonitorContentScaleWin32(_GLFWmonitor* monitor, float* xscale, float* yscale);

View File

@ -2562,6 +2562,28 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance,
return err;
}
typedef struct WGPUSurfaceSourceWindowsHWND
{
WGPUChainedStruct chain;
void * hinstance;
void * hwnd;
} WGPUSurfaceSourceWindowsHWND;
WGPUSurface _glfwCreateWindowWGPUSurfaceWin32(WGPUInstance instance, _GLFWwindow *window)
{
WGPUSurfaceSourceWindowsHWND windowsSurface;
windowsSurface.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
windowsSurface.chain.next = NULL;
windowsSurface.hinstance = _glfw.win32.instance;
windowsSurface.hwnd = window->win32.handle;
WGPUSurfaceDescriptor surfaceDescriptor;
surfaceDescriptor.nextInChain = &windowsSurface.chain;
surfaceDescriptor.label = (WGPUStringView){ NULL, SIZE_MAX };
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
}
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);

View File

@ -515,7 +515,8 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform)
.getEGLNativeWindow = _glfwGetEGLNativeWindowWayland,
.getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsWayland,
.getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportWayland,
.createWindowSurface = _glfwCreateWindowSurfaceWayland
.createWindowSurface = _glfwCreateWindowSurfaceWayland,
.createWindowWGPUSurface = _glfwCreateWindowWGPUSurfaceWayland
};
void* module = _glfwPlatformLoadModule("libwayland-client.so.0");
@ -979,7 +980,8 @@ void _glfwTerminateWayland(void)
if (_glfw.wl.cursorTimerfd >= 0)
close(_glfw.wl.cursorTimerfd);
// Free modules only after all wayland termination functions are called
// Free modules only after all Wayland termination functions are called
if (_glfw.egl.handle)
{
_glfwPlatformFreeModule(_glfw.egl.handle);
@ -1003,6 +1005,7 @@ void _glfwTerminateWayland(void)
_glfwPlatformFreeModule(_glfw.wl.xkb.handle);
_glfw.wl.xkb.handle = NULL;
}
if (_glfw.wl.cursor.handle)
{
_glfwPlatformFreeModule(_glfw.wl.cursor.handle);

View File

@ -136,18 +136,22 @@ struct wl_output;
#define GLFW_WAYLAND_MONITOR_STATE _GLFWmonitorWayland wl;
#define GLFW_WAYLAND_CURSOR_STATE _GLFWcursorWayland wl;
struct wl_cursor_image {
struct wl_cursor_image
{
uint32_t width;
uint32_t height;
uint32_t hotspot_x;
uint32_t hotspot_y;
uint32_t delay;
};
struct wl_cursor {
struct wl_cursor
{
unsigned int image_count;
struct wl_cursor_image** images;
char* name;
};
typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*);
typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*);
typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*);
@ -678,6 +682,8 @@ void _glfwGetRequiredInstanceExtensionsWayland(char** extensions);
GLFWbool _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
WGPUSurface _glfwCreateWindowWGPUSurfaceWayland(WGPUInstance instance, _GLFWwindow* window);
void _glfwFreeMonitorWayland(_GLFWmonitor* monitor);
void _glfwGetMonitorPosWayland(_GLFWmonitor* monitor, int* xpos, int* ypos);
void _glfwGetMonitorContentScaleWayland(_GLFWmonitor* monitor, float* xscale, float* yscale);

View File

@ -1413,7 +1413,7 @@ static void handleEvents(double* timeout)
if (read(_glfw.wl.keyRepeatTimerfd, &repeats, sizeof(repeats)) == 8)
{
if(_glfw.wl.keyboardFocus)
if (_glfw.wl.keyboardFocus)
{
for (uint64_t i = 0; i < repeats; i++)
{
@ -1692,7 +1692,8 @@ static void keyboardHandleKeymap(void* userData,
}
mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (mapStr == MAP_FAILED) {
if (mapStr == MAP_FAILED)
{
close(fd);
return;
}
@ -1838,7 +1839,9 @@ static void keyboardHandleKey(void* userData,
timer.it_value.tv_nsec = (_glfw.wl.keyRepeatDelay % 1000) * 1000000;
timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
}
} else if (scancode == _glfw.wl.keyRepeatScancode) {
}
else if (scancode == _glfw.wl.keyRepeatScancode)
{
timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL);
}
@ -2974,10 +2977,16 @@ static void lockPointer(_GLFWwindow* window)
if (!_glfw.wl.relativePointerManager)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: The compositor does not support pointer locking");
"Wayland: The compositor does not support relative pointer motion");
return;
}
if (!_glfw.wl.pointerConstraints)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: The compositor does not support locking the pointer");
}
window->wl.relativePointer =
zwp_relative_pointer_manager_v1_get_relative_pointer(
_glfw.wl.relativePointerManager,
@ -3025,6 +3034,12 @@ static const struct zwp_confined_pointer_v1_listener confinedPointerListener =
static void confinePointer(_GLFWwindow* window)
{
if (!_glfw.wl.pointerConstraints)
{
_glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: The compositor does not support confining the pointer");
}
window->wl.confinedPointer =
zwp_pointer_constraints_v1_confine_pointer(
_glfw.wl.pointerConstraints,
@ -3324,6 +3339,27 @@ VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance,
return err;
}
typedef struct WGPUSurfaceSourceWaylandSurface
{
WGPUChainedStruct chain;
void * display;
void * surface;
} WGPUSurfaceSourceWaylandSurface;
WGPUSurface _glfwCreateWindowWGPUSurfaceWayland(WGPUInstance instance, _GLFWwindow* window)
{
WGPUSurfaceSourceWaylandSurface waylandSurface;
waylandSurface.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
waylandSurface.chain.next = NULL;
waylandSurface.surface = window->wl.surface;
waylandSurface.display = _glfw.wl.display;
WGPUSurfaceDescriptor surfaceDescriptor;
surfaceDescriptor.nextInChain = &waylandSurface.chain;
surfaceDescriptor.label = (WGPUStringView){ NULL, SIZE_MAX };
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////

View File

@ -1246,7 +1246,8 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
.getEGLNativeWindow = _glfwGetEGLNativeWindowX11,
.getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsX11,
.getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportX11,
.createWindowSurface = _glfwCreateWindowSurfaceX11
.createWindowSurface = _glfwCreateWindowSurfaceX11,
.createWindowWGPUSurface = _glfwCreateWindowWGPUSurfaceX11
};
// HACK: If the application has left the locale as "C" then both wide

View File

@ -151,7 +151,8 @@ void _glfwPollMonitorsX11(void)
}
XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc);
if (!ci) {
if (!ci)
{
XRRFreeOutputInfo(oi);
continue;
}

View File

@ -964,6 +964,8 @@ void _glfwGetRequiredInstanceExtensionsX11(char** extensions);
GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
WGPUSurface _glfwCreateWindowWGPUSurfaceX11(WGPUInstance instance, _GLFWwindow* window);
void _glfwFreeMonitorX11(_GLFWmonitor* monitor);
void _glfwGetMonitorPosX11(_GLFWmonitor* monitor, int* xpos, int* ypos);
void _glfwGetMonitorContentScaleX11(_GLFWmonitor* monitor, float* xscale, float* yscale);

View File

@ -2207,10 +2207,10 @@ void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height)
void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height)
{
// The dimensions must be nonzero, or a BadValue error results.
// The dimensions must be nonzero, or a BadValue error results
width = _glfw_max(1, width);
height = _glfw_max(1, height);
if (window->monitor)
{
if (window->monitor->window == window)
@ -3290,6 +3290,55 @@ VkResult _glfwCreateWindowSurfaceX11(VkInstance instance,
}
}
typedef struct WGPUSurfaceSourceXCBWindow
{
WGPUChainedStruct chain;
void * connection;
uint32_t window;
} WGPUSurfaceSourceXCBWindow;
typedef struct WGPUSurfaceSourceXlibWindow
{
WGPUChainedStruct chain;
void * display;
uint64_t window;
} WGPUSurfaceSourceXlibWindow;
WGPUSurface _glfwCreateWindowWGPUSurfaceX11(WGPUInstance instance, _GLFWwindow* window)
{
WGPUSurfaceDescriptor surfaceDescriptor;
if (_glfw.x11.x11xcb.handle)
{
WGPUSurfaceSourceXCBWindow xcbSurface;
xcbSurface.chain.sType = WGPUSType_SurfaceSourceXCBWindow;
xcbSurface.chain.next = NULL;
xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display);
if (!connection)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to retrieve XCB connection");
return NULL;
}
xcbSurface.connection = connection;
xcbSurface.window = window->x11.handle;
surfaceDescriptor.nextInChain = &xcbSurface.chain;
}
else
{
WGPUSurfaceSourceXlibWindow xlibSurface;
xlibSurface.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
xlibSurface.chain.next = NULL;
xlibSurface.display = _glfw.x11.display;
xlibSurface.window = window->x11.handle;
surfaceDescriptor.nextInChain = &xlibSurface.chain;
}
surfaceDescriptor.label = (WGPUStringView){ NULL, SIZE_MAX };
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////