From fe6734d6dbf0b73549e279e2d8a972e94b6aa4a5 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Tue, 4 Jun 2024 16:32:41 -0700 Subject: [PATCH] refactor GraphicsDevice --- src/Graphics/GraphicsDevice.cs | 376 ++++++++++++++------------------- src/Window.cs | 1 + 2 files changed, 155 insertions(+), 222 deletions(-) diff --git a/src/Graphics/GraphicsDevice.cs b/src/Graphics/GraphicsDevice.cs index a52f222..3a863eb 100644 --- a/src/Graphics/GraphicsDevice.cs +++ b/src/Graphics/GraphicsDevice.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using MoonWorks.Video; -using RefreshCS; -using WellspringCS; +using SDL2; +using SDL2_gpuCS; namespace MoonWorks.Graphics { @@ -14,7 +14,7 @@ namespace MoonWorks.Graphics public class GraphicsDevice : IDisposable { public IntPtr Handle { get; } - public Backend Backend { get; } + public BackendFlags Backend { get; } public bool DebugMode { get; } private uint windowFlags; @@ -23,12 +23,11 @@ namespace MoonWorks.Graphics // Built-in video pipeline internal GraphicsPipeline VideoPipeline { get; } - // Built-in blit pipeline - internal GraphicsPipeline BlitPipeline { get; } - // Built-in text shader info - public GraphicsShaderInfo TextVertexShaderInfo { get; } - public GraphicsShaderInfo TextFragmentShaderInfo { get; } + public Shader TextVertexShader; + public Shader TextFragmentShader; + public GraphicsPipelineResourceInfo TextVertexShaderInfo { get; } + public GraphicsPipelineResourceInfo TextFragmentShaderInfo { get; } public VertexInputState TextVertexInputState { get; } // Built-in samplers @@ -43,29 +42,24 @@ namespace MoonWorks.Graphics private FencePool FencePool; internal unsafe GraphicsDevice( - Span preferredBackends, + BackendFlags preferredBackends, bool debugMode ) { - var backends = stackalloc Refresh.Backend[preferredBackends.Length]; - for (var i = 0; i < preferredBackends.Length; i += 1) - { - backends[i] = (Refresh.Backend) preferredBackends[i]; - } - - Backend = (Backend) Refresh.Refresh_SelectBackend(backends, (uint) preferredBackends.Length, out windowFlags); - - if (Backend == Backend.Invalid) + if (preferredBackends == BackendFlags.Invalid) { throw new System.Exception("Could not set graphics backend!"); } - Handle = Refresh.Refresh_CreateDevice( + Handle = SDL_Gpu.SDL_GpuCreateDevice( + (SDL_Gpu.BackendFlags) preferredBackends, Conversions.BoolToByte(debugMode) ); DebugMode = debugMode; // TODO: check for CreateDevice fail + Backend = (BackendFlags) SDL_Gpu.SDL_GpuGetBackend(Handle); + // Check for replacement stock shaders string basePath = System.AppContext.BaseDirectory; @@ -77,42 +71,79 @@ namespace MoonWorks.Graphics string videoFragPath = Path.Combine(basePath, "video_yuv2rgba.frag.refresh"); string blitFragPath = Path.Combine(basePath, "blit.frag.refresh"); - ShaderModule fullscreenVertShader; + Shader fullscreenVertShader; - ShaderModule textVertShader; - ShaderModule textFragShader; + Shader textVertShader; + Shader textFragShader; - ShaderModule videoFragShader; - ShaderModule blitFragShader; + Shader videoFragShader; + Shader blitFragShader; if (File.Exists(fullscreenVertPath)) { - fullscreenVertShader = new ShaderModule(this, fullscreenVertPath); + fullscreenVertShader = new Shader( + this, + fullscreenVertPath, + "main", + ShaderStage.Vertex, + ShaderFormat.SECRET + ); } else { // use defaults var assembly = typeof(GraphicsDevice).Assembly; using var vertStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.Fullscreen.vert.refresh"); - fullscreenVertShader = new ShaderModule(this, vertStream); + fullscreenVertShader = new Shader( + this, + vertStream, + "main", + ShaderStage.Vertex, + ShaderFormat.SPIRV + ); } if (File.Exists(videoFragPath)) { - videoFragShader = new ShaderModule(this, videoFragPath); + videoFragShader = new Shader( + this, + videoFragPath, + "main", + ShaderStage.Fragment, + ShaderFormat.SECRET + ); } else { // use defaults var assembly = typeof(GraphicsDevice).Assembly; using var fragStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.VideoYUV2RGBA.frag.refresh"); - videoFragShader = new ShaderModule(this, fragStream); + videoFragShader = new Shader( + this, + fragStream, + "main", + ShaderStage.Fragment, + ShaderFormat.SPIRV + ); } if (File.Exists(textVertPath) && File.Exists(textFragPath)) { - textVertShader = new ShaderModule(this, textVertPath); - textFragShader = new ShaderModule(this, textFragPath); + textVertShader = new Shader( + this, + textVertPath, + "main", + ShaderStage.Vertex, + ShaderFormat.SECRET + ); + + textFragShader = new Shader( + this, + textFragPath, + "main", + ShaderStage.Fragment, + ShaderFormat.SECRET + ); } else { @@ -122,13 +153,32 @@ namespace MoonWorks.Graphics using var vertStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.TextTransform.vert.refresh"); using var fragStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.TextMSDF.frag.refresh"); - textVertShader = new ShaderModule(this, vertStream); - textFragShader = new ShaderModule(this, fragStream); + textVertShader = new Shader( + this, + vertStream, + "main", + ShaderStage.Fragment, + ShaderFormat.SPIRV + ); + + textFragShader = new Shader( + this, + fragStream, + "main", + ShaderStage.Fragment, + ShaderFormat.SPIRV + ); } if (File.Exists(blitFragPath)) { - blitFragShader = new ShaderModule(this, blitFragPath); + blitFragShader = new Shader( + this, + blitFragPath, + "main", + ShaderStage.Fragment, + ShaderFormat.SECRET + ); } else { @@ -136,7 +186,13 @@ namespace MoonWorks.Graphics var assembly = typeof(GraphicsDevice).Assembly; using var fragStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.Blit.frag.refresh"); - blitFragShader = new ShaderModule(this, fragStream); + blitFragShader = new Shader( + this, + fragStream, + "main", + ShaderStage.Fragment, + ShaderFormat.SPIRV + ); } VideoPipeline = new GraphicsPipeline( @@ -150,16 +206,12 @@ namespace MoonWorks.Graphics ) ), DepthStencilState = DepthStencilState.Disable, - VertexShaderResourceInfo = GraphicsShaderInfo.Create( - fullscreenVertShader, - "main", - 0 - ), - FragmentShaderResourceInfo = GraphicsShaderInfo.Create( - videoFragShader, - "main", - 3 - ), + VertexShader = fullscreenVertShader, + FragmentShader = videoFragShader, + FragmentShaderResourceInfo = new GraphicsPipelineResourceInfo + { + SamplerCount = 3 + }, VertexInputState = VertexInputState.Empty, RasterizerState = RasterizerState.CCW_CullNone, PrimitiveType = PrimitiveType.TriangleList, @@ -167,36 +219,15 @@ namespace MoonWorks.Graphics } ); - BlitPipeline = new GraphicsPipeline( - this, - new GraphicsPipelineCreateInfo - { - AttachmentInfo = new GraphicsPipelineAttachmentInfo( - new ColorAttachmentDescription( - TextureFormat.R8G8B8A8, - ColorAttachmentBlendState.None - ) - ), - DepthStencilState = DepthStencilState.Disable, - VertexShaderResourceInfo = GraphicsShaderInfo.Create( - fullscreenVertShader, - "main", - 0 - ), - FragmentShaderResourceInfo = GraphicsShaderInfo.Create( - blitFragShader, - "main", - 1 - ), - VertexInputState = VertexInputState.Empty, - RasterizerState = RasterizerState.CCW_CullNone, - PrimitiveType = PrimitiveType.TriangleList, - MultisampleState = MultisampleState.None - } - ); + TextVertexShader = textVertShader; + TextVertexShaderInfo = new GraphicsPipelineResourceInfo(); + + TextFragmentShader = textFragShader; + TextFragmentShaderInfo = new GraphicsPipelineResourceInfo + { + SamplerCount = 1 + }; - TextVertexShaderInfo = GraphicsShaderInfo.Create(textVertShader, "main", 0); - TextFragmentShaderInfo = GraphicsShaderInfo.Create(textFragShader, "main", 1); TextVertexInputState = VertexInputState.CreateSingleBinding(); PointSampler = new Sampler(this, SamplerCreateInfo.PointClamp); @@ -209,28 +240,35 @@ namespace MoonWorks.Graphics /// /// Prepares a window so that frames can be presented to it. /// + /// The desired composition of the swapchain. Ignore this unless you are using HDR or tonemapping. /// The desired presentation mode for the window. Roughly equivalent to V-Sync. /// True if successfully claimed. - public bool ClaimWindow(Window window, PresentMode presentMode) - { + public bool ClaimWindow( + Window window, + SwapchainComposition swapchainComposition, + PresentMode presentMode + ) { if (window.Claimed) { Logger.LogError("Window already claimed!"); return false; } - var success = Conversions.ByteToBool( - Refresh.Refresh_ClaimWindow( + var success = Conversions.IntToBool( + SDL_Gpu.SDL_GpuClaimWindow( Handle, window.Handle, - (Refresh.PresentMode) presentMode + (SDL_Gpu.SwapchainComposition) swapchainComposition, + (SDL_Gpu.PresentMode) presentMode ) ); if (success) { window.Claimed = true; + window.SwapchainComposition = swapchainComposition; window.SwapchainFormat = GetSwapchainFormat(window); + if (window.SwapchainTexture == null) { window.SwapchainTexture = new Texture(this, window.SwapchainFormat); @@ -247,7 +285,7 @@ namespace MoonWorks.Graphics { if (window.Claimed) { - Refresh.Refresh_UnclaimWindow( + SDL_Gpu.SDL_GpuUnclaimWindow( Handle, window.Handle ); @@ -265,18 +303,22 @@ namespace MoonWorks.Graphics /// /// /// - public void SetPresentMode(Window window, PresentMode presentMode) - { + public void SetSwapchainParameters( + Window window, + SwapchainComposition swapchainComposition, + PresentMode presentMode + ) { if (!window.Claimed) { Logger.LogError("Cannot set present mode on unclaimed window!"); return; } - Refresh.Refresh_SetSwapchainPresentMode( + SDL_Gpu.SDL_GpuSetSwapchainParameters( Handle, window.Handle, - (Refresh.PresentMode) presentMode + (SDL_Gpu.SwapchainComposition) swapchainComposition, + (SDL_Gpu.PresentMode) presentMode ); } @@ -288,7 +330,7 @@ namespace MoonWorks.Graphics public CommandBuffer AcquireCommandBuffer() { var commandBuffer = CommandBufferPool.Obtain(); - commandBuffer.SetHandle(Refresh.Refresh_AcquireCommandBuffer(Handle)); + commandBuffer.SetHandle(SDL_Gpu.SDL_GpuAcquireCommandBuffer(Handle)); #if DEBUG commandBuffer.ResetStateTracking(); #endif @@ -307,8 +349,7 @@ namespace MoonWorks.Graphics } #endif - Refresh.Refresh_Submit( - Handle, + SDL_Gpu.SDL_GpuSubmit( commandBuffer.Handle ); @@ -325,8 +366,7 @@ namespace MoonWorks.Graphics /// public Fence SubmitAndAcquireFence(CommandBuffer commandBuffer) { - var fenceHandle = Refresh.Refresh_SubmitAndAcquireFence( - Handle, + var fenceHandle = SDL_Gpu.SDL_GpuSubmitAndAcquireFence( commandBuffer.Handle ); @@ -341,7 +381,7 @@ namespace MoonWorks.Graphics /// public void Wait() { - Refresh.Refresh_Wait(Handle); + SDL_Gpu.SDL_GpuWait(Handle); } /// @@ -349,14 +389,13 @@ namespace MoonWorks.Graphics /// public unsafe void WaitForFences(Fence fence) { - var handlePtr = stackalloc nint[1]; - handlePtr[0] = fence.Handle; + var fenceHandle = fence.Handle; - Refresh.Refresh_WaitForFences( + SDL_Gpu.SDL_GpuWaitForFences( Handle, 1, 1, - (nint) handlePtr + &fenceHandle ); } @@ -373,11 +412,11 @@ namespace MoonWorks.Graphics handlePtr[0] = fenceOne.Handle; handlePtr[1] = fenceTwo.Handle; - Refresh.Refresh_WaitForFences( + SDL_Gpu.SDL_GpuWaitForFences( Handle, - Conversions.BoolToByte(waitAll), + Conversions.BoolToInt(waitAll), 2, - (nint) handlePtr + handlePtr ); } @@ -396,11 +435,11 @@ namespace MoonWorks.Graphics handlePtr[1] = fenceTwo.Handle; handlePtr[2] = fenceThree.Handle; - Refresh.Refresh_WaitForFences( + SDL_Gpu.SDL_GpuWaitForFences( Handle, - Conversions.BoolToByte(waitAll), + Conversions.BoolToInt(waitAll), 3, - (nint) handlePtr + handlePtr ); } @@ -421,11 +460,11 @@ namespace MoonWorks.Graphics handlePtr[2] = fenceThree.Handle; handlePtr[3] = fenceFour.Handle; - Refresh.Refresh_WaitForFences( + SDL_Gpu.SDL_GpuWaitForFences( Handle, - Conversions.BoolToByte(waitAll), + Conversions.BoolToInt(waitAll), 4, - (nint) handlePtr + handlePtr ); } @@ -433,7 +472,7 @@ namespace MoonWorks.Graphics /// Wait for one or more fences to become signaled. /// /// If true, will wait for all given fences to be signaled. - public unsafe void WaitForFences(Fence[] fences, bool waitAll) + public unsafe void WaitForFences(Span fences, bool waitAll) { var handlePtr = stackalloc nint[fences.Length]; @@ -442,11 +481,11 @@ namespace MoonWorks.Graphics handlePtr[i] = fences[i].Handle; } - Refresh.Refresh_WaitForFences( + SDL_Gpu.SDL_GpuWaitForFences( Handle, - Conversions.BoolToByte(waitAll), + Conversions.BoolToInt(waitAll), 4, - (nint) handlePtr + handlePtr ); } @@ -456,7 +495,7 @@ namespace MoonWorks.Graphics /// Throws if the fence query indicates that the graphics device has been lost. public bool QueryFence(Fence fence) { - var result = Refresh.Refresh_QueryFence(Handle, fence.Handle); + var result = SDL_Gpu.SDL_GpuQueryFence(Handle, fence.Handle); if (result < 0) { @@ -471,126 +510,19 @@ namespace MoonWorks.Graphics /// public void ReleaseFence(Fence fence) { - Refresh.Refresh_ReleaseFence(Handle, fence.Handle); + SDL_Gpu.SDL_GpuReleaseFence(Handle, fence.Handle); fence.Handle = IntPtr.Zero; FencePool.Return(fence); } - /// - /// ⚠️⚠️⚠️
- /// Downloads data from a Texture to a TransferBuffer. - /// This copy occurs immediately on the CPU timeline.
- /// - /// If you modify this texture in a command buffer and then call this function without calling - /// SubmitAndAcquireFence and WaitForFences first, the results will not be what you expect.
- /// - /// This method forces a sync point and is generally a bad thing to do. - /// Only use it if you have exhausted all other options.
- /// - /// Remember: friends don't let friends readback.
- /// ⚠️⚠️⚠️ - ///
- public void DownloadFromTexture( - in TextureRegion textureRegion, - TransferBuffer transferBuffer, - in BufferImageCopy copyParams, - TransferOptions transferOption - ) { - Refresh.Refresh_DownloadFromTexture( - Handle, - textureRegion.ToRefreshTextureRegion(), - transferBuffer.Handle, - copyParams.ToRefresh(), - (Refresh.TransferOptions) transferOption - ); - } - - /// - /// ⚠️⚠️⚠️
- /// Downloads all data from a 2D texture with no mips to a TransferBuffer. - /// This copy occurs immediately on the CPU timeline.
- /// - /// If you modify this texture in a command buffer and then call this function without calling - /// SubmitAndAcquireFence and WaitForFences first, the results will not be what you expect.
- /// - /// This method forces a sync point and is generally a bad thing to do. - /// Only use it if you have exhausted all other options.
- /// - /// Remember: friends don't let friends readback.
- /// ⚠️⚠️⚠️ - ///
- public void DownloadFromTexture( - Texture texture, - TransferBuffer transferBuffer, - TransferOptions transferOption - ) { - DownloadFromTexture( - new TextureRegion(texture), - transferBuffer, - new BufferImageCopy(0, 0, 0), - transferOption - ); - } - - /// - /// ⚠️⚠️⚠️
- /// Downloads data from a GpuBuffer to a TransferBuffer. - /// This copy occurs immediately on the CPU timeline.
- /// - /// If you modify this GpuBuffer in a command buffer and then call this function without calling - /// SubmitAndAcquireFence and WaitForFences first, the results will not be what you expect.
- /// - /// This method forces a sync point and is generally a bad thing to do. - /// Only use it if you have exhausted all other options.
- /// - /// Remember: friends don't let friends readback.
- /// ⚠️⚠️⚠️ - ///
- public void DownloadFromBuffer( - GpuBuffer gpuBuffer, - TransferBuffer transferBuffer, - in BufferCopy copyParams, - TransferOptions transferOption - ) { - Refresh.Refresh_DownloadFromBuffer( - Handle, - gpuBuffer.Handle, - transferBuffer.Handle, - copyParams.ToRefresh(), - (Refresh.TransferOptions) transferOption - ); - } - - /// - /// ⚠️⚠️⚠️
- /// Downloads all data in a GpuBuffer to a TransferBuffer. - /// This copy occurs immediately on the CPU timeline.
- /// - /// If you modify this GpuBuffer in a command buffer and then call this function without calling - /// SubmitAndAcquireFence and WaitForFences first, the results will not be what you expect.
- /// - /// This method forces a sync point and is generally a bad thing to do. - /// Only use it if you have exhausted all other options.
- /// - /// Remember: friends don't let friends readback.
- /// ⚠️⚠️⚠️ - ///
- public void DownloadFromBuffer( - GpuBuffer gpuBuffer, - TransferBuffer transferBuffer, - TransferOptions option - ) { - DownloadFromBuffer( - gpuBuffer, - transferBuffer, - new BufferCopy(0, 0, gpuBuffer.Size), - option - ); - } - private TextureFormat GetSwapchainFormat(Window window) { - return (TextureFormat) Refresh.Refresh_GetSwapchainFormat(Handle, window.Handle); + if (!window.Claimed) + { + throw new System.ArgumentException("Cannot get swapchain format of unclaimed window!"); + } + + return (TextureFormat) SDL_Gpu.SDL_GpuGetSwapchainTextureFormat(Handle, window.Handle); } internal void AddResourceReference(GCHandle resourceReference) @@ -638,7 +570,7 @@ namespace MoonWorks.Graphics } } - Refresh.Refresh_DestroyDevice(Handle); + SDL_Gpu.SDL_GpuDestroyDevice(Handle); IsDisposed = true; } diff --git a/src/Window.cs b/src/Window.cs index 4cc1b6e..74d270e 100644 --- a/src/Window.cs +++ b/src/Window.cs @@ -19,6 +19,7 @@ namespace MoonWorks internal Texture SwapchainTexture { get; set; } public bool Claimed { get; internal set; } + public MoonWorks.Graphics.SwapchainComposition SwapchainComposition { get; internal set; } public MoonWorks.Graphics.TextureFormat SwapchainFormat { get; internal set; } public (int, int) Position