WebGPU renders again

This commit is contained in:
PJB3005
2025-10-07 23:44:04 +02:00
parent b6a5300f81
commit 91650fb4fb
36 changed files with 394 additions and 901 deletions

View File

@@ -7,7 +7,7 @@ struct UniformConstants {
// Group 1: parameters that change infrequently in a draw pass.
struct UniformView {
projViewMatrix: mat3x2f,
projViewMatrix: mat2x3f,
screenPixelSize: vec2f
}
@@ -35,7 +35,7 @@ struct VertexOutput {
@vertex
fn vs_main(input: VertexInput) -> VertexOutput {
var transformed = View.projViewMatrix * vec3(input.position, 1.0);
var transformed = vec3(input.position, 1.0) * View.projViewMatrix;
transformed += 1.0;
transformed /= View.screenPixelSize * 2.0;

View File

@@ -30,7 +30,7 @@ public abstract partial class RhiBase
/// </summary>
internal abstract void WindowRecreateSwapchain(RhiWebGpu.WindowData reg, Vector2i size);
internal abstract RhiTexture CreateTextureViewForWindow(RhiWebGpu.WindowData reg);
internal abstract RhiTexture GetSurfaceTextureForWindow(RhiWebGpu.WindowData reg);
internal abstract void WindowPresent(RhiWebGpu.WindowData reg);
//

View File

@@ -1,25 +1,34 @@
using System.Numerics;
using System.Runtime.InteropServices;
namespace Robust.Client.Graphics.Rhi;
/// <summary>
/// Equivalent to a WGSL <c>mat3x2f</c>.
/// Equivalent to a WGSL <c>mat2x3f</c>.
/// </summary>
/// <remarks>
/// This matrix is columnar and 3 columns, 2 rows. This is different from the rest of the engine and .NET.
/// This matrix is columnar and 2 columns, 3 rows. This is equivalent to .NET's <see cref="Matrix3x2"/>!
/// </remarks>
public struct ShaderMat3x2F
[StructLayout(LayoutKind.Explicit)]
public struct ShaderMat2x3F
{
[FieldOffset(0)]
public float M11;
public float M12;
[FieldOffset(4)]
public float M21;
public float M22;
[FieldOffset(8)]
public float M31;
[FieldOffset(16)]
public float M12;
[FieldOffset(20)]
public float M22;
[FieldOffset(24)]
public float M32;
public static ShaderMat3x2F Transpose(in Matrix3x2 matrix)
public static ShaderMat2x3F FromMatrix(in Matrix3x2 matrix)
{
var ret = default(ShaderMat3x2F);
var ret = default(ShaderMat2x3F);
ret.M11 = matrix.M11;
ret.M12 = matrix.M12;
ret.M21 = matrix.M21;

View File

@@ -589,37 +589,47 @@ public record struct RhiVertexAttribute(RhiVertexFormat Format, ulong Offset, ui
public enum RhiVertexFormat : byte
{
Undefined = 0x00000000,
Uint8x2 = 0x00000001,
Uint8x4 = 0x00000002,
Sint8x2 = 0x00000003,
Sint8x4 = 0x00000004,
Unorm8x2 = 0x00000005,
Unorm8x4 = 0x00000006,
Snorm8x2 = 0x00000007,
Snorm8x4 = 0x00000008,
Uint16x2 = 0x00000009,
Uint16x4 = 0x0000000A,
Sint16x2 = 0x0000000B,
Sint16x4 = 0x0000000C,
Unorm16x2 = 0x0000000D,
Unorm16x4 = 0x0000000E,
Snorm16x2 = 0x0000000F,
Snorm16x4 = 0x00000010,
Float16x2 = 0x00000011,
Float16x4 = 0x00000012,
Float32 = 0x00000013,
Float32x2 = 0x00000014,
Float32x3 = 0x00000015,
Float32x4 = 0x00000016,
Uint32 = 0x00000017,
Uint32x2 = 0x00000018,
Uint32x3 = 0x00000019,
Uint32x4 = 0x0000001A,
Sint32 = 0x0000001B,
Sint32x2 = 0x0000001C,
Sint32x3 = 0x0000001D,
Sint32x4 = 0x0000001E,
Uint8 = 0x00000001,
Uint8x2 = 0x00000002,
Uint8x4 = 0x00000003,
Sint8 = 0x00000004,
Sint8x2 = 0x00000005,
Sint8x4 = 0x00000006,
Unorm8 = 0x00000007,
Unorm8x2 = 0x00000008,
Unorm8x4 = 0x00000009,
Snorm8 = 0x0000000A,
Snorm8x2 = 0x0000000B,
Snorm8x4 = 0x0000000C,
Uint16 = 0x0000000D,
Uint16x2 = 0x0000000E,
Uint16x4 = 0x0000000F,
Sint16 = 0x00000010,
Sint16x2 = 0x00000011,
Sint16x4 = 0x00000012,
Unorm16 = 0x00000013,
Unorm16x2 = 0x00000014,
Unorm16x4 = 0x00000015,
Snorm16 = 0x00000016,
Snorm16x2 = 0x00000017,
Snorm16x4 = 0x00000018,
Float16 = 0x00000019,
Float16x2 = 0x0000001A,
Float16x4 = 0x0000001B,
Float32 = 0x0000001C,
Float32x2 = 0x0000001D,
Float32x3 = 0x0000001E,
Float32x4 = 0x0000001F,
Uint32 = 0x00000020,
Uint32x2 = 0x00000021,
Uint32x3 = 0x00000022,
Uint32x4 = 0x00000023,
Sint32 = 0x00000024,
Sint32x2 = 0x00000025,
Sint32x3 = 0x00000026,
Sint32x4 = 0x00000027,
Unorm10_10_10_2 = 0x00000028,
Unorm8x4BGRA = 0x00000029,
Final
}
@@ -638,11 +648,11 @@ public record struct RhiPrimitiveState(
public enum RhiPrimitiveTopology : byte
{
PointList = 0x00000000,
LineList = 0x00000001,
LineStrip = 0x00000002,
TriangleList = 0x00000003,
TriangleStrip = 0x00000004,
PointList = 0x00000001,
LineList = 0x00000002,
LineStrip = 0x00000003,
TriangleList = 0x00000004,
TriangleStrip = 0x00000005,
Final
}
@@ -747,29 +757,31 @@ public record struct RhiBlendComponent(
public enum RhiBlendOperation : byte
{
Add = 0x00000000,
Subtract = 0x00000001,
ReverseSubtract = 0x00000002,
Min = 0x00000003,
Max = 0x00000004,
Undefined = 0x00000000,
Add = 0x00000001,
Subtract = 0x00000002,
ReverseSubtract = 0x00000003,
Min = 0x00000004,
Max = 0x00000005,
Final
}
public enum RhiBlendFactor : byte
{
Zero = 0x00000000,
One = 0x00000001,
Src = 0x00000002,
OneMinusSrc = 0x00000003,
SrcAlpha = 0x00000004,
OneMinusSrcAlpha = 0x00000005,
Dst = 0x00000006,
OneMinusDst = 0x00000007,
DstAlpha = 0x00000008,
OneMinusDstAlpha = 0x00000009,
SrcAlphaSaturated = 0x0000000A,
Constant = 0x0000000B,
OneMinusConstant = 0x0000000C,
Undefined = 0x00000000,
Zero = 0x00000001,
One = 0x00000002,
Src = 0x00000003,
OneMinusSrc = 0x00000004,
SrcAlpha = 0x00000005,
OneMinusSrcAlpha = 0x00000006,
Dst = 0x00000007,
OneMinusDst = 0x00000008,
DstAlpha = 0x00000009,
OneMinusDstAlpha = 0x0000000A,
SrcAlphaSaturated = 0x0000000B,
Constant = 0x0000000C,
OneMinusConstant = 0x0000000D,
Final
}
@@ -847,23 +859,23 @@ public record struct RhiSamplerDescriptor(
public enum RhiAddressMode : byte
{
Repeat = 0,
MirrorRepeat = 1,
ClampToEdge = 2,
ClampToEdge = 1,
Repeat = 2,
MirrorRepeat = 3,
Final
}
public enum RhiFilterMode : byte
{
Nearest = 0,
Linear = 1,
Nearest = 1,
Linear = 2,
Final
}
public enum RhiMipmapFilterMode : byte
{
Nearest = 0,
Linear = 1,
Nearest = 1,
Linear = 2,
Final
}

View File

@@ -49,6 +49,7 @@ internal sealed unsafe partial class RhiWebGpu
pAttachment->clearValue = WgpuColor(attachment.ClearValue);
pAttachment->loadOp = (WGPULoadOp)attachment.LoadOp;
pAttachment->storeOp = (WGPUStoreOp)attachment.StoreOp;
pAttachment->depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
}
if (descriptor.DepthStencilAttachment is { } depthStencilAttachment)

View File

@@ -1,3 +1,4 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -85,12 +86,18 @@ internal sealed unsafe partial class RhiWebGpu
return format;
}
private static RhiTextureDimension ValidateTextureDimension(RhiTextureDimension dimension)
private static WGPUTextureDimension ValidateTextureDimension(RhiTextureDimension dimension)
{
if (dimension > RhiTextureDimension.Dim3D)
throw new ArgumentException($"Invalid {nameof(RhiTextureDimension)}");
return dimension;
return dimension switch
{
RhiTextureDimension.Dim1D => WGPUTextureDimension.WGPUTextureDimension_1D,
RhiTextureDimension.Dim2D => WGPUTextureDimension.WGPUTextureDimension_2D,
RhiTextureDimension.Dim3D => WGPUTextureDimension.WGPUTextureDimension_3D,
_ => throw new UnreachableException()
};
}
private static RhiTextureUsage ValidateTextureUsage(RhiTextureUsage usage)

View File

@@ -80,7 +80,9 @@ internal sealed unsafe partial class RhiWebGpu
{
ref var bufferLayout = ref pipelineDesc.vertex.buffers[i];
bufferLayout.arrayStride = buffers[i].ArrayStride;
bufferLayout.stepMode = (WGPUVertexStepMode)buffers[i].StepMode;
bufferLayout.stepMode = buffers[i].StepMode == RhiVertexStepMode.Instance
? WGPUVertexStepMode.WGPUVertexStepMode_Instance
: WGPUVertexStepMode.WGPUVertexStepMode_Vertex;
var attributes = buffers[i].Attributes;
bufferLayout.attributeCount = (uint)attributes.Length;

View File

@@ -10,10 +10,9 @@ internal sealed unsafe partial class RhiWebGpu
public override RhiTexture CreateTexture(in RhiTextureDescriptor descriptor)
{
var format = descriptor.Format;
var dimension = descriptor.Dimension;
var usage = descriptor.Usage;
ValidateTextureFormat(format);
ValidateTextureDimension(dimension);
var dimension = ValidateTextureDimension(descriptor.Dimension);
ValidateTextureUsage(usage);
// TODO: Copy to stackalloc instead.
@@ -36,7 +35,7 @@ internal sealed unsafe partial class RhiWebGpu
{
sampleCount = descriptor.SampleCount,
mipLevelCount = descriptor.MipLevelCount,
dimension = (WGPUTextureDimension) dimension,
dimension = dimension,
format = (WGPUTextureFormat) format,
label = new WGPUStringView
{
@@ -112,7 +111,7 @@ internal sealed unsafe partial class RhiWebGpu
_textureViewRegistry.Remove(textureView.Handle);
}
internal override RhiTexture CreateTextureViewForWindow(WindowData reg)
internal override RhiTexture GetSurfaceTextureForWindow(WindowData reg)
{
// TODO: Thread safety

View File

@@ -89,10 +89,11 @@ internal sealed unsafe partial class RhiWebGpu
var swapChainDesc = new WGPUSurfaceConfiguration
{
format = format,
height = (uint)size.X,
width = (uint)size.Y,
width = (uint)size.X,
height = (uint)size.Y,
usage = WGPUTextureUsage_RenderAttachment,
presentMode = WGPUPresentMode.WGPUPresentMode_Fifo
presentMode = WGPUPresentMode.WGPUPresentMode_Fifo,
device = _wgpuDevice
};
wgpuSurfaceConfigure(window.Surface, &swapChainDesc);

View File

@@ -0,0 +1,21 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Robust.Client.Interop.RobustNative;
internal static class DllMap
{
#pragma warning disable CA2255
[ModuleInitializer]
#pragma warning restore CA2255
public static void Initializer()
{
if (Environment.GetEnvironmentVariable("ROBUST_NATIVE_PATH") is not { } nativePath)
return;
NativeLibrary.SetDllImportResolver(
typeof(DllMap).Assembly,
(_, _, _) => NativeLibrary.Load(nativePath));
}
}

View File

@@ -4,4 +4,5 @@ internal static partial class Wgpu
{
public static readonly nuint WGPU_STRLEN = nuint.MaxValue;
public const ulong WGPU_WHOLE_SIZE = ulong.MaxValue;
public const uint WGPU_DEPTH_SLICE_UNDEFINED = uint.MaxValue;
}

View File

@@ -111,10 +111,7 @@ namespace Robust.Client.Graphics.Clyde
if (!reg.IsVisible) // Only send this for open windows
return;
// var loaded = RtToLoaded(reg.RenderTarget);
// loaded.Size = reg.FramebufferSize;
Rhi.WindowRecreateSwapchain(reg);
reg.NeedSurfaceReconfigure = true;
var eventArgs = new WindowResizedEventArgs(
oldSize,

View File

@@ -50,7 +50,7 @@ namespace Robust.Client.Graphics.Clyde
if (string.IsNullOrEmpty(splashTex))
return;
var backbuffer = _mainWindow!.CurSwapchainView!;
var backbuffer = _mainWindow!.CurSurfaceTextureView!;
var size = _mainWindow!.FramebufferSize;
@@ -182,7 +182,7 @@ namespace Robust.Client.Graphics.Clyde
public void RenderNow(IRenderTarget renderTarget, Action<IRenderHandle> callback)
{
ClearRenderState();
// ClearRenderState();
_renderHandle.RenderInRenderTarget(
renderTarget,

View File

@@ -603,6 +603,7 @@ namespace Robust.Client.Graphics.Clyde
return true;
}
*/
private sealed class LightCapacityComparer : IComparer<(PointLightComponent light, Vector2 pos, float distanceSquared, Angle rot)>
{
@@ -626,6 +627,8 @@ namespace Robust.Client.Graphics.Clyde
}
}
/*
private (int count, Box2 expandedBounds) GetLightsToRender(
MapId map,
in Box2Rotated worldBounds,
@@ -676,6 +679,7 @@ namespace Robust.Client.Graphics.Clyde
return (state.count, expandedBounds);
}
*/
/// <inheritdoc/>
[Pure]
@@ -685,6 +689,18 @@ namespace Robust.Client.Graphics.Clyde
MapLightComponent.DefaultColor;
}
public void BlurRenderTarget(
IClydeViewport viewport,
IRenderTarget target,
IRenderTarget blurBuffer,
IEye eye,
float multiplier)
{
throw new NotImplementedException();
}
/*
/// <inheritdoc/>
public void BlurRenderTarget(IClydeViewport viewport, IRenderTarget target, IRenderTarget blurBuffer, IEye eye, float multiplier)
{

View File

@@ -5,7 +5,6 @@ using Robust.Client.GameObjects;
using Robust.Client.Graphics.Rhi;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Vector2 = Robust.Shared.Maths.Vector2;
using Robust.Shared.Graphics;
namespace Robust.Client.Graphics.Clyde
@@ -38,13 +37,12 @@ namespace Robust.Client.Graphics.Clyde
public void SetModelTransform(in Matrix3x2 matrix)
{
matrix.Transpose(out var transposed);
_spriteBatch.SetModelTransform((Matrix3x2)transposed);
_spriteBatch.SetModelTransform(matrix);
}
public Matrix3x2 GetModelTransform()
{
return _clyde.DrawGetModelTransform();
return _spriteBatch.GetModelTransform();
}
public void SetProjView(in Matrix3x2 proj, in Matrix3x2 view)
@@ -145,7 +143,7 @@ namespace Robust.Client.Graphics.Clyde
if (loaded.IsWindow)
{
targetTexture = loaded.Window!.CurSwapchainView!;
targetTexture = loaded.Window!.CurSurfaceTextureView!;
targetSize = loaded.Window!.FramebufferSize;
}
else
@@ -284,9 +282,10 @@ namespace Robust.Client.Graphics.Clyde
public ShaderInstance? GetShader()
{
return _clyde._queuedShaderInstance == _clyde._defaultShader
? null
: _clyde._queuedShaderInstance;
throw new NotImplementedException();
// return _clyde._queuedShaderInstance == _clyde._defaultShader
// ? null
// : _clyde._queuedShaderInstance;
}
public void Viewport(Box2i viewport)

View File

@@ -22,7 +22,7 @@ namespace Robust.Client.Graphics.Clyde
public IRenderTexture CreateLightRenderTarget(Vector2i size, string? name = null, bool depthStencil = true)
{
var lightMapColorFormat = _hasGLFloatFramebuffers
var lightMapColorFormat = true // _hasGLFloatFramebuffers
? RTCF.R11FG11FB10F
: RTCF.Rgba8;
var lightMapSampleParameters = new TextureSampleParameters { Filter = true };
@@ -109,13 +109,12 @@ namespace Robust.Client.Graphics.Clyde
ColorFormat = format.ColorFormat,
DepthStencilTexture = depthStencilTexture,
DepthSencilTextureView = depthStencilTextureView,
MemoryPressure = pressure,
MemoryPressure = 0, // pressure,
SampleParameters = sampleParameters,
Instance = new WeakReference<RenderTargetBase>(renderTarget),
Name = name,
};
var renderTarget = new RenderTexture(size, textureObject, this, handle);
_renderTargets.Add(handle, data);
return renderTarget;
}
@@ -171,6 +170,7 @@ namespace Robust.Client.Graphics.Clyde
{
public bool IsWindow;
public WindowReg? Window;
public string? Name;
public Vector2i Size;
public bool IsSrgb;
@@ -186,6 +186,11 @@ namespace Robust.Client.Graphics.Clyde
// Depth/stencil attachment.
public RhiTexture? DepthStencilTexture;
public RhiTextureView? DepthSencilTextureView;
public TextureSampleParameters? SampleParameters;
public required WeakReference<RenderTargetBase> Instance;
public long MemoryPressure;
}
internal abstract class RenderTargetBase : IRenderTarget

View File

@@ -1,6 +1,7 @@
using System;
using Robust.Client.Graphics.Rhi;
using Robust.Client.Graphics.Rhi.WebGpu;
using Robust.Client.Interop.RobustNative.Webgpu;
using Robust.Shared;
using Robust.Shared.Utility;
using RhiBase = Robust.Client.Graphics.Rhi.RhiBase;
@@ -26,10 +27,13 @@ internal sealed partial class Clyde
};
Rhi.Init(new RhiBase.RhiInitParams
{
Backends = _cfg.GetCVar(CVars.DisplayWgpuBackends),
PowerPreference = (RhiPowerPreference)_cfg.GetCVar(CVars.DisplayGpuPowerPreference)
});
{
Backends = _cfg.GetCVar(CVars.DisplayWgpuBackends),
PowerPreference = (RhiPowerPreference)_cfg.GetCVar(CVars.DisplayGpuPowerPreference),
MainWindowSize = _mainWindow!.FramebufferSize,
MainWindowSurfaceParams = _mainWindow.SurfaceParams
},
out _mainWindow.RhiWebGpuData);
}
private void AcquireSwapchainTextures()
@@ -41,13 +45,29 @@ internal sealed partial class Clyde
foreach (var window in _windows)
{
window.CurSwapchainView?.Dispose();
window.CurSwapchainView = Rhi.CreateTextureViewForWindow(window);
window.CurSurfaceTexture?.Dispose();
window.CurSurfaceTextureView?.Dispose();
if (window.NeedSurfaceReconfigure)
{
Rhi.WindowRecreateSwapchain(window.RhiWebGpuData!, window.FramebufferSize);
window.NeedSurfaceReconfigure = false;
}
window.CurSurfaceTexture = Rhi.GetSurfaceTextureForWindow(window.RhiWebGpuData!);
window.CurSurfaceTextureView = window.CurSurfaceTexture.CreateView(new RhiTextureViewDescriptor
{
Dimension = RhiTextureViewDimension.Dim2D,
Format = RhiTextureFormat.BGRA8UnormSrgb,
ArrayLayerCount = 1,
MipLevelCount = 1,
Aspect = RhiTextureAspect.All,
});
var pass = encoder.BeginRenderPass(new RhiRenderPassDescriptor(
new[]
{
new RhiRenderPassColorAttachment(window.CurSwapchainView, RhiLoadOp.Clear, RhiStoreOp.Store)
new RhiRenderPassColorAttachment(window.CurSurfaceTextureView, RhiLoadOp.Clear, RhiStoreOp.Store)
}
));
@@ -61,13 +81,16 @@ internal sealed partial class Clyde
{
foreach (var window in _windows)
{
if (window.CurSwapchainView == null)
if (window.CurSurfaceTexture == null)
return;
window.CurSwapchainView.Dispose();
window.CurSwapchainView = null;
window.CurSurfaceTexture.Dispose();
window.CurSurfaceTexture = null;
Rhi.WindowPresent(window);
window.CurSurfaceTextureView!.Dispose();
window.CurSurfaceTextureView = null;
Rhi.WindowPresent(window.RhiWebGpuData!);
}
}
}

View File

@@ -1,15 +1,12 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Robust.Client.Graphics.Rhi;
using Robust.Shared.Collections;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using RhiBase = Robust.Client.Graphics.Rhi.RhiBase;
using RVector2 = Robust.Shared.Maths.Vector2;
using RVector4 = Robust.Shared.Maths.Vector4;
using SVector2 = System.Numerics.Vector2;
using SVector4 = System.Numerics.Vector4;
namespace Robust.Client.Graphics.Clyde;
@@ -18,10 +15,10 @@ internal partial class Clyde
// Implementation of a sprite batch on the new RHI.
// Basically, the old rendering API.
private sealed class SpriteBatch
internal sealed class SpriteBatch
{
private const int VertexSize = 32;
private const int UniformPassSize = 32;
private const int UniformPassSize = 64;
private const uint BindGroup0 = 0;
private const uint BindGroup1 = 1;
@@ -83,7 +80,7 @@ internal partial class Clyde
var uniformPoolSize = MathHelper.CeilingPowerOfTwo(
UniformPassSize,
(int)_rhi.DeviceLimits.MinUniformBufferOffsetAlignment
Math.Max((int)_rhi.DeviceLimits.MinUniformBufferOffsetAlignment, UniformPassSize)
) * 20;
_uniformPassPool = new GpuExpansionBuffer(
@@ -118,7 +115,7 @@ internal partial class Clyde
new RhiBindGroupLayoutEntry(
0,
RhiShaderStage.Vertex | RhiShaderStage.Fragment,
new RhiBufferBindingLayout(MinBindingSize: 32)
new RhiBufferBindingLayout(MinBindingSize: UniformPassSize)
)
},
"SpriteBatch bind group 1 (view)"
@@ -216,8 +213,8 @@ internal partial class Clyde
uniformPass[0] = new UniformView
{
ProjViewMatrix = ShaderMat3x2F.Transpose(projView),
ScreenPixelSize = new SVector2(1f / size.X, 1f / size.Y)
ProjViewMatrix = ShaderMat2x3F.FromMatrix(projView),
ScreenPixelSize = new Vector2(1f / size.X, 1f / size.Y)
};
var rhiClearColor = clearColor == null ? new RhiColor(0, 0, 0, 1) : Color.FromSrgb(clearColor.Value);
@@ -279,7 +276,7 @@ internal partial class Clyde
Clear();
}
public void Draw(ClydeTexture texture, RVector2 position, Color color)
public void Draw(ClydeTexture texture, Vector2 position, Color color)
{
var textureHandle = texture.TextureId;
@@ -291,24 +288,24 @@ internal partial class Clyde
var width = texture.Width;
var height = texture.Height;
var bl = (SVector2)(position);
var br = (SVector2)(position + (width, 0));
var tr = (SVector2)(position + (width, height));
var tl = (SVector2)(position + (0, height));
var bl = (position);
var br = (position + new Vector2(width, 0));
var tr = (position + new Vector2(width, height));
var tl = (position + new Vector2(0, height));
var sBl = SVector2.Transform(bl, _modelTransform);
var sBr = SVector2.Transform(br, _modelTransform);
var sTl = SVector2.Transform(tl, _modelTransform);
var sTr = SVector2.Transform(tr, _modelTransform);
var sBl = Vector2.Transform(bl, _modelTransform);
var sBr = Vector2.Transform(br, _modelTransform);
var sTl = Vector2.Transform(tl, _modelTransform);
var sTr = Vector2.Transform(tr, _modelTransform);
var asColor = Unsafe.As<Color, SVector4>(ref color);
var asColor = Unsafe.As<Color, Vector4>(ref color);
vertices[0] = new Vertex2D(sBl, new SVector2(0, 1), asColor);
vertices[1] = new Vertex2D(sBr, new SVector2(1, 1), asColor);
vertices[2] = new Vertex2D(sTr, new SVector2(1, 0), asColor);
vertices[3] = new Vertex2D(sTr, new SVector2(1, 0), asColor);
vertices[4] = new Vertex2D(sTl, new SVector2(0, 0), asColor);
vertices[5] = new Vertex2D(sBl, new SVector2(0, 1), asColor);
vertices[0] = new Vertex2D(sBl, new Vector2(0, 1), asColor);
vertices[1] = new Vertex2D(sBr, new Vector2(1, 1), asColor);
vertices[2] = new Vertex2D(sTr, new Vector2(1, 0), asColor);
vertices[3] = new Vertex2D(sTr, new Vector2(1, 0), asColor);
vertices[4] = new Vertex2D(sTl, new Vector2(0, 0), asColor);
vertices[5] = new Vertex2D(sBl, new Vector2(0, 1), asColor);
_vertexStartIndex += 6;
_curBatchSize += 6;
@@ -316,7 +313,7 @@ internal partial class Clyde
public void Draw(
ClydeTexture texture,
RVector2 bl, RVector2 br, RVector2 tl, RVector2 tr,
Vector2 bl, Vector2 br, Vector2 tl, Vector2 tr,
in Color color,
in Box2 region)
{
@@ -327,18 +324,18 @@ internal partial class Clyde
var vertices = AllocateVertexSpace(6);
var asColor = Unsafe.As<Color, SVector4>(ref Unsafe.AsRef(color));
var asColor = Unsafe.As<Color, Vector4>(ref Unsafe.AsRef(color));
var sBl = SVector2.Transform((SVector2)bl, _modelTransform);
var sBr = SVector2.Transform((SVector2)br, _modelTransform);
var sTl = SVector2.Transform((SVector2)tl, _modelTransform);
var sTr = SVector2.Transform((SVector2)tr, _modelTransform);
var sBl = Vector2.Transform((Vector2)bl, _modelTransform);
var sBr = Vector2.Transform((Vector2)br, _modelTransform);
var sTl = Vector2.Transform((Vector2)tl, _modelTransform);
var sTr = Vector2.Transform((Vector2)tr, _modelTransform);
vertices[0] = new Vertex2D(sBl, (SVector2)region.BottomLeft, asColor);
vertices[1] = new Vertex2D(sBr, (SVector2)region.BottomRight, asColor);
vertices[2] = new Vertex2D(sTr, (SVector2)region.TopRight, asColor);
vertices[0] = new Vertex2D(sBl, (Vector2)region.BottomLeft, asColor);
vertices[1] = new Vertex2D(sBr, (Vector2)region.BottomRight, asColor);
vertices[2] = new Vertex2D(sTr, (Vector2)region.TopRight, asColor);
vertices[3] = vertices[2];
vertices[4] = new Vertex2D(sTl, (SVector2)region.TopLeft, asColor);
vertices[4] = new Vertex2D(sTl, (Vector2)region.TopLeft, asColor);
vertices[5] = vertices[0];
_vertexStartIndex += 6;
@@ -515,6 +512,11 @@ internal partial class Clyde
_modelTransform = matrix;
}
public Matrix3x2 GetModelTransform()
{
return _modelTransform;
}
private RhiBindGroup AllocTempBindGroup(in RhiBindGroupDescriptor descriptor)
{
var bindGroup = _rhi.CreateBindGroup(descriptor);
@@ -524,11 +526,11 @@ internal partial class Clyde
private struct Vertex2D
{
public SVector2 Position;
public SVector2 TexCoord;
public SVector4 Color;
public Vector2 Position;
public Vector2 TexCoord;
public Vector4 Color;
public Vertex2D(SVector2 position, SVector2 texCoord, SVector4 color)
public Vertex2D(Vector2 position, Vector2 texCoord, Vector4 color)
{
Position = position;
TexCoord = texCoord;
@@ -536,10 +538,13 @@ internal partial class Clyde
}
}
[StructLayout(LayoutKind.Explicit)]
private struct UniformView
{
public ShaderMat3x2F ProjViewMatrix;
public SVector2 ScreenPixelSize;
[FieldOffset(0)]
public ShaderMat2x3F ProjViewMatrix;
[FieldOffset(32)]
public Vector2 ScreenPixelSize;
}
[Flags]

View File

@@ -159,6 +159,7 @@ namespace Robust.Client.Graphics.Clyde
Height = height,
Format = format,
Name = name,
TextureInstance = new WeakReference<ClydeTexture>(instance),
};
_loadedTextures.Add(id, loaded);
@@ -609,6 +610,7 @@ namespace Robust.Client.Graphics.Clyde
public int Width;
public int Height;
public long MemoryPressure;
public RhiTextureFormat Format;
public string? Name;

View File

@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Robust.Client.Graphics.Rhi;
@@ -10,7 +9,6 @@ using Robust.Client.Graphics.Rhi.WebGpu;
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Shared;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
@@ -79,11 +77,6 @@ namespace Robust.Client.Graphics.Clyde
}
}
public uint? GetX11WindowId()
{
return _windowing?.WindowGetX11Id(_mainWindow!) ?? null;
}
private bool InitWindowing()
{
var iconPath = _cfg.GetCVar(CVars.DisplayWindowIconSet);
@@ -288,7 +281,7 @@ namespace Robust.Client.Graphics.Clyde
{
Size = reg.FramebufferSize,
IsWindow = true,
WindowId = reg.Id,
Window = reg,
IsSrgb = true,
Instance = new WeakReference<RenderTargetBase>(renderTarget),
});
@@ -296,7 +289,7 @@ namespace Robust.Client.Graphics.Clyde
reg.RenderTarget = renderTarget;
if (!isMain)
Rhi.WindowCreated(reg);
Rhi.WindowCreated(in reg.SurfaceParams, reg.FramebufferSize);
}
// Pass through result whether successful or not, caller handles it.
@@ -315,7 +308,7 @@ namespace Robust.Client.Graphics.Clyde
reg.IsDisposed = true;
Rhi.WindowDestroy(reg);
Rhi.WindowDestroy(reg.RhiWebGpuData!);
_windowing!.WindowDestroy(reg);
@@ -424,10 +417,14 @@ namespace Robust.Client.Graphics.Clyde
public IClydeWindow? Owner;
public RhiWebGpu.WindowData? RhiWebGpuData;
public RhiTextureView? CurSwapchainView;
public RhiTexture? CurSurfaceTexture;
public RhiTextureView? CurSurfaceTextureView;
public bool DisposeOnClose;
public bool NeedSurfaceReconfigure;
public RhiBase.RhiWindowSurfaceParams SurfaceParams;
public bool IsMainWindow;
public WindowHandle Handle = default!;
public RenderWindow RenderTarget = default!;
@@ -529,8 +526,6 @@ namespace Robust.Client.Graphics.Clyde
_clyde._windowing!.TextInputStop(Reg);
}
public nint? WindowsHWnd => _clyde._windowing!.WindowGetWin32Window(Reg);
}
private sealed class MonitorHandle : IClydeMonitor

View File

@@ -19,6 +19,8 @@ using Robust.Shared.Maths;
using Robust.Shared.Profiling;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Robust.Client.Graphics.Clyde
{
/// <summary>
@@ -26,7 +28,6 @@ namespace Robust.Client.Graphics.Clyde
/// </summary>
internal sealed partial class Clyde : IClydeInternal, IPostInjectInit, IEntityEventSubscriber
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IClydeTileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly ILightManager _lightManager = default!;
[Dependency] private readonly ILogManager _logManager = default!;
@@ -56,6 +57,9 @@ namespace Robust.Client.Graphics.Clyde
private Thread? _gameThread;
private ISawmill _sawmillWin = default!;
private ISawmill _clydeSawmill = default!;
private bool _threadWindowApi;
public Clyde()
@@ -76,7 +80,7 @@ namespace Robust.Client.Graphics.Clyde
_proto.PrototypesReloaded += OnProtoReload;
_cfg.OnValueChanged(CVars.DisplayVSync, VSyncChanged, true);
_cfg.OnValueChanged(CVars.DisplayVSync, b => VsyncEnabled = b, true);
_cfg.OnValueChanged(CVars.DisplayWindowMode, WindowModeChanged, true);
/*
_cfg.OnValueChanged(CVars.LightResolutionScale, LightResolutionScaleChanged, true);
@@ -189,9 +193,9 @@ namespace Robust.Client.Graphics.Clyde
public void RegisterGridEcsEvents()
{
_entityManager.EventBus.SubscribeEvent<TileChangedEvent>(EventSource.Local, this, _updateTileMapOnUpdate);
_entityManager.EventBus.SubscribeEvent<GridStartupEvent>(EventSource.Local, this, _updateOnGridCreated);
_entityManager.EventBus.SubscribeEvent<GridRemovalEvent>(EventSource.Local, this, _updateOnGridRemoved);
// _entityManager.EventBus.SubscribeEvent<TileChangedEvent>(EventSource.Local, this, _updateTileMapOnUpdate);
// _entityManager.EventBus.SubscribeEvent<GridStartupEvent>(EventSource.Local, this, _updateOnGridCreated);
// _entityManager.EventBus.SubscribeEvent<GridRemovalEvent>(EventSource.Local, this, _updateOnGridRemoved);
}
public void ShutdownGridEcsEvents()

View File

@@ -41,12 +41,6 @@ namespace Robust.Client.Graphics.Clyde
void WindowSetSize(WindowReg window, Vector2i size);
void WindowSetVisible(WindowReg window, bool visible);
void WindowRequestAttention(WindowReg window);
void WindowSwapBuffers(WindowReg window);
uint? WindowGetX11Id(WindowReg window);
nint? WindowGetX11Display(WindowReg window);
nint? WindowGetMetalLayer(WindowReg window);
HWND WindowGetWin32Window(WindowReg window);
HINSTANCE WindowGetWin32Instance(WindowReg window);
// Keyboard
string? KeyGetName(Keyboard.Key key);

View File

@@ -2,16 +2,12 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Robust.Client.Graphics.Rhi;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using SDL3;
using TerraFX.Interop.Windows;
using TerraFX.Interop.Xlib;
#if WINDOWS
using BOOL = TerraFX.Interop.Windows.BOOL;
using Windows = TerraFX.Interop.Windows.Windows;
#endif
using GLAttr = SDL3.SDL.SDL_GLAttr;
using X11Window = TerraFX.Interop.Xlib.Window;
namespace Robust.Client.Graphics.Clyde;
@@ -23,24 +19,14 @@ internal partial class Clyde
private int _nextWindowId = 1;
public (WindowReg?, string? error) WindowCreate(
GLContextSpec? spec,
WindowCreateParameters parameters,
WindowReg? share,
WindowReg? owner)
{
nint shareWindow = 0;
nint shareContext = 0;
if (share is Sdl3WindowReg shareReg)
{
shareWindow = shareReg.Sdl3Window;
shareContext = shareReg.GlContext;
}
nint ownerPtr = 0;
if (owner is Sdl3WindowReg ownerReg)
ownerPtr = ownerReg.Sdl3Window;
var task = SharedWindowCreate(spec, parameters, shareWindow, shareContext, ownerPtr);
var task = SharedWindowCreate(parameters, ownerPtr);
// Block the main thread (to avoid stuff like texture uploads being problematic).
WaitWindowCreate(task);
@@ -68,10 +54,7 @@ internal partial class Clyde
}
private Task<Sdl3WindowCreateResult> SharedWindowCreate(
GLContextSpec? glSpec,
WindowCreateParameters parameters,
nint shareWindow,
nint shareContext,
nint owner)
{
//
@@ -93,10 +76,7 @@ internal partial class Clyde
var tcs = new TaskCompletionSource<Sdl3WindowCreateResult>();
SendCmd(new CmdWinCreate
{
GLSpec = glSpec,
Parameters = parameters,
ShareWindow = shareWindow,
ShareContext = shareContext,
OwnerWindow = owner,
Tcs = tcs
});
@@ -110,12 +90,7 @@ internal partial class Clyde
private void WinThreadWinCreate(CmdWinCreate cmd)
{
var (window, context) = CreateSdl3WindowForRenderer(
cmd.GLSpec,
cmd.Parameters,
cmd.ShareWindow,
cmd.ShareContext,
cmd.OwnerWindow);
var window = CreateSdl3WindowForRenderer(cmd.Parameters, cmd.OwnerWindow);
if (window == 0)
{
@@ -135,7 +110,7 @@ internal partial class Clyde
// * it'd not be synchronized to other incoming window events correctly which might be icky.
// So we send the TCS back to the game thread
// which processes events in the correct order and has better control of stuff during init.
var reg = WinThreadSetupWindow(window, context);
var reg = WinThreadSetupWindow(window);
SendEvent(new EventWindowCreate
{
@@ -152,11 +127,8 @@ internal partial class Clyde
#endif
}
private (nint window, nint context) CreateSdl3WindowForRenderer(
GLContextSpec? spec,
private nint CreateSdl3WindowForRenderer(
WindowCreateParameters parameters,
nint shareWindow,
nint shareContext,
nint ownerWindow)
{
var createProps = SDL.SDL_CreateProperties();
@@ -164,55 +136,6 @@ internal partial class Clyde
SDL.SDL_SetBooleanProperty(createProps, SDL.SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, true);
SDL.SDL_SetBooleanProperty(createProps, SDL.SDL_PROP_WINDOW_CREATE_HIGH_PIXEL_DENSITY_BOOLEAN, true);
if (spec is { } s)
{
SDL.SDL_SetBooleanProperty(createProps, SDL.SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_RED_SIZE, 8);
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_GREEN_SIZE, 8);
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_BLUE_SIZE, 8);
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_ALPHA_SIZE, 8);
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_STENCIL_SIZE, 8);
SDL.SDL_GL_SetAttribute(
GLAttr.SDL_GL_FRAMEBUFFER_SRGB_CAPABLE,
s.Profile == GLContextProfile.Es ? 0 : 1);
int ctxFlags = 0;
#if DEBUG
ctxFlags |= SDL.SDL_GL_CONTEXT_DEBUG_FLAG;
#endif
if (s.Profile == GLContextProfile.Core)
ctxFlags |= SDL.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG;
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_CONTEXT_FLAGS, (int)ctxFlags);
if (shareContext != 0)
{
SDL.SDL_GL_MakeCurrent(shareWindow, shareContext);
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
}
else
{
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 0);
}
var profile = s.Profile switch
{
GLContextProfile.Compatibility => SDL.SDL_GL_CONTEXT_PROFILE_COMPATIBILITY,
GLContextProfile.Core => SDL.SDL_GL_CONTEXT_PROFILE_CORE,
GLContextProfile.Es => SDL.SDL_GL_CONTEXT_PROFILE_ES,
_ => SDL.SDL_GL_CONTEXT_PROFILE_COMPATIBILITY,
};
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_CONTEXT_PROFILE_MASK, profile);
SDL.SDL_SetHint(SDL.SDL_HINT_OPENGL_ES_DRIVER, s.CreationApi == GLContextCreationApi.Egl ? "1" : "0");
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_CONTEXT_MAJOR_VERSION, s.Major);
SDL.SDL_GL_SetAttribute(GLAttr.SDL_GL_CONTEXT_MINOR_VERSION, s.Minor);
if (s.CreationApi == GLContextCreationApi.Egl)
WsiShared.EnsureEglAvailable();
}
if (parameters.Fullscreen)
SDL.SDL_SetBooleanProperty(createProps, SDL.SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
@@ -251,13 +174,6 @@ internal partial class Clyde
if (window == 0)
return default;
nint glContext = SDL.SDL_GL_CreateContext(window);
if (glContext == 0)
{
SDL.SDL_DestroyWindow(window);
return default;
}
if ((parameters.Styles & OSWindowStyles.NoTitleOptions) != 0)
{
var props = SDL.SDL_GetWindowProperties(window);
@@ -295,44 +211,24 @@ internal partial class Clyde
// TODO: Monitors, window maximize.
// Make sure window thread doesn't keep hold of the GL context.
SDL.SDL_GL_MakeCurrent(IntPtr.Zero, IntPtr.Zero);
if (parameters.Visible)
SDL.SDL_ShowWindow(window);
return (window, glContext);
return window;
}
private Sdl3WindowReg WinThreadSetupWindow(nint window, nint context)
private Sdl3WindowReg WinThreadSetupWindow(nint window)
{
var reg = new Sdl3WindowReg
{
Sdl3Window = window,
GlContext = context,
WindowId = SDL.SDL_GetWindowID(window),
Id = new WindowId(_nextWindowId++)
};
var handle = new WindowHandle(_clyde, reg);
reg.Handle = handle;
var windowProps = SDL.SDL_GetWindowProperties(window);
switch (_videoDriver)
{
case SdlVideoDriver.Windows:
reg.WindowsHwnd = SDL.SDL_GetPointerProperty(
windowProps,
SDL.SDL_PROP_WINDOW_WIN32_HWND_POINTER,
0);
break;
case SdlVideoDriver.X11:
reg.X11Display = SDL.SDL_GetPointerProperty(
windowProps,
SDL.SDL_PROP_WINDOW_X11_DISPLAY_POINTER,
0);
reg.X11Id = (uint)SDL.SDL_GetNumberProperty(windowProps, SDL.SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
break;
}
reg.SurfaceParams = GetSurfaceParams(window);
AssignWindowIconToWindow(window);
@@ -461,95 +357,6 @@ internal partial class Clyde
_sawmill.Error("Failed to flash window: {error}", SDL.SDL_GetError());
}
public unsafe void WindowSwapBuffers(WindowReg window)
{
var reg = (Sdl3WindowReg)window;
var windowPtr = WinPtr(reg);
#if WINDOWS
// On Windows, SwapBuffers does not correctly sync to the DWM compositor.
// This means OpenGL vsync is effectively broken by default on Windows.
// We manually sync via DwmFlush(). GLFW does this automatically, SDL3 does not.
//
// Windows DwmFlush logic partly taken from:
// https://github.com/love2d/love/blob/5175b0d1b599ea4c7b929f6b4282dd379fa116b8/src/modules/window/sdl/Window.cpp#L1018
// https://github.com/glfw/glfw/blob/d3ede7b6847b66cf30b067214b2b4b126d4c729b/src/wgl_context.c#L321-L340
// See also: https://github.com/libsdl-org/SDL/issues/5797
var dwmFlush = false;
var swapInterval = 0;
if (!reg.Fullscreen && reg.SwapInterval > 0)
{
BOOL compositing;
// 6.2 is Windows 8
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfoexw
if (OperatingSystem.IsWindowsVersionAtLeast(6, 2)
|| Windows.SUCCEEDED(Windows.DwmIsCompositionEnabled(&compositing)) && compositing)
{
var curCtx = SDL.SDL_GL_GetCurrentContext();
var curWin = SDL.SDL_GL_GetCurrentWindow();
if (curCtx != reg.GlContext || curWin != reg.Sdl3Window)
throw new InvalidOperationException("Window context must be current!");
SDL.SDL_GL_SetSwapInterval(0);
dwmFlush = true;
swapInterval = reg.SwapInterval;
}
}
#endif
//_sawmill.Debug($"Swapping: {window.Id} @ {_clyde._gameTiming.CurFrame}");
SDL.SDL_GL_SwapWindow(windowPtr);
#if WINDOWS
if (dwmFlush)
{
var i = swapInterval;
while (i-- > 0)
{
Windows.DwmFlush();
}
SDL.SDL_GL_SetSwapInterval(swapInterval);
}
#endif
}
public uint? WindowGetX11Id(WindowReg window)
{
CheckWindowDisposed(window);
if (_videoDriver != SdlVideoDriver.X11)
return null;
var reg = (Sdl3WindowReg)window;
return reg.X11Id;
}
public nint? WindowGetX11Display(WindowReg window)
{
CheckWindowDisposed(window);
if (_videoDriver != SdlVideoDriver.X11)
return null;
var reg = (Sdl3WindowReg)window;
return reg.X11Display;
}
public nint? WindowGetWin32Window(WindowReg window)
{
CheckWindowDisposed(window);
if (_videoDriver != SdlVideoDriver.Windows)
return null;
var reg = (Sdl3WindowReg)window;
return reg.WindowsHwnd;
}
public void RunOnWindowThread(Action a)
{
SendCmd(new CmdRunAction { Action = a });
@@ -643,23 +450,56 @@ internal partial class Clyde
return null;
}
private unsafe RhiBase.RhiWindowSurfaceParams GetSurfaceParams(nint sdlWindow)
{
var props = SDL.SDL_GetWindowProperties(sdlWindow);
#if WINDOWS
return new RhiBase.RhiWindowSurfaceParams()
{
HInstance = (void*)SDL.SDL_GetPointerProperty(props, SDL.SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER, 0),
HWnd = (void*)SDL.SDL_GetPointerProperty(props, SDL.SDL_PROP_WINDOW_WIN32_HWND_POINTER, 0),
};
#elif LINUX
if (_videoDriver == SdlVideoDriver.Wayland)
{
return new RhiBase.RhiWindowSurfaceParams
{
X11Display = SDL.SDL_GetPointerProperty(windowProps, SDL.SDL_PROP_WINDOW_X11_DISPLAY_POINTER, 0),
X11Id = SDL.SDL_GetPointerProperty(windowProps, SDL.SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0),
};
}
else
{
Debug.Assert(_videoDriver == _sdlVideoDriver.X11);
return new RhiBase.RhiWindowSurfaceParams
{
Wayland = true,
WaylandDisplay = SDL.SDL_GetPointerProperty(
windowProps,
SDL.SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER,
0),
WaylandSurface = SDL.SDL_GetPointerProperty(
windowProps,
SDL.SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER,
0),
};
}
#else
throw new NotImplementedException();
#endif
}
private sealed class Sdl3WindowReg : WindowReg
{
public nint Sdl3Window;
public uint WindowId;
public nint GlContext;
#pragma warning disable CS0649
public bool Fullscreen;
#pragma warning restore CS0649
public int SwapInterval;
// Kept around to avoid it being GCd.
public CursorImpl? Cursor;
public nint WindowsHwnd;
public nint X11Display;
public uint X11Id;
}
}
}

View File

@@ -112,6 +112,7 @@ internal partial class Clyde
{
"windows" => SdlVideoDriver.Windows,
"x11" => SdlVideoDriver.X11,
"wayland" => SdlVideoDriver.Wayland,
_ => SdlVideoDriver.Other,
};
}
@@ -139,29 +140,6 @@ internal partial class Clyde
// Not currently used
}
public void GLMakeContextCurrent(WindowReg? reg)
{
SDL.SDLBool res;
if (reg is Sdl3WindowReg sdlReg)
res = SDL.SDL_GL_MakeCurrent(sdlReg.Sdl3Window, sdlReg.GlContext);
else
res = SDL.SDL_GL_MakeCurrent(IntPtr.Zero, IntPtr.Zero);
if (!res)
_sawmill.Error("SDL_GL_MakeCurrent failed: {error}", SDL.SDL_GetError());
}
public void GLSwapInterval(WindowReg reg, int interval)
{
((Sdl3WindowReg)reg).SwapInterval = interval;
SDL.SDL_GL_SetSwapInterval(interval);
}
public unsafe void* GLGetProcAddress(string procName)
{
return (void*) SDL.SDL_GL_GetProcAddress(procName);
}
public string GetDescription()
{
var version = SDL.SDL_GetVersion();
@@ -224,7 +202,8 @@ internal partial class Clyde
// These are the ones we need to be able to check against.
Other,
Windows,
X11
X11,
Wayland
}
}
}

View File

@@ -63,9 +63,6 @@ namespace Robust.Client.Graphics
void Shutdown();
/// <returns>Null if not running on X11.</returns>
uint? GetX11WindowId();
void RegisterGridEcsEvents();
void ShutdownGridEcsEvents();

View File

@@ -69,6 +69,5 @@ namespace Robust.Client.Graphics
public interface IClydeWindowInternal : IClydeWindow
{
nint? WindowsHWnd { get; }
}
}

View File

@@ -64,8 +64,6 @@ public abstract class Texture : IRsiStateLike
return this;
}
public abstract Color GetPixel(int x, int y);
public static Texture Transparent =>
IoCManager.Resolve<IClydeInternal>().GetStockTexture(ClydeStockTexture.Transparent);

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Robust.Client.Audio;
using Robust.Client.Graphics;
using Robust.Client.Utility;
using Robust.Shared;
@@ -23,7 +24,6 @@ namespace Robust.Client.ResourceManagement
internal partial class ResourceCache
{
[field: Dependency] public IClyde Clyde { get; } = default!;
[field: Dependency] public IAudioInternal ClydeAudio { get; } = default!;
[Dependency] private readonly IResourceManager _manager = default!;
[field: Dependency] public IFontManager FontManager { get; } = default!;
[Dependency] private readonly ILogManager _logManager = default!;
@@ -215,6 +215,7 @@ namespace Robust.Client.ResourceManagement
Array.Sort(atlasList, (b, a) => a.AtlasSheet.Height.CompareTo(b.AtlasSheet.Height));
var maxSize = _configurationManager.GetCVar(CVars.ResRSIAtlasSize);
maxSize = Math.Min((int)Clyde.Rhi.DeviceLimits.MaxTextureDimension2D, maxSize);
// THIS IS NOT GUARANTEED TO HAVE ANY PARTICULARLY LOGICAL ORDERING.
// E.G you could have atlas 1 RSIs appear *before* you're done seeing atlas 2 RSIs.

View File

@@ -45,9 +45,9 @@ namespace Robust.Client.UserInterface.CustomControls.DebugMonitorControls
var stats = _clydeInternal.DebugStats;
_textBuilder.AppendLine($@"RHI: {rhi.Description}
Adapter: {rhi.AdapterInfo.Name}
Vendor: {rhi.AdapterInfo.VendorName} ({rhi.AdapterInfo.VendorID})
Driver: {rhi.AdapterInfo.Driver}");
Adapter: {rhi.AdapterInfo.Device}
Vendor: {rhi.AdapterInfo.Vendor} ({rhi.AdapterInfo.VendorID})
Driver: {rhi.AdapterInfo.Description}");
_textBuilder.Append($"Windowing: {info.WindowingApi}\n");

View File

@@ -112,14 +112,14 @@ internal sealed partial class DevWindowTabRenderTargets : Control
if (loaded.Name != null)
AddColumnText(loaded.Name);
else if (loaded.WindowId != WindowId.Invalid)
AddColumnText(loaded.WindowId.ToString());
else if (loaded.Window != null)
AddColumnText(loaded.Window.Id.ToString());
else
AddColumnText(_loc.GetString("dev-window-tab-render-targets-value-null"));
AddColumnText(loaded.Size.ToString());
var type = loaded.ColorFormat.ToString();
if (loaded.DepthStencilHandle != default)
if (loaded.DepthStencilTexture != null)
type += "+DS";
AddColumnText(type);
AddColumnText(ByteHelpers.FormatBytes(loaded.MemoryPressure));

View File

@@ -32,9 +32,9 @@ public sealed partial class DevWindowTabRenderer : Control
var adapter = rhi.AdapterInfo;
Add("Adapter name", adapter.Name);
Add("Adapter vendor", $"{adapter.VendorName} ({adapter.VendorID})");
Add("Adapter driver", $"{adapter.Driver}");
Add("Adapter name", adapter.Device);
Add("Adapter vendor", $"{adapter.Vendor} ({adapter.VendorID})");
Add("Adapter driver", $"{adapter.Description}");
Add("Adapter architecture", $"{adapter.Architecture}");
Add("Adapter backend", $"{adapter.BackendType}");
Add("Adapter type", $"{adapter.AdapterType}");
@@ -70,7 +70,6 @@ public sealed partial class DevWindowTabRenderer : Control
Add("MaxBufferSize", limits.MaxBufferSize);
Add("MaxVertexAttributes", limits.MaxVertexAttributes);
Add("MaxVertexBufferArrayStride", limits.MaxVertexBufferArrayStride);
Add("MaxInterStageShaderComponents", limits.MaxInterStageShaderComponents);
Add("MaxInterStageShaderVariables", limits.MaxInterStageShaderVariables);
Add("MaxColorAttachments", limits.MaxColorAttachments);
Add("MaxColorAttachmentBytesPerSample", limits.MaxColorAttachmentBytesPerSample);

View File

@@ -92,7 +92,7 @@ internal sealed partial class DevWindowTabTextures : Control
SelectedTextureInfo.Text = _loc.GetString("dev-window-tab-textures-info",
("width", loaded.Width),
("height", loaded.Height),
("pixelType", loaded.TexturePixelType),
("pixelType", loaded.Format),
("srgb", loaded.IsSrgb),
("name", loaded.Name ?? ""),
("bytes", ByteHelpers.FormatBytes(loaded.MemoryPressure)));

View File

@@ -1,35 +1,15 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Robust.Client.Graphics;
using Robust.Shared.Console;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Utility;
namespace Robust.Client.UserInterface
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
[SuppressMessage("ReSharper", "IdentifierTypo")]
[SuppressMessage("ReSharper", "CommentTypo")]
[SuppressMessage("ReSharper", "StringLiteralTypo")]
internal sealed class FileDialogManager : IFileDialogManager, IPostInjectInit
internal sealed class FileDialogManager : IFileDialogManager
{
// Uses nativefiledialog to open the file dialogs cross platform.
// On Linux, if the kdialog command is found, it will be used instead.
// TODO: Should we maybe try to avoid running kdialog if the DE isn't KDE?
[Dependency] private readonly IClydeInternal _clyde = default!;
[Dependency] private readonly ILogManager _log = default!;
private ISawmill _sawmill = default!;
private bool _kDialogAvailable;
private bool _checkedKDialogAvailable;
public async Task<Stream?> OpenFile(
FileDialogFilters? filters = null,
@@ -47,7 +27,7 @@ namespace Robust.Client.UserInterface
if (_clyde.FileDialogImpl is { } clydeImpl)
name = await clydeImpl.OpenFile(filters);
else
name = await GetOpenFileName(filters);
throw new NotSupportedException();
if (name == null)
return null;
@@ -55,16 +35,6 @@ namespace Robust.Client.UserInterface
return File.Open(name, FileMode.Open, access, realShare);
}
private async Task<string?> GetOpenFileName(FileDialogFilters? filters)
{
if (await IsKDialogAvailable())
{
return await OpenFileKDialog(filters);
}
return await OpenFileNfd(filters);
}
public async Task<(Stream, bool)?> SaveFile(
FileDialogFilters? filters,
bool truncate = true,
@@ -81,7 +51,7 @@ namespace Robust.Client.UserInterface
if (_clyde.FileDialogImpl is { } clydeImpl)
name = await clydeImpl.SaveFile(filters);
else
name = await GetSaveFileName(filters);
throw new NotSupportedException();
if (name == null)
return null;
@@ -95,329 +65,6 @@ namespace Robust.Client.UserInterface
return (File.Open(name, FileMode.Create, access, share), false);
}
}
private async Task<string?> GetSaveFileName(FileDialogFilters? filters)
{
if (await IsKDialogAvailable())
{
return await SaveFileKDialog(filters);
}
return await SaveFileNfd(filters);
}
private unsafe Task<string?> OpenFileNfd(FileDialogFilters? filters)
{
// Have to run it in the thread pool to avoid blocking the main thread.
return RunAsyncMaybe(() =>
{
byte* outPath;
var filterPtr = FormatFiltersNfd(filters);
sw_nfdresult result;
try
{
result = sw_NFD_OpenDialog((byte*)filterPtr, null, &outPath);
}
finally
{
if (filterPtr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(filterPtr);
}
}
return HandleNfdResult(result, outPath);
});
}
private static IntPtr FormatFiltersNfd(FileDialogFilters? filters)
{
if (filters != null)
{
var filterString = string.Join(';', filters.Groups.Select(f => string.Join(',', f.Extensions)));
return Marshal.StringToCoTaskMemUTF8(filterString);
}
return IntPtr.Zero;
}
private unsafe Task<string?> SaveFileNfd(FileDialogFilters? filters)
{
// Have to run it in the thread pool to avoid blocking the main thread.
return RunAsyncMaybe(() =>
{
byte* outPath;
var filterPtr = FormatFiltersNfd(filters);
sw_nfdresult result;
try
{
result = sw_NFD_SaveDialog((byte*) filterPtr, null, &outPath);
}
finally
{
if (filterPtr != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(filterPtr);
}
}
return HandleNfdResult(result, outPath);
});
}
/*
private unsafe Task<string?> OpenFolderNfd()
{
// Have to run it in the thread pool to avoid blocking the main thread.
return RunAsyncMaybe(() =>
{
byte* outPath;
var result = sw_NFD_PickFolder(null, &outPath);
return HandleNfdResult(result, outPath);
});
}
*/
// ReSharper disable once MemberCanBeMadeStatic.Local
private Task<string?> RunAsyncMaybe(Func<string?> action)
{
if (OperatingSystem.IsMacOS())
{
// macOS seems pretty annoying about having the file dialog opened from the main windowing thread.
// So we are forced to execute this synchronously on the main windowing thread.
// nativefiledialog doesn't provide any form of async API, so this WILL lock up half the client.
var tcs = new TaskCompletionSource<string?>();
_clyde.RunOnWindowThread(() => tcs.SetResult(action()));
return tcs.Task;
}
else
{
// Luckily, GTK Linux and COM Windows are both happily threaded. Yay!
// * Actual attempts to have multiple file dialogs up at the same time, and the resulting crashes,
// have shown that at least for GTK+ (Linux), just because it can handle being on any thread doesn't mean it handle being on two at the same time.
// Testing system was Ubuntu 20.04.
// COM on Windows might handle this, but honestly, who exactly wants to risk it?
// In particular this could very well be an swnfd issue.
return Task.Run(() =>
{
lock (this)
{
return action();
}
});
}
}
private static unsafe string? HandleNfdResult(sw_nfdresult result, byte* outPath)
{
switch (result)
{
case sw_nfdresult.SW_NFD_ERROR:
var errPtr = sw_NFD_GetError();
throw new Exception(Marshal.PtrToStringUTF8((IntPtr) errPtr));
case sw_nfdresult.SW_NFD_OKAY:
var str = Marshal.PtrToStringUTF8((IntPtr) outPath)!;
sw_NFD_Free(outPath);
return str;
case sw_nfdresult.SW_NFD_CANCEL:
return null;
default:
throw new ArgumentOutOfRangeException();
}
}
private async Task CheckKDialogSupport()
{
var currentDesktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
if (currentDesktop == null || !currentDesktop.Contains("KDE"))
{
return;
}
try
{
var process = Process.Start(
new ProcessStartInfo
{
FileName = "kdialog",
Arguments = "--version",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
});
if (process == null)
{
_kDialogAvailable = false;
return;
}
await process.WaitForExitAsync();
_kDialogAvailable = process.ExitCode == 0;
if (_kDialogAvailable)
{
_sawmill.Debug("kdialog available.");
}
}
catch
{
_kDialogAvailable = false;
}
}
private Task<string?> OpenFileKDialog(FileDialogFilters? filters)
{
var filtersFormatted = FormatFiltersKDialog(filters);
return RunKDialog("--getopenfilename", Environment.GetEnvironmentVariable("HOME")!, filtersFormatted);
}
private static string FormatFiltersKDialog(FileDialogFilters? filters)
{
var sb = new StringBuilder();
if (filters != null && filters.Groups.Count != 0)
{
var first = true;
foreach (var group in filters.Groups)
{
if (!first)
{
sb.Append('|');
}
foreach (var extension in @group.Extensions)
{
sb.AppendFormat(".{0} ", extension);
}
sb.Append('(');
foreach (var extension in @group.Extensions)
{
sb.AppendFormat("*.{0} ", extension);
}
sb.Append(')');
first = false;
}
sb.Append("| All Files (*)");
}
return sb.ToString();
}
private Task<string?> SaveFileKDialog(FileDialogFilters? filters)
{
var filtersFormatted = FormatFiltersKDialog(filters);
return RunKDialog("--getsavefilename", Environment.GetEnvironmentVariable("HOME")!, filtersFormatted);
}
/*
private Task<string?> OpenFolderKDialog()
{
return RunKDialog("--getexistingdirectory");
}
*/
private async Task<string?> RunKDialog(params string[] options)
{
var startInfo = new ProcessStartInfo
{
FileName = "kdialog",
RedirectStandardOutput = true,
UseShellExecute = false,
StandardOutputEncoding = EncodingHelpers.UTF8
};
foreach (var option in options)
{
startInfo.ArgumentList.Add(option);
}
if (_clyde.GetX11WindowId() is { } id)
{
startInfo.ArgumentList.Add("--attach");
startInfo.ArgumentList.Add(id.ToString());
}
var process = Process.Start(startInfo);
DebugTools.AssertNotNull(process);
await process!.WaitForExitAsync();
// Cancel hit.
if (process.ExitCode == 1)
{
return null;
}
return (await process.StandardOutput.ReadLineAsync())?.Trim();
}
private async Task<bool> IsKDialogAvailable()
{
if (!OperatingSystem.IsLinux())
return false;
if (!_checkedKDialogAvailable)
{
await CheckKDialogSupport();
_checkedKDialogAvailable = true;
}
return _kDialogAvailable;
}
[DllImport("swnfd.dll")]
private static extern unsafe byte* sw_NFD_GetError();
[DllImport("swnfd.dll")]
private static extern unsafe sw_nfdresult
sw_NFD_OpenDialog(byte* filterList, byte* defaultPath, byte** outPath);
[DllImport("swnfd.dll")]
private static extern unsafe sw_nfdresult
sw_NFD_SaveDialog(byte* filterList, byte* defaultPath, byte** outPath);
/*
[DllImport("swnfd.dll")]
private static extern unsafe sw_nfdresult
sw_NFD_PickFolder(byte* defaultPath, byte** outPath);
*/
[DllImport("swnfd.dll")]
private static extern unsafe void sw_NFD_Free(void* ptr);
public void PostInject()
{
_sawmill = _log.GetSawmill("filedialog");
}
private enum sw_nfdresult
{
SW_NFD_ERROR,
SW_NFD_OKAY,
SW_NFD_CANCEL,
}
}
public sealed class OpenFileCommand : LocalizedCommands

View File

@@ -4,3 +4,4 @@
[assembly: InternalsVisibleTo("Robust.Client.Graphics.Rhi")]
[assembly: InternalsVisibleTo("Robust.Server")]
[assembly: InternalsVisibleTo("Robust.Shared")]
[assembly: InternalsVisibleTo("Robust.UnitTesting")]

View File

@@ -1385,7 +1385,7 @@ namespace Robust.Shared
/// the purpose of using an atlas if it gets too small.
/// </summary>
public static readonly CVarDef<int> ResRSIAtlasSize =
CVarDef.Create("res.rsi_atlas_size", 12288, CVar.CLIENTONLY);
CVarDef.Create("res.rsi_atlas_size", 16384, CVar.CLIENTONLY);
// TODO: Currently unimplemented.
/// <summary>

179
native/Cargo.lock generated
View File

@@ -78,7 +78,7 @@ version = "0.72.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
dependencies = [
"bitflags 2.9.4",
"bitflags",
"cexpr",
"clang-sys",
"itertools 0.13.0",
@@ -107,20 +107,11 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
dependencies = [
"serde",
]
[[package]]
name = "block"
@@ -211,8 +202,6 @@ version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
dependencies = [
"serde",
"termcolor",
"unicode-width",
]
@@ -227,9 +216,9 @@ dependencies = [
[[package]]
name = "core-foundation"
version = "0.9.4"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
dependencies = [
"core-foundation-sys",
"libc",
@@ -243,11 +232,11 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "core-graphics-types"
version = "0.1.3"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [
"bitflags 1.3.2",
"bitflags",
"core-foundation",
"libc",
]
@@ -363,6 +352,12 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foldhash"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "foreign-types"
version = "0.5.0"
@@ -444,7 +439,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
dependencies = [
"bitflags 2.9.4",
"bitflags",
"gpu-alloc-types",
]
@@ -454,7 +449,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
dependencies = [
"bitflags 2.9.4",
"bitflags",
]
[[package]]
@@ -475,7 +470,7 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca"
dependencies = [
"bitflags 2.9.4",
"bitflags",
"gpu-descriptor-types",
"hashbrown 0.15.5",
]
@@ -486,7 +481,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91"
dependencies = [
"bitflags 2.9.4",
"bitflags",
]
[[package]]
@@ -506,7 +501,7 @@ version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash",
"foldhash 0.1.5",
]
[[package]]
@@ -514,12 +509,9 @@ name = "hashbrown"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
dependencies = [
"foldhash 0.2.0",
]
[[package]]
name = "hexf-parse"
@@ -804,11 +796,11 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "metal"
version = "0.31.0"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e"
checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605"
dependencies = [
"bitflags 2.9.4",
"bitflags",
"block",
"core-graphics-types",
"foreign-types",
@@ -834,18 +826,21 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "naga"
version = "25.0.1"
source = "git+https://github.com/gfx-rs/wgpu?tag=v25.0.2#f35cf942af1a3bb6f48aa9185f4d2bcee809f814"
version = "27.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b2e757b11b47345d44e7760e45458339bc490463d9548cd8651c53ae523153"
dependencies = [
"arrayvec",
"bit-set",
"bitflags 2.9.4",
"bitflags",
"cfg-if",
"cfg_aliases",
"codespan-reporting",
"half",
"hashbrown 0.15.5",
"hashbrown 0.16.0",
"hexf-parse",
"indexmap",
"libm",
"log",
"num-traits",
"once_cell",
@@ -853,16 +848,15 @@ dependencies = [
"pp-rs",
"rustc-hash 1.1.0",
"spirv",
"strum",
"thiserror 2.0.17",
"unicode-ident",
]
[[package]]
name = "ndk-sys"
version = "0.5.0+25.2.9519653"
version = "0.6.0+11769913"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
dependencies = [
"jni-sys",
]
@@ -965,7 +959,6 @@ dependencies = [
"fixedbitset",
"hashbrown 0.15.5",
"indexmap",
"serde",
]
[[package]]
@@ -1056,7 +1049,7 @@ version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags 2.9.4",
"bitflags",
]
[[package]]
@@ -1158,36 +1151,6 @@ version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sha3"
version = "0.10.8"
@@ -1231,7 +1194,7 @@ version = "0.3.0+sdk-1.3.268.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
dependencies = [
"bitflags 2.9.4",
"bitflags",
]
[[package]]
@@ -1246,28 +1209,6 @@ dependencies = [
"precomputed-hash",
]
[[package]]
name = "strum"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "2.0.106"
@@ -1288,15 +1229,6 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.69"
@@ -1506,17 +1438,18 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "25.0.2"
source = "git+https://github.com/gfx-rs/wgpu?tag=v25.0.2#f35cf942af1a3bb6f48aa9185f4d2bcee809f814"
version = "27.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d654c0b6c6335edfca18c11bdaed964def641b8e9997d3a495a2ff4077c922"
dependencies = [
"arrayvec",
"bit-set",
"bit-vec",
"bitflags 2.9.4",
"bitflags",
"bytemuck",
"cfg_aliases",
"document-features",
"hashbrown 0.15.5",
"hashbrown 0.16.0",
"indexmap",
"log",
"naga",
@@ -1536,38 +1469,42 @@ dependencies = [
[[package]]
name = "wgpu-core-deps-apple"
version = "25.0.0"
source = "git+https://github.com/gfx-rs/wgpu?tag=v25.0.2#f35cf942af1a3bb6f48aa9185f4d2bcee809f814"
version = "27.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0772ae958e9be0c729561d5e3fd9a19679bcdfb945b8b1a1969d9bfe8056d233"
dependencies = [
"wgpu-hal",
]
[[package]]
name = "wgpu-core-deps-emscripten"
version = "25.0.0"
source = "git+https://github.com/gfx-rs/wgpu?tag=v25.0.2#f35cf942af1a3bb6f48aa9185f4d2bcee809f814"
version = "27.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06ac3444a95b0813ecfd81ddb2774b66220b264b3e2031152a4a29fda4da6b5"
dependencies = [
"wgpu-hal",
]
[[package]]
name = "wgpu-core-deps-windows-linux-android"
version = "25.0.0"
source = "git+https://github.com/gfx-rs/wgpu?tag=v25.0.2#f35cf942af1a3bb6f48aa9185f4d2bcee809f814"
version = "27.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71197027d61a71748e4120f05a9242b2ad142e3c01f8c1b47707945a879a03c3"
dependencies = [
"wgpu-hal",
]
[[package]]
name = "wgpu-hal"
version = "25.0.2"
source = "git+https://github.com/gfx-rs/wgpu?tag=v25.0.2#f35cf942af1a3bb6f48aa9185f4d2bcee809f814"
version = "27.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2618a2d6b8a5964ecc1ac32a5db56cb3b1e518725fcd773fd9a782e023453f2b"
dependencies = [
"android_system_properties",
"arrayvec",
"ash",
"bit-set",
"bitflags 2.9.4",
"bitflags",
"block",
"bytemuck",
"cfg-if",
@@ -1578,7 +1515,7 @@ dependencies = [
"gpu-alloc",
"gpu-allocator",
"gpu-descriptor",
"hashbrown 0.15.5",
"hashbrown 0.16.0",
"js-sys",
"khronos-egl",
"libc",
@@ -1588,6 +1525,7 @@ dependencies = [
"naga",
"ndk-sys",
"objc",
"once_cell",
"ordered-float",
"parking_lot",
"profiling",
@@ -1608,7 +1546,7 @@ name = "wgpu-native"
version = "0.0.0"
dependencies = [
"bindgen",
"bitflags 2.9.4",
"bitflags",
"log",
"naga",
"parking_lot",
@@ -1623,10 +1561,11 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "25.0.0"
source = "git+https://github.com/gfx-rs/wgpu?tag=v25.0.2#f35cf942af1a3bb6f48aa9185f4d2bcee809f814"
version = "27.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb"
dependencies = [
"bitflags 2.9.4",
"bitflags",
"bytemuck",
"js-sys",
"log",