Skip to content

Commit c6c56ac

Browse files
[Rendering] WIP on SDLGPU Render Targets;
1 parent 47b9a40 commit c6c56ac

18 files changed

+300
-349
lines changed

Engine/Staple.Core/Rendering/RenderSystem/Backend/IRendererBackend.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ internal interface IRendererBackend
1111

1212
bool SupportsLinearColorSpace { get; }
1313

14+
TextureFormat? DepthStencilFormat { get; }
15+
1416
bool Initialize(RendererType renderer, bool debug, IRenderWindow window, RenderModeFlags renderFlags);
1517

1618
void Destroy();

Engine/Staple.Core/Rendering/RenderSystem/Backend/Impls/SDLGPU/Commands/SDLGPUBeginRenderPassCommand.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public void Update(IRendererBackend rendererBackend)
3636

3737
SDLGPUTexture depthTexture = null;
3838

39-
if (target == null)
39+
if (target == null || target.Disposed)
4040
{
4141
texture = backend.swapchainTexture;
4242
width = backend.swapchainWidth;
@@ -53,12 +53,17 @@ public void Update(IRendererBackend rendererBackend)
5353
}
5454
else
5555
{
56-
//TODO: texture
56+
if(target.ColorTextureCount > 0 &&
57+
target.colorTextures[0].impl is SDLGPUTexture t &&
58+
backend.TryGetTexture(t.handle, out var textureResource))
59+
{
60+
texture = textureResource.texture;
61+
}
5762

5863
width = target.width;
5964
height = target.height;
6065

61-
return;
66+
depthTexture = target.DepthTexture?.impl as SDLGPUTexture;
6267
}
6368

