Files
RobustToolbox/Robust.Client.Graphics.Rhi/WebGpu/RhiWebGpu.Window.cs
Myra f4cf5565fa Add linux wayland support to claudia (#6249)
* Add linux wayland support to claudia

Could not do x11 because quote "oh my god x11 support might be a hecking nightmare" -pjb

but the skeleton is there i guess

* Review

* Ok massivly misunderstood pjb
2025-10-10 20:43:28 +02:00

172 lines
5.6 KiB
C#

using Robust.Shared.Maths;
namespace Robust.Client.Graphics.Rhi.WebGpu;
internal sealed unsafe partial class RhiWebGpu
{
private RhiTextureFormat _mainTextureFormat;
private WGPUPresentMode[] _availPresentModes = [];
public override RhiTextureFormat MainTextureFormat => _mainTextureFormat;
public sealed class WindowData
{
public WGPUSurface Surface;
}
private WindowData CreateSurfaceForWindow(in RhiWindowSurfaceParams surfaceParams)
{
WGPUSurfaceDescriptor surfaceDesc = default;
#if WINDOWS
var surfaceDescHwnd = new WGPUSurfaceSourceWindowsHWND
{
chain =
{
sType = WGPUSType.WGPUSType_SurfaceSourceWindowsHWND
},
hinstance = surfaceParams.HInstance,
hwnd = surfaceParams.HWnd,
};
surfaceDesc.nextInChain = (WGPUChainedStruct*)(&surfaceDescHwnd);
#elif MACOS
var surfaceDescMetal = new WGPUSurfaceSourceMetalLayer
{
chain =
{
sType = WGPUSType.WGPUSType_SurfaceSourceMetalLayer
},
layer = surfaceParams.MetalLayer
};
surfaceDesc.nextInChain = (WGPUChainedStruct*)(&surfaceDescMetal);
#elif LINUX
WGPUSurfaceSourceWaylandSurface surfaceDescWayland;
WGPUSurfaceSourceXlibWindow surfaceDescX11;
if (surfaceParams.Wayland)
{
surfaceDescWayland = new WGPUSurfaceSourceWaylandSurface
{
chain =
{
sType = WGPUSType.WGPUSType_SurfaceSourceWaylandSurface
},
display = surfaceParams.WaylandDisplay,
surface = surfaceParams.WaylandSurface,
};
surfaceDesc.nextInChain = (WGPUChainedStruct*)(&surfaceDescWayland);
}
else
{
surfaceDescX11 = new WGPUSurfaceSourceXlibWindow()
{
chain =
{
sType = WGPUSType.WGPUSType_SurfaceSourceXlibWindow
},
display = surfaceParams.X11Display,
// TODO "Oh my god x11 support might be a nightmare this is outside of your ability to deal with -pjb"
// window = surfaceParams.X11Window,
};
surfaceDesc.nextInChain = (WGPUChainedStruct*)(&surfaceDescX11);
}
#endif
var surface = wgpuInstanceCreateSurface(_wgpuInstance, &surfaceDesc);
return new WindowData
{
Surface = surface
};
}
private void DecideMainTextureFormat(WindowData mainWindow)
{
WGPUSurfaceCapabilities surfaceCaps;
var res = wgpuSurfaceGetCapabilities(mainWindow.Surface, _wgpuAdapter, &surfaceCaps);
if (res != WGPUStatus.WGPUStatus_Success)
throw new RhiException("wgpuSurfaceGetCapabilities failed");
var modes = new Span<WGPUPresentMode>(surfaceCaps.presentModes, (int)surfaceCaps.presentModeCount);
_availPresentModes = modes.ToArray();
_sawmill.Debug($"Available present modes: {string.Join(", ", _availPresentModes)}");
var formats = new Span<WGPUTextureFormat>(surfaceCaps.formats, (int)surfaceCaps.formatCount);
var found = false;
foreach (var format in formats)
{
if (format == WGPUTextureFormat.WGPUTextureFormat_BGRA8UnormSrgb ||
format == WGPUTextureFormat.WGPUTextureFormat_RGBA8UnormSrgb)
{
found = true;
_mainTextureFormat = ToRhiFormat(format);
break;
}
}
_sawmill.Debug($"Available surface formats: {string.Join(", ", formats.ToArray())}");
if (!found)
throw new RhiException("Unable to find suitable surface format for main window!");
_sawmill.Debug($"Preferred surface format is {_mainTextureFormat}");
wgpuSurfaceCapabilitiesFreeMembers(surfaceCaps);
}
private void ConfigureSurface(WindowData window, Vector2i size, bool vsync)
{
var swapChainDesc = new WGPUSurfaceConfiguration
{
format = ValidateTextureFormat(_mainTextureFormat),
width = (uint)size.X,
height = (uint)size.Y,
usage = WGPUTextureUsage_RenderAttachment,
presentMode = WGPUPresentMode.WGPUPresentMode_Fifo,
device = _wgpuDevice
};
if (!vsync)
{
if (_availPresentModes.Contains(WGPUPresentMode.WGPUPresentMode_Immediate))
swapChainDesc.presentMode = WGPUPresentMode.WGPUPresentMode_Immediate;
else if (_availPresentModes.Contains(WGPUPresentMode.WGPUPresentMode_Mailbox))
swapChainDesc.presentMode = WGPUPresentMode.WGPUPresentMode_Mailbox;
}
wgpuSurfaceConfigure(window.Surface, &swapChainDesc);
_sawmill.Verbose("WebGPU Surface reconfigured!");
}
internal override WindowData WindowCreated(in RhiWindowSurfaceParams surfaceParams, Vector2i size, bool vsync)
{
var windowData = CreateSurfaceForWindow(in surfaceParams);
ConfigureSurface(windowData, size, vsync);
return windowData;
}
internal override void WindowDestroy(WindowData reg)
{
wgpuSurfaceUnconfigure(reg.Surface);
wgpuSurfaceRelease(reg.Surface);
}
internal override void WindowRecreateSwapchain(WindowData reg, Vector2i size, bool vsyncEnabled)
{
ConfigureSurface(reg, size, vsyncEnabled);
}
internal override void WindowPresent(WindowData reg)
{
// TODO: Safety
wgpuSurfacePresent(reg.Surface);
}
}