mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Handle vsync and surface formats properly
This commit is contained in:
@@ -18,7 +18,7 @@ public abstract partial class RhiBase
|
||||
/// <remarks>
|
||||
/// Does not get called for the main window.
|
||||
/// </remarks>
|
||||
internal abstract RhiWebGpu.WindowData WindowCreated(in RhiWindowSurfaceParams surfaceParams, Vector2i size);
|
||||
internal abstract RhiWebGpu.WindowData WindowCreated(in RhiWindowSurfaceParams surfaceParams, Vector2i size, bool vsync);
|
||||
|
||||
/// <summary>
|
||||
/// A window is about to be destroyed by Clyde. Clean up resources for it.
|
||||
@@ -28,7 +28,7 @@ public abstract partial class RhiBase
|
||||
/// <summary>
|
||||
/// Recreate the native swap chain, in case it has become suboptimal (e.g. due to window resizing).
|
||||
/// </summary>
|
||||
internal abstract void WindowRecreateSwapchain(RhiWebGpu.WindowData reg, Vector2i size);
|
||||
internal abstract void WindowRecreateSwapchain(RhiWebGpu.WindowData reg, Vector2i size, bool vsyncEnabled);
|
||||
|
||||
internal abstract RhiTexture GetSurfaceTextureForWindow(RhiWebGpu.WindowData reg);
|
||||
internal abstract void WindowPresent(RhiWebGpu.WindowData reg);
|
||||
@@ -107,7 +107,6 @@ public abstract partial class RhiBase
|
||||
{
|
||||
public required string Backends;
|
||||
public required RhiPowerPreference PowerPreference;
|
||||
public required Vector2i MainWindowSize;
|
||||
public required RhiWindowSurfaceParams MainWindowSurfaceParams;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ public abstract partial class RhiBase
|
||||
public abstract RhiAdapterInfo AdapterInfo { get; }
|
||||
public abstract string Description { get; }
|
||||
|
||||
public abstract RhiTextureFormat MainTextureFormat { get; }
|
||||
|
||||
public abstract RhiTexture CreateTexture(in RhiTextureDescriptor descriptor);
|
||||
|
||||
public abstract RhiSampler CreateSampler(in RhiSamplerDescriptor descriptor);
|
||||
|
||||
@@ -76,12 +76,17 @@ internal sealed unsafe partial class RhiWebGpu
|
||||
return Encoding.UTF8.GetString(span);
|
||||
}
|
||||
|
||||
private static RhiTextureFormat ValidateTextureFormat(RhiTextureFormat format)
|
||||
private static RhiTextureFormat ToRhiFormat(WGPUTextureFormat format)
|
||||
{
|
||||
return (RhiTextureFormat)format;
|
||||
}
|
||||
|
||||
private static WGPUTextureFormat ValidateTextureFormat(RhiTextureFormat format)
|
||||
{
|
||||
if (format is 0 or >= RhiTextureFormat.Final)
|
||||
throw new ArgumentException($"Invalid {nameof(RhiTextureFormat)}");
|
||||
|
||||
return format;
|
||||
return (WGPUTextureFormat)format;
|
||||
}
|
||||
|
||||
private static WGPUTextureDimension ValidateTextureDimension(RhiTextureDimension dimension)
|
||||
|
||||
@@ -4,6 +4,11 @@ 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;
|
||||
@@ -68,15 +73,46 @@ internal sealed unsafe partial class RhiWebGpu
|
||||
};
|
||||
}
|
||||
|
||||
private void ConfigureSurface(WindowData window, Vector2i size)
|
||||
private void DecideMainTextureFormat(WindowData mainWindow)
|
||||
{
|
||||
// TODO: Safety
|
||||
var format = WGPUTextureFormat.WGPUTextureFormat_BGRA8UnormSrgb;
|
||||
_sawmill.Debug($"Preferred surface format is {format}");
|
||||
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 = format,
|
||||
format = ValidateTextureFormat(_mainTextureFormat),
|
||||
width = (uint)size.X,
|
||||
height = (uint)size.Y,
|
||||
usage = WGPUTextureUsage_RenderAttachment,
|
||||
@@ -84,15 +120,23 @@ internal sealed unsafe partial class RhiWebGpu
|
||||
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.Debug("WebGPU Surface created!");
|
||||
_sawmill.Verbose("WebGPU Surface reconfigured!");
|
||||
}
|
||||
|
||||
internal override WindowData WindowCreated(in RhiWindowSurfaceParams surfaceParams, Vector2i size)
|
||||
internal override WindowData WindowCreated(in RhiWindowSurfaceParams surfaceParams, Vector2i size, bool vsync)
|
||||
{
|
||||
var windowData = CreateSurfaceForWindow(in surfaceParams);
|
||||
ConfigureSurface(windowData, size);
|
||||
ConfigureSurface(windowData, size, vsync);
|
||||
return windowData;
|
||||
}
|
||||
|
||||
@@ -102,9 +146,9 @@ internal sealed unsafe partial class RhiWebGpu
|
||||
wgpuSurfaceRelease(reg.Surface);
|
||||
}
|
||||
|
||||
internal override void WindowRecreateSwapchain(WindowData reg, Vector2i size)
|
||||
internal override void WindowRecreateSwapchain(WindowData reg, Vector2i size, bool vsyncEnabled)
|
||||
{
|
||||
ConfigureSurface(reg, size);
|
||||
ConfigureSurface(reg, size, vsyncEnabled);
|
||||
}
|
||||
|
||||
internal override void WindowPresent(WindowData reg)
|
||||
|
||||
@@ -52,8 +52,7 @@ internal sealed unsafe partial class RhiWebGpu : RhiBase
|
||||
_sawmill.Debug("WebGPU main surface created!");
|
||||
|
||||
InitAdapterAndDevice(in initParams, windowData.Surface);
|
||||
|
||||
ConfigureSurface(windowData, initParams.MainWindowSize);
|
||||
DecideMainTextureFormat(windowData);
|
||||
}
|
||||
|
||||
private void InitInstance(in RhiInitParams initParams)
|
||||
|
||||
@@ -30,7 +30,6 @@ internal sealed partial class Clyde
|
||||
{
|
||||
Backends = _cfg.GetCVar(CVars.DisplayWgpuBackends),
|
||||
PowerPreference = (RhiPowerPreference)_cfg.GetCVar(CVars.DisplayGpuPowerPreference),
|
||||
MainWindowSize = _mainWindow!.FramebufferSize,
|
||||
MainWindowSurfaceParams = _mainWindow.SurfaceParams
|
||||
},
|
||||
out _mainWindow.RhiWebGpuData);
|
||||
@@ -50,7 +49,7 @@ internal sealed partial class Clyde
|
||||
|
||||
if (window.NeedSurfaceReconfigure)
|
||||
{
|
||||
Rhi.WindowRecreateSwapchain(window.RhiWebGpuData!, window.FramebufferSize);
|
||||
Rhi.WindowRecreateSwapchain(window.RhiWebGpuData!, window.FramebufferSize, VsyncEnabled);
|
||||
window.NeedSurfaceReconfigure = false;
|
||||
}
|
||||
|
||||
@@ -58,7 +57,7 @@ internal sealed partial class Clyde
|
||||
window.CurSurfaceTextureView = window.CurSurfaceTexture.CreateView(new RhiTextureViewDescriptor
|
||||
{
|
||||
Dimension = RhiTextureViewDimension.Dim2D,
|
||||
Format = RhiTextureFormat.BGRA8UnormSrgb,
|
||||
Format = Rhi.MainTextureFormat,
|
||||
ArrayLayerCount = 1,
|
||||
MipLevelCount = 1,
|
||||
Aspect = RhiTextureAspect.All,
|
||||
|
||||
@@ -166,7 +166,7 @@ internal partial class Clyde
|
||||
new[]
|
||||
{
|
||||
new RhiColorTargetState(
|
||||
RhiTextureFormat.BGRA8UnormSrgb,
|
||||
rhi.MainTextureFormat,
|
||||
new RhiBlendState(
|
||||
new RhiBlendComponent(
|
||||
RhiBlendOperation.Add,
|
||||
|
||||
@@ -289,7 +289,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
reg.RenderTarget = renderTarget;
|
||||
|
||||
if (!isMain)
|
||||
reg.RhiWebGpuData = Rhi.WindowCreated(in reg.SurfaceParams, reg.FramebufferSize);
|
||||
reg.RhiWebGpuData = Rhi.WindowCreated(in reg.SurfaceParams, reg.FramebufferSize, VsyncEnabled);
|
||||
}
|
||||
|
||||
// Pass through result whether successful or not, caller handles it.
|
||||
@@ -329,7 +329,15 @@ namespace Robust.Client.Graphics.Clyde
|
||||
public bool VsyncEnabled
|
||||
{
|
||||
get => _vSync;
|
||||
set => _vSync = value;
|
||||
set
|
||||
{
|
||||
_vSync = value;
|
||||
|
||||
foreach (var window in _windows)
|
||||
{
|
||||
window.NeedSurfaceReconfigure = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void WindowModeChanged(int mode)
|
||||
@@ -422,7 +430,7 @@ namespace Robust.Client.Graphics.Clyde
|
||||
|
||||
public bool DisposeOnClose;
|
||||
|
||||
public bool NeedSurfaceReconfigure;
|
||||
public bool NeedSurfaceReconfigure = true;
|
||||
public RhiBase.RhiWindowSurfaceParams SurfaceParams;
|
||||
|
||||
public bool IsMainWindow;
|
||||
|
||||
Reference in New Issue
Block a user