6469
if (texture == nint.Zero ||

Engine/Staple.Core/Rendering/RenderSystem/Backend/Impls/SDLGPU/SDLGPURendererBackend+Textures.cs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ internal static ResourceHandle<Texture> ReserveTextureResource(TextureResource[]
6565
resource.height = height;
6666
resource.format = format;
6767
resource.flags = flags;
68+
resource.length = 0;
6869

6970
return new ResourceHandle<Texture>((ushort)i);
7071
}
@@ -307,13 +308,66 @@ public ITexture CreateEmptyTexture(int width, int height, TextureFormat format,
307308

308309
var handle = ReserveTextureResource(textures, texture, width, height, format, flags);
309310

310-
if (handle.IsValid == false)
311+
if (handle.IsValid == false || TryGetTexture(handle, out var resource) == false)
311312
{
312313
SDL.SDL_ReleaseGPUTexture(device, texture);
313314

314315
return null;
315316
}
316317

318+
resource.length = width * height * format switch
319+
{
320+
TextureFormat.A8 => sizeof(byte),
321+
TextureFormat.R8 => sizeof(byte),
322+
TextureFormat.R8I => sizeof(byte),
323+
TextureFormat.R8U => sizeof(byte),
324+
TextureFormat.R8S => sizeof(byte),
325+
TextureFormat.R16 => sizeof(ushort),
326+
TextureFormat.R16I => sizeof(ushort),
327+
TextureFormat.R16U => sizeof(ushort),
328+
TextureFormat.R16F => sizeof(ushort),
329+
TextureFormat.R16S => sizeof(ushort),
330+
TextureFormat.R32I => sizeof(uint),
331+
TextureFormat.R32U => sizeof(uint),
332+
TextureFormat.R32F => sizeof(uint),
333+
TextureFormat.RG8 => sizeof(ushort),
334+
TextureFormat.RG8I => sizeof(ushort),
335+
TextureFormat.RG8U => sizeof(ushort),
336+
TextureFormat.RG8S => sizeof(ushort),
337+
TextureFormat.RG16 => sizeof(uint),
338+
TextureFormat.RG16I => sizeof(uint),
339+
TextureFormat.RG16U => sizeof(uint),
340+
TextureFormat.RG16F => sizeof(uint),
341+
TextureFormat.RG16S => sizeof(uint),
342+
TextureFormat.RG32I => sizeof(ulong),
343+
TextureFormat.RG32U => sizeof(ulong),
344+
TextureFormat.RG32F => sizeof(ulong),
345+
TextureFormat.BGRA8 => sizeof(uint),
346+
TextureFormat.RGBA8 => sizeof(uint),
347+
TextureFormat.RGBA8I => sizeof(uint),
348+
TextureFormat.RGBA8U => sizeof(uint),
349+
TextureFormat.RGBA8S => sizeof(uint),
350+
TextureFormat.RGBA16 => sizeof(ulong),
351+
TextureFormat.RGBA16I => sizeof(ulong),
352+
TextureFormat.RGBA16U => sizeof(ulong),
353+
TextureFormat.RGBA16F => sizeof(ulong),
354+
TextureFormat.RGBA16S => sizeof(ulong),
355+
TextureFormat.RGBA32I => sizeof(uint) * 4,
356+
TextureFormat.RGBA32U => sizeof(uint) * 4,
357+
TextureFormat.RGBA32F => sizeof(uint) * 4,
358+
TextureFormat.B5G6R5 => sizeof(ushort),
359+
TextureFormat.BGRA4 => sizeof(ushort),
360+
TextureFormat.BGR5A1 => sizeof(ushort),
361+
TextureFormat.RGB10A2 => sizeof(uint),
362+
TextureFormat.RG11B10F => sizeof(uint),
363+
TextureFormat.D16 => sizeof(ushort),
364+
TextureFormat.D24 => sizeof(uint),
365+
TextureFormat.D24S8 => sizeof(uint),
366+
TextureFormat.D32S8 => sizeof(uint) + sizeof(byte),
367+
TextureFormat.D32F => sizeof(uint),
368+
_ => 0,
369+
};
370+
317371
return new SDLGPUTexture(handle, width, height, format, flags, this);
318372
}
319373

Engine/Staple.Core/Rendering/RenderSystem/Backend/Impls/SDLGPU/SDLGPURendererBackend.cs

Lines changed: 136 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ public void CreateBuffers()
404404
private readonly BufferResource[] indexBuffers = new BufferResource[ushort.MaxValue - 1];
405405
private readonly Dictionary<VertexLayout, TransientEntry> transientBuffers = [];
406406
private readonly TextureResource[] textures = new TextureResource[ushort.MaxValue - 1];
407+
private RenderTarget currentRenderTarget;
407408

408409
private bool iteratingCommands = false;
409410
private int commandIndex;
@@ -711,9 +712,11 @@ public void EndFrame()
711712

712713
if (commandBuffer != nint.Zero)
713714
{
714-
var fences = new nint[SDL.SDL_SubmitGPUCommandBufferAndAcquireFence(commandBuffer)];
715+
var fences = new nint[1];
715716

716-
if(SDL.SDL_WaitForGPUFences(device, true, fences.AsSpan(), (uint)fences.Length) == false)
717+
fences[0] = SDL.SDL_SubmitGPUCommandBufferAndAcquireFence(commandBuffer);
718+
719+
if (SDL.SDL_WaitForGPUFences(device, true, fences.AsSpan(), (uint)fences.Length) == false)
717720
{
718721
Log.Error($"[SDL GPU] Failed to wait for GPU Fences: {SDL.SDL_GetError()}");
719722
}
@@ -756,6 +759,14 @@ public void EndFrame()
756759

757760
commandBuffer = nint.Zero;
758761
}
762+
763+
if(currentRenderTarget != null)
764+
{
765+
currentRenderTarget = null;
766+
767+
Screen.Width = window.Size.X;
768+
Screen.Height = window.Size.Y;
769+
}
759770
}
760771

761772
internal void UpdateDepthTextureIfNeeded(bool force)
@@ -888,13 +899,24 @@ internal void ResumeRenderPass()
888899
public void BeginRenderPass(RenderTarget target, CameraClearMode clear, Color clearColor, Vector4 viewport,
889900
in Matrix4x4 view, in Matrix4x4 projection)
890901
{
891-
viewData.renderTarget = target;
902+
viewData.renderTarget = currentRenderTarget = target;
892903
viewData.clearMode = clear;
893904
viewData.clearColor = clearColor;
894905
viewData.viewport = viewport;
895906
viewData.renderData.view = view;
896907
viewData.renderData.projection = projection;
897908

909+
if(target != null)
910+
{
911+
Screen.Width = target.width;
912+
Screen.Height = target.height;
913+
}
914+
else
915+
{
916+
Screen.Width = window.Size.X;
917+
Screen.Height = window.Size.Y;
918+
}
919+
898920
AddCommand(new SDLGPUBeginRenderPassCommand(target, clear, clearColor, viewport, view, projection));
899921
}
900922

