Skip to content

Commit 04eb130

Browse files
authored
Merge pull request #15 from FModel/fix/igpu
iGPU fixes
2 parents 8e90ea6 + 8f0ff3b commit 04eb130

23 files changed

Lines changed: 159 additions & 104 deletions

Snooper/Core/Containers/Buffers/Buffer.cs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public abstract class Buffer<T>(BufferTarget target, BufferUsageHint usageHint,
3838
public int Count { get; private set; }
3939
public int Capacity { get; private set; }
4040

41-
private bool _bInitialized;
41+
protected bool IsAllocated;
4242
private readonly Dictionary<int, BufferAllocationMetadata> _allocations = new();
4343
private readonly SortedSet<FreeBlock> _freeBlocks = new(Comparer<FreeBlock>.Create((a, b) =>
4444
{
@@ -52,12 +52,12 @@ public abstract class Buffer<T>(BufferTarget target, BufferUsageHint usageHint,
5252

5353
public override void Generate()
5454
{
55-
if (_bInitialized)
55+
if (IsAllocated)
5656
throw new InvalidOperationException("Buffer is already initialized.");
5757

5858
GL.CreateBuffers(1, out uint handle);
5959
Handle = handle;
60-
_bInitialized = false;
60+
IsAllocated = false;
6161
}
6262

6363
public void Bind()
@@ -78,11 +78,11 @@ private void ResizeIfNeeded(int newSize, double factor = 1.5, bool copy = false)
7878
var oldCapacity = Capacity;
7979
Capacity = (int) Math.Max(Capacity * factor, newSize);
8080

81-
if (_bInitialized)
81+
if (IsAllocated)
8282
{
8383
Log.Warning("Resizing buffer {0} ({1}) from {2} to {3} (asked: {4}) (initialized!!!!!!)", Handle, PName, oldCapacity, Capacity, newSize);
8484

85-
_bInitialized = false;
85+
IsAllocated = false;
8686
if (copy)
8787
{
8888
var oldBuffer = Handle;
@@ -109,15 +109,15 @@ private void ResizeIfNeeded(int newSize, double factor = 1.5, bool copy = false)
109109

110110
public void Reallocate(int size)
111111
{
112-
_bInitialized = false;
112+
IsAllocated = false;
113113
Allocate(size);
114114
}
115115

116116
public void Allocate(uint size) => Allocate((int)size);
117117
public void Allocate(int size)
118118
{
119119
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(size);
120-
if (_bInitialized)
120+
if (IsAllocated)
121121
throw new InvalidOperationException("Buffer is already initialized. Use Update method to modify data.");
122122

123123
if (size > Capacity)
@@ -133,7 +133,7 @@ public void Allocate(int size)
133133
// _allocationIdCounter = 0;
134134
// _allocations.Clear();
135135
// _freeBlocks.Clear();
136-
_bInitialized = true;
136+
IsAllocated = true;
137137
}
138138

139139
public BufferAllocation Add(T data) => AddInternal([data]);
@@ -143,7 +143,7 @@ private BufferAllocation AddInternal(T[] data)
143143
var length = data.Length;
144144
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(length);
145145

146-
if (!_bInitialized)
146+
if (!IsAllocated)
147147
{
148148
Allocate(length);
149149
}
@@ -176,7 +176,7 @@ private void UpsertInternal(int index, T[] data)
176176
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(length);
177177
ArgumentOutOfRangeException.ThrowIfNegative(index);
178178

179-
if (!_bInitialized)
179+
if (!IsAllocated)
180180
{
181181
Allocate(index + length);
182182
}
@@ -196,7 +196,7 @@ private void UpsertInternal(int index, T[] data)
196196
public void Update(int allocationId, T[] data) => UpdateInternal(allocationId, data);
197197
private void UpdateInternal(int allocationId, T[] data, bool batched = false)
198198
{
199-
if (!_bInitialized)
199+
if (!IsAllocated)
200200
throw new InvalidOperationException("Buffer is not initialized. Use Add method to initialize it.");
201201

202202
if (!_allocations.TryGetValue(allocationId, out var metadata))
@@ -215,7 +215,7 @@ private void UpdateInternal(int allocationId, T[] data, bool batched = false)
215215
public void UpdateCustom<TCustom>(BufferAllocation allocation, TCustom data, int offset) where TCustom : unmanaged => UpdateCustomInternal(allocation.AllocationId, data, offset);
216216
private void UpdateCustomInternal<TCustom>(int allocationId, TCustom data, int offset) where TCustom : unmanaged
217217
{
218-
if (!_bInitialized)
218+
if (!IsAllocated)
219219
throw new InvalidOperationException("Buffer is not initialized. Use Add method to initialize it.");
220220

221221
if (!_allocations.TryGetValue(allocationId, out var metadata))
@@ -304,7 +304,7 @@ public BufferAllocation CopyFrom(Buffer<T> sourceBuffer, BufferAllocation source
304304
var length = sourceAllocation.Length;
305305
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(length);
306306

307-
if (!_bInitialized)
307+
if (!IsAllocated)
308308
{
309309
Allocate(length);
310310
}
@@ -326,7 +326,7 @@ public BufferAllocation CopyFrom(Buffer<T> sourceBuffer, BufferAllocation source
326326

327327
public void Clear()
328328
{
329-
if (!_bInitialized)
329+
if (!IsAllocated)
330330
throw new InvalidOperationException("Cannot clear a buffer that is not initialized.");
331331

332332
ClearStorage(0, TotalElements * Stride);

Snooper/Core/Containers/Buffers/ShaderStorageBuffer.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ public sealed class ShaderStorageBuffer<T>(BufferUsageHint usageHint = BufferUsa
1111

1212
public void Bind(uint index)
1313
{
14-
GL.BindBufferBase(BufferRangeTarget.ShaderStorageBuffer, index, Handle);
14+
// iGPUs don't like binding unallocated buffers, and unlike some other buffers, we never unbind SSBOs
15+
// silently skipping the bind leaves whatever another system bound at this index in place
16+
// that's too risky, so we unbind the slot instead so an unallocated buffer reads as out of range
17+
// TODO: we should properly unbind SSBOs, and skip if unallocated
18+
GL.BindBufferBase(BufferRangeTarget.ShaderStorageBuffer, index, IsAllocated ? Handle : 0);
1519
}
1620

1721
public void QueueUpdate(BufferAllocation allocation, T data) => _batcher.Add(allocation, data);

Snooper/Core/Containers/Programs/EmbeddedShader.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Reflection;
22
using OpenTK.Graphics.OpenGL4;
33
using Snooper.Core.Containers.Buffers;
4+
using Snooper.Core.Hardware;
45

56
namespace Snooper.Core.Containers.Programs;
67

@@ -25,7 +26,7 @@ protected override uint CompileShader(ShaderType type, string file)
2526
content = string.Join("\n", Defines.Select(d => $"#define {d}")) + "\n" + content;
2627
}
2728

28-
content = string.Join('\n', "#version 460 core", "", Bindings.GlslDefines, "", content);
29+
content = string.Join('\n', "#version 460 core", "", Bindings.GlslDefines, DeviceInfo.GlslDefines, content);
2930

3031
return base.CompileShader(type, content);
3132
}

Snooper/Core/Containers/Resources/GeometryPool.cs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
using System.Numerics;
2-
using CUE4Parse.UE4.Objects.Core.Misc;
1+
using CUE4Parse.UE4.Objects.Core.Misc;
32
using OpenTK.Graphics.OpenGL4;
43
using Snooper.Core.Containers.Buffers;
5-
using Snooper.Rendering.Components.Camera;
4+
using Snooper.Core.Hardware;
65
using Snooper.Rendering.Components.Descriptors;
76

87
namespace Snooper.Core.Containers.Resources;
@@ -18,6 +17,51 @@ public class GeometryHandle(uint firstIndex, uint baseVertex, BufferAllocation m
1817
public int OverrideLod { get; internal set; } = overrideLod;
1918
}
2019

20+
public readonly struct VertexArrayLayout
21+
{
22+
private readonly uint _vao;
23+
private readonly uint _vbo;
24+
private readonly int _stride;
25+
26+
public VertexArrayLayout(uint vao, uint vbo, int stride)
27+
{
28+
_vao = vao;
29+
_vbo = vbo;
30+
_stride = stride;
31+
32+
if (!DeviceInfo.IsIntel)
33+
{
34+
GL.VertexArrayVertexBuffer(vao, 0, vbo, 0, stride);
35+
}
36+
}
37+
38+
public VertexArrayLayout Float(uint location, int size, VertexAttribType type = VertexAttribType.Float, bool normalized = false, uint offset = 0)
39+
{
40+
GL.VertexArrayAttribFormat(_vao, location, size, type, normalized, DeviceInfo.IsIntel ? 0 : offset);
41+
return Enable(location, offset);
42+
}
43+
44+
public VertexArrayLayout Integer(uint location, int size, VertexAttribIType type = VertexAttribIType.UnsignedInt, uint offset = 0)
45+
{
46+
GL.VertexArrayAttribIFormat(_vao, location, size, type, DeviceInfo.IsIntel ? 0 : offset);
47+
return Enable(location, offset);
48+
}
49+
50+
private VertexArrayLayout Enable(uint location, uint offset)
51+
{
52+
var binding = 0u;
53+
if (DeviceInfo.IsIntel)
54+
{
55+
binding = location;
56+
GL.VertexArrayVertexBuffer(_vao, binding, _vbo, (nint)offset, _stride);
57+
}
58+
59+
GL.VertexArrayAttribBinding(_vao, location, binding);
60+
GL.EnableVertexArrayAttrib(_vao, location);
61+
return this;
62+
}
63+
}
64+
2165
public class GeometryPool<TVertex> : IMemoryDetailsProvider, IDisposable where TVertex : unmanaged
2266
{
2367
private readonly VertexArray _vao = new();
@@ -27,7 +71,7 @@ public class GeometryPool<TVertex> : IMemoryDetailsProvider, IDisposable where T
2771
private readonly CullingResources _culling = new();
2872

2973
private readonly Dictionary<FGuid, GeometryHandle> _cache = new();
30-
private Action<uint>? _vertexLayoutSetter;
74+
private Action<VertexArrayLayout>? _vertexLayoutSetter;
3175

3276
public void Generate()
3377
{
@@ -41,18 +85,16 @@ public void Generate()
4185
_vbo.OnHandleChanged += (_, _) => BindBuffersToVao();
4286
}
4387

44-
public void SetVertexLayout(Action<uint> setter)
88+
public void SetVertexLayout(Action<VertexArrayLayout> setter)
4589
{
4690
_vertexLayoutSetter = setter;
4791
BindBuffersToVao();
4892
}
4993

5094
private void BindBuffersToVao()
5195
{
52-
GL.VertexArrayVertexBuffer(_vao, 0, _vbo, 0, _vbo.Stride);
5396
GL.VertexArrayElementBuffer(_vao, _ebo);
54-
55-
_vertexLayoutSetter?.Invoke(_vao);
97+
_vertexLayoutSetter?.Invoke(new VertexArrayLayout(_vao, _vbo, _vbo.Stride));
5698
}
5799

58100
public void Allocate(AllocationCounts counts)

Snooper/Core/Containers/Resources/IndirectResources.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public void Generate()
4141
_materialData.Generate();
4242
}
4343

44-
public void SetVertexLayout(Action<uint> setter) => _geometry.SetVertexLayout(setter);
44+
public void SetVertexLayout(Action<VertexArrayLayout> setter) => _geometry.SetVertexLayout(setter);
4545

4646
public void Allocate(AllocationCounts counts)
4747
{

Snooper/Core/Hardware/DeviceInfo.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@ public class DeviceInfo
1010
public ExtensionSupport ExtensionSupport { get; } = new();
1111
public GpuMemoryInfo Memory { get; } = new();
1212

13+
public static bool IsIntel { get; private set; }
14+
public static string GlslDefines { get; private set; } = string.Empty;
15+
1316
public void Load()
1417
{
1518
Name = GL.GetString(StringName.Renderer);
1619
Vendor = GL.GetString(StringName.Vendor);
1720
MaxShaderStorageBufferBindings = GL.GetInteger(GetPName.MaxShaderStorageBufferBindings);
1821
ExtensionSupport.Load();
1922
Memory.Load(ExtensionSupport);
23+
24+
IsIntel = Vendor.Contains("Intel", StringComparison.OrdinalIgnoreCase);
25+
GlslDefines = IsIntel ? "#define BINDLESS_RAW_HANDLES\n" : string.Empty;
2026
}
2127
}

Snooper/Core/Managers/ActorManager.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ private void DequeueSystems(int limit = 0)
191191

192192
Systems.Add(system.Order, system);
193193
system.Load();
194+
195+
if (system is IResizable resizable)
196+
resizable.Resize(_width, _height); // resize right away for the screen-sized resources to get allocated (ClusteredLightSystem)
197+
194198
count++;
195199
}
196200
}
@@ -232,8 +236,13 @@ private void TrackBackgroundWork()
232236
}
233237
}
234238

239+
private int _width;
240+
private int _height;
235241
public virtual void Resize(int newWidth, int newHeight)
236242
{
243+
_width = newWidth;
244+
_height = newHeight;
245+
237246
foreach (var system in Systems.Values.OfType<IResizable>())
238247
system.Resize(newWidth, newHeight);
239248
}

Snooper/Rendering/Components/Mesh/MeshComponent.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace Snooper.Rendering.Components.Mesh;
2323
/// <summary>
2424
/// Packed vertex layout — 20 bytes total<br/>
2525
/// loc 0: uvec2 — pos.x|pos.y (half2), pos.z|0 (half2) [offset 0, 8 bytes]<br/>
26-
/// loc 1: uint — normal xyzw RGB10A2 SNorm [offset 8, 4 bytes]<br/>
26+
/// loc 1: uint — normal xyz RGB10A2 SNorm, w = basis sign [offset 8, 4 bytes]<br/>
2727
/// loc 2: uint — tangent xyz RGB10A2 SNorm, w = texLayer(0-3) [offset 12, 4 bytes]<br/>
2828
/// loc 3: uint — uv.x|uv.y (half2) [offset 16, 4 bytes]<br/>
2929
/// </summary>
@@ -43,10 +43,11 @@ private static uint PackHalf2(float x, float y)
4343
return hx | (hy << 16);
4444
}
4545

46-
private static uint PackRgb10A2Snorm(Vector4 v) => PackRgb10A2Snorm(v.X, v.Y, v.Z, Snorm10(v.W));
46+
private static uint PackRgb10A2Snorm(Vector4 v) => PackRgb10A2Snorm(v.X, v.Y, v.Z, Snorm2(v.W));
4747
private static uint PackRgb10A2Snorm(Vector3 v, uint texLayer) => PackRgb10A2Snorm(v.X, v.Y, v.Z, texLayer & 0x3u);
4848
private static uint PackRgb10A2Snorm(float x, float y, float z, uint w) => Snorm10(x) | (Snorm10(y) << 10) | (Snorm10(z) << 20) | (w << 30);
4949
private static uint Snorm10(float f) => (uint)(int)MathF.Round(Math.Clamp(f, -1f, 1f) * 511f) & 0x3FFu;
50+
private static uint Snorm2(float f) => f < 0f ? 3u : 1u;
5051
}
5152

5253
public unsafe struct PerMaterialMeshData : IPerMaterialData
@@ -189,7 +190,7 @@ public Geometry(MeshVertex[] vertices, uint[] indices, FColor[]? colors, FMeshUV
189190
{
190191
var vertex = vertices[i];
191192
var position = new Vector3(vertex.Position.X, vertex.Position.Z, vertex.Position.Y) * Settings.GlobalScale;
192-
var normal = new Vector4(vertex.Normal.X, vertex.Normal.Z, vertex.Normal.Y, vertex.Normal.W);
193+
var normal = new Vector4(vertex.Normal.X, vertex.Normal.Z, vertex.Normal.Y, -vertex.Normal.W);
193194
var tangent = new Vector3(vertex.Tangent.X, vertex.Tangent.Z, vertex.Tangent.Y);
194195
var texCoord = new Vector2(vertex.Uv.U, vertex.Uv.V);
195196
var texLayer = extraUvs != null ? (uint)Math.Floor(extraUvs[i].U) : 0u;
@@ -219,7 +220,7 @@ public Geometry(SkinnedMeshVertex[] vertices, uint[] indices, FColor[]? colors,
219220
{
220221
var vertex = vertices[i];
221222
var position = new Vector3(vertex.Position.X, vertex.Position.Z, vertex.Position.Y) * Settings.GlobalScale;
222-
var normal = new Vector4(vertex.Normal.X, vertex.Normal.Z, vertex.Normal.Y, vertex.Normal.W);
223+
var normal = new Vector4(vertex.Normal.X, vertex.Normal.Z, vertex.Normal.Y, -vertex.Normal.W);
223224
var tangent = new Vector3(vertex.Tangent.X, vertex.Tangent.Z, vertex.Tangent.Y);
224225
var texCoord = new Vector2(vertex.Uv.U, vertex.Uv.V);
225226
var texLayer = extraUvs != null ? (uint)Math.Floor(extraUvs[i].U) : 0u;

Snooper/Rendering/Managers/PostProcessor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public override void Generate()
9595
shader.SetUniform("ssao", 4);
9696
}
9797

98-
if (ctx.LightSystem is { IsEnabled: true } system)
98+
if (ctx.LightSystem is { IsEnabled: true, HasClusters: true } system)
9999
{
100100
system.BindForRendering();
101101
shader.SetUniform("useLighting", true);
@@ -191,7 +191,7 @@ public override void Generate()
191191
shader.SetUniform("uShowGrid", ctx.ShowGrid);
192192
shader.SetUniform("uMaxLightsPerCluster", ClusteredLightSystem.MaxLightsPerClusterLimit);
193193

194-
if (ctx.LightSystem is { IsEnabled: true } system)
194+
if (ctx.LightSystem is { IsEnabled: true, HasClusters: true } system)
195195
{
196196
system.BindForRendering();
197197
shader.SetUniform("uHasLights", true);

Snooper/Rendering/Systems/BillboardSystem.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,5 @@ public class BillboardSystem : PrimitiveSystem<Vector2, BillboardComponent, PerI
1616
[CommandBufferType.Transparent] = new EmbeddedShader("billboard")
1717
};
1818

19-
protected override Action<uint> VertexLayout { get; } = vao =>
20-
{
21-
GL.VertexArrayAttribFormat(vao, 0, 2, VertexAttribType.Float, false, 0);
22-
GL.EnableVertexArrayAttrib(vao, 0);
23-
GL.VertexArrayAttribBinding(vao, 0, 0);
24-
};
19+
protected override Action<VertexArrayLayout> VertexLayout { get; } = layout => layout.Float(0, 2);
2520
}

0 commit comments

Comments
 (0)