@@ -1179,74 +1201,122 @@ instance.program is not SDLGPUShaderProgram shader ||
11791201
_ => throw new ArgumentOutOfRangeException(nameof(state.destinationBlend), "Invalid blend mode"),
11801202
};
11811203

1182-
var colorTargetDescription = new SDL.SDL_GPUColorTargetDescription()
1204+
var colorTargetDescriptions = new List<SDL.SDL_GPUColorTargetDescription>();
1205+
1206+
if(state.renderTarget == null || state.renderTarget.Disposed)
11831207
{
1184-
format = SDL.SDL_GetGPUSwapchainTextureFormat(device, window.window),
1185-
blend_state = new()
1208+
var colorTargetDescription = new SDL.SDL_GPUColorTargetDescription()
11861209
{
1187-
enable_blend = state.sourceBlend != BlendMode.Off && state.destinationBlend != BlendMode.Off,
1188-
color_blend_op = SDL.SDL_GPUBlendOp.SDL_GPU_BLENDOP_ADD,
1189-
alpha_blend_op = SDL.SDL_GPUBlendOp.SDL_GPU_BLENDOP_ADD,
1190-
src_color_blendfactor = sourceBlend,
1191-
src_alpha_blendfactor = sourceBlend,
1192-
dst_color_blendfactor = destinationBlend,
1193-
dst_alpha_blendfactor = destinationBlend,
1210+
format = SDL.SDL_GetGPUSwapchainTextureFormat(device, window.window),
1211+
blend_state = new()
1212+
{
1213+
enable_blend = state.sourceBlend != BlendMode.Off && state.destinationBlend != BlendMode.Off,
1214+
color_blend_op = SDL.SDL_GPUBlendOp.SDL_GPU_BLENDOP_ADD,
1215+
alpha_blend_op = SDL.SDL_GPUBlendOp.SDL_GPU_BLENDOP_ADD,
1216+
src_color_blendfactor = sourceBlend,
1217+
src_alpha_blendfactor = sourceBlend,
1218+
dst_color_blendfactor = destinationBlend,
1219+
dst_alpha_blendfactor = destinationBlend,
1220+
}
1221+
};
1222+
1223+
colorTargetDescriptions.Add(colorTargetDescription);
1224+
}
1225+
else
1226+
{
1227+
foreach(var texture in state.renderTarget.colorTextures)
1228+
{
1229+
if(texture.Disposed)
1230+
{
1231+
continue;
1232+
}
1233+
1234+
if(TryGetTextureFormat(texture.impl.Format, state.renderTarget.flags | TextureFlags.ColorTarget, out var textureFormat))
1235+
{
1236+
var colorTargetDescription = new SDL.SDL_GPUColorTargetDescription()
1237+
{
1238+
format = textureFormat,
1239+
blend_state = new()
1240+
{
1241+
enable_blend = state.sourceBlend != BlendMode.Off && state.destinationBlend != BlendMode.Off,
1242+
color_blend_op = SDL.SDL_GPUBlendOp.SDL_GPU_BLENDOP_ADD,
1243+
alpha_blend_op = SDL.SDL_GPUBlendOp.SDL_GPU_BLENDOP_ADD,
1244+
src_color_blendfactor = sourceBlend,
1245+
src_alpha_blendfactor = sourceBlend,
1246+
dst_color_blendfactor = destinationBlend,
1247+
dst_alpha_blendfactor = destinationBlend,
1248+
}
1249+
};
1250+
1251+
colorTargetDescriptions.Add(colorTargetDescription);
1252+
}
11941253
}
1195-
};
11961254

1197-
SDL.SDL_GPUVertexBufferDescription[] vertexDescriptions = [vertexDescription];
1255+
if(state.renderTarget.DepthTexture != null &&
1256+
state.renderTarget.DepthTexture.Disposed == false &&
1257+
TryGetTextureFormat(state.renderTarget.DepthTexture.impl.Format, state.renderTarget.flags | TextureFlags.DepthStencilTarget,
1258+
out var depthFormat))
1259+
{
1260+
sdlDepthFormat = depthFormat;
1261+
}
1262+
}
11981263

1199-
fixed (SDL.SDL_GPUVertexBufferDescription* descriptions = vertexDescriptions)
1264+
fixed(SDL.SDL_GPUColorTargetDescription *colorTargetDescriptionsPtr = CollectionsMarshal.AsSpan(colorTargetDescriptions))
12001265
{
1201-
var info = new SDL.SDL_GPUGraphicsPipelineCreateInfo()
1266+
SDL.SDL_GPUVertexBufferDescription[] vertexDescriptions = [vertexDescription];
1267+
1268+
fixed (SDL.SDL_GPUVertexBufferDescription* descriptions = vertexDescriptions)
12021269
{
1203-
primitive_type = state.primitiveType switch
1270+
var info = new SDL.SDL_GPUGraphicsPipelineCreateInfo()
12041271
{
1205-
MeshTopology.TriangleStrip => SDL.SDL_GPUPrimitiveType.SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP,
1206-
MeshTopology.Triangles => SDL.SDL_GPUPrimitiveType.SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
1207-
MeshTopology.Lines => SDL.SDL_GPUPrimitiveType.SDL_GPU_PRIMITIVETYPE_LINELIST,
1208-
MeshTopology.LineStrip => SDL.SDL_GPUPrimitiveType.SDL_GPU_PRIMITIVETYPE_LINESTRIP,
1209-
_ => throw new ArgumentOutOfRangeException("Invalid value for primitive type", nameof(state.primitiveType)),
1210-
},
1211-
vertex_shader = shader.vertex,
1212-
fragment_shader = shader.fragment,
1213-
rasterizer_state = new()
1214-
{
1215-
cull_mode = state.cull switch
1272+
primitive_type = state.primitiveType switch
12161273
{
1217-
CullingMode.None => SDL.SDL_GPUCullMode.SDL_GPU_CULLMODE_NONE,
1218-
CullingMode.Front => SDL.SDL_GPUCullMode.SDL_GPU_CULLMODE_FRONT,
1219-
CullingMode.Back => SDL.SDL_GPUCullMode.SDL_GPU_CULLMODE_BACK,
1220-
_ => throw new ArgumentOutOfRangeException("Invalid value for cull", nameof(state.cull)),
1274+
MeshTopology.TriangleStrip => SDL.SDL_GPUPrimitiveType.SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP,
1275+
MeshTopology.Triangles => SDL.SDL_GPUPrimitiveType.SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
1276+
MeshTopology.Lines => SDL.SDL_GPUPrimitiveType.SDL_GPU_PRIMITIVETYPE_LINELIST,
1277+
MeshTopology.LineStrip => SDL.SDL_GPUPrimitiveType.SDL_GPU_PRIMITIVETYPE_LINESTRIP,
1278+
_ => throw new ArgumentOutOfRangeException("Invalid value for primitive type", nameof(state.primitiveType)),
12211279
},
1222-
fill_mode = state.wireframe ? SDL.SDL_GPUFillMode.SDL_GPU_FILLMODE_LINE : SDL.SDL_GPUFillMode.SDL_GPU_FILLMODE_FILL,
1223-
front_face = SDL.SDL_GPUFrontFace.SDL_GPU_FRONTFACE_CLOCKWISE,
1224-
},
1225-
depth_stencil_state = new()
1226-
{
1227-
enable_depth_test = state.enableDepth,
1228-
enable_depth_write = state.depthWrite,
1229-
compare_op = SDL.SDL_GPUCompareOp.SDL_GPU_COMPAREOP_LESS_OR_EQUAL,
1230-
},
1231-
vertex_input_state = new()
1232-
{
1233-
num_vertex_buffers = 1,
1234-
num_vertex_attributes = (uint)attributesSpan.Length,
1235-
vertex_attributes = attributes,
1236-
vertex_buffer_descriptions = descriptions,
1237-
},
1238-
target_info = new()
1239-
{
1240-
num_color_targets = 1,
1241-
color_target_descriptions = &colorTargetDescription,
1242-
has_depth_stencil_target = state.enableDepth && depthStencilFormat.HasValue,
1243-
depth_stencil_format = sdlDepthFormat,
1244-
}
1245-
};
1280+
vertex_shader = shader.vertex,
1281+
fragment_shader = shader.fragment,
1282+
rasterizer_state = new()
1283+
{
1284+
cull_mode = state.cull switch
1285+
{
1286+
CullingMode.None => SDL.SDL_GPUCullMode.SDL_GPU_CULLMODE_NONE,
1287+
CullingMode.Front => SDL.SDL_GPUCullMode.SDL_GPU_CULLMODE_FRONT,
1288+
CullingMode.Back => SDL.SDL_GPUCullMode.SDL_GPU_CULLMODE_BACK,
1289+
_ => throw new ArgumentOutOfRangeException("Invalid value for cull", nameof(state.cull)),
1290+
},
1291+
fill_mode = state.wireframe ? SDL.SDL_GPUFillMode.SDL_GPU_FILLMODE_LINE : SDL.SDL_GPUFillMode.SDL_GPU_FILLMODE_FILL,
1292+
front_face = SDL.SDL_GPUFrontFace.SDL_GPU_FRONTFACE_CLOCKWISE,
1293+
},
1294+
depth_stencil_state = new()
1295+
{
1296+
enable_depth_test = state.enableDepth,
1297+
enable_depth_write = state.depthWrite,
1298+
compare_op = SDL.SDL_GPUCompareOp.SDL_GPU_COMPAREOP_LESS_OR_EQUAL,
1299+
},
1300+
vertex_input_state = new()
1301+
{
1302+
num_vertex_buffers = 1,
1303+
num_vertex_attributes = (uint)attributesSpan.Length,
1304+
vertex_attributes = attributes,
1305+
vertex_buffer_descriptions = descriptions,
1306+
},
1307+
target_info = new()
1308+
{
1309+
num_color_targets = (uint)colorTargetDescriptions.Count,
1310+
color_target_descriptions = colorTargetDescriptionsPtr,
1311+
has_depth_stencil_target = depthStencilFormat.HasValue,
1312+
depth_stencil_format = sdlDepthFormat,
1313+
}
1314+
};
12461315

1247-
pipeline = SDL.SDL_CreateGPUGraphicsPipeline(device, in info);
1316+
pipeline = SDL.SDL_CreateGPUGraphicsPipeline(device, in info);
12481317

1249-
graphicsPipelines.Add(hash, pipeline);
1318+
graphicsPipelines.Add(hash, pipeline);
1319+
}
12501320
}
12511321
}
12521322
}
@@ -1262,7 +1332,9 @@ instance.program is not SDLGPUShaderProgram shader ||
12621332

12631333
public void Render(RenderState state)
12641334
{
1265-
if(state.shader == null ||
1335+
state.renderTarget = currentRenderTarget;
1336+
1337+
if (state.shader == null ||
12661338
state.shaderVariant == null ||
12671339
state.shader.instances.TryGetValue(state.shaderVariant, out var instance) == false ||
12681340
instance.program is not SDLGPUShaderProgram shader ||
@@ -1343,6 +1415,8 @@ state.indexBuffer is not SDLGPUIndexBuffer index ||
13431415
public void RenderTransient<T>(Span<T> vertices, VertexLayout layout, Span<ushort> indices, RenderState state)
13441416
where T : unmanaged
13451417
{
1418+
state.renderTarget = currentRenderTarget;
1419+
13461420
if (layout is not SDLGPUVertexLayout vertexLayout ||
13471421
state.shaderVariant == null ||
13481422
state.shader == null ||
@@ -1484,6 +1558,8 @@ instance.program is not SDLGPUShaderProgram shader ||
14841558
public void RenderTransient<T>(Span<T> vertices, VertexLayout layout, Span<uint> indices, RenderState state)
14851559
where T : unmanaged
14861560
{
1561+
state.renderTarget = currentRenderTarget;
1562+
14871563
if (layout is not SDLGPUVertexLayout vertexLayout ||
14881564
state.shaderVariant == null ||
14891565
state.shader == null ||

0 commit comments

Comments
 (0)