2021-01-20 03:33:27 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2022-08-02 21:04:12 +00:00
|
|
|
|
using System.IO;
|
2023-11-20 23:18:06 +00:00
|
|
|
|
using System.Runtime.InteropServices;
|
2023-12-15 18:46:43 +00:00
|
|
|
|
using MoonWorks.Video;
|
2024-06-05 19:34:24 +00:00
|
|
|
|
using RefreshCS;
|
2021-01-20 03:33:27 +00:00
|
|
|
|
|
|
|
|
|
namespace MoonWorks.Graphics
|
|
|
|
|
{
|
2023-09-19 20:19:41 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// GraphicsDevice manages all graphics-related concerns.
|
|
|
|
|
/// </summary>
|
2022-02-23 05:14:32 +00:00
|
|
|
|
public class GraphicsDevice : IDisposable
|
|
|
|
|
{
|
|
|
|
|
public IntPtr Handle { get; }
|
2024-06-04 23:32:41 +00:00
|
|
|
|
public BackendFlags Backend { get; }
|
2024-03-11 23:28:00 +00:00
|
|
|
|
public bool DebugMode { get; }
|
2022-09-29 22:22:50 +00:00
|
|
|
|
|
2022-08-02 21:04:12 +00:00
|
|
|
|
// Built-in video pipeline
|
|
|
|
|
internal GraphicsPipeline VideoPipeline { get; }
|
|
|
|
|
|
2023-12-15 18:46:43 +00:00
|
|
|
|
// Built-in text shader info
|
2024-06-04 23:32:41 +00:00
|
|
|
|
public Shader TextVertexShader;
|
|
|
|
|
public Shader TextFragmentShader;
|
|
|
|
|
public GraphicsPipelineResourceInfo TextVertexShaderInfo { get; }
|
|
|
|
|
public GraphicsPipelineResourceInfo TextFragmentShaderInfo { get; }
|
2023-12-15 18:46:43 +00:00
|
|
|
|
public VertexInputState TextVertexInputState { get; }
|
|
|
|
|
|
|
|
|
|
// Built-in samplers
|
|
|
|
|
public Sampler PointSampler { get; }
|
|
|
|
|
public Sampler LinearSampler { get; }
|
|
|
|
|
|
2022-02-23 05:14:32 +00:00
|
|
|
|
public bool IsDisposed { get; private set; }
|
2021-01-20 03:33:27 +00:00
|
|
|
|
|
2023-11-20 23:18:06 +00:00
|
|
|
|
private readonly HashSet<GCHandle> resources = new HashSet<GCHandle>();
|
2024-01-18 20:27:34 +00:00
|
|
|
|
private CommandBufferPool CommandBufferPool;
|
2024-06-04 23:04:19 +00:00
|
|
|
|
private FencePool FencePool;
|
2024-06-05 19:34:24 +00:00
|
|
|
|
internal RenderPassPool RenderPassPool = new RenderPassPool();
|
|
|
|
|
internal ComputePassPool ComputePassPool = new ComputePassPool();
|
|
|
|
|
internal CopyPassPool CopyPassPool = new CopyPassPool();
|
2021-01-27 05:06:15 +00:00
|
|
|
|
|
2024-03-07 18:34:30 +00:00
|
|
|
|
internal unsafe GraphicsDevice(
|
2024-06-04 23:32:41 +00:00
|
|
|
|
BackendFlags preferredBackends,
|
2022-02-23 06:16:06 +00:00
|
|
|
|
bool debugMode
|
2023-01-21 23:37:01 +00:00
|
|
|
|
) {
|
2024-06-04 23:32:41 +00:00
|
|
|
|
if (preferredBackends == BackendFlags.Invalid)
|
2022-09-30 02:21:47 +00:00
|
|
|
|
{
|
|
|
|
|
throw new System.Exception("Could not set graphics backend!");
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Handle = Refresh.Refresh_CreateDevice(
|
|
|
|
|
(Refresh.BackendFlags) preferredBackends,
|
2022-02-23 05:14:32 +00:00
|
|
|
|
Conversions.BoolToByte(debugMode)
|
|
|
|
|
);
|
2022-08-02 21:04:12 +00:00
|
|
|
|
|
2024-03-11 23:28:00 +00:00
|
|
|
|
DebugMode = debugMode;
|
2023-12-15 18:46:43 +00:00
|
|
|
|
// TODO: check for CreateDevice fail
|
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Backend = (BackendFlags) Refresh.Refresh_GetBackend(Handle);
|
2024-06-04 23:32:41 +00:00
|
|
|
|
|
2023-12-15 18:46:43 +00:00
|
|
|
|
// Check for replacement stock shaders
|
2023-02-08 20:44:36 +00:00
|
|
|
|
string basePath = System.AppContext.BaseDirectory;
|
2023-12-15 18:46:43 +00:00
|
|
|
|
|
2024-02-23 20:39:59 +00:00
|
|
|
|
string fullscreenVertPath = Path.Combine(basePath, "fullscreen.vert.refresh");
|
2023-12-15 18:46:43 +00:00
|
|
|
|
|
|
|
|
|
string textVertPath = Path.Combine(basePath, "text_transform.vert.refresh");
|
|
|
|
|
string textFragPath = Path.Combine(basePath, "text_msdf.frag.refresh");
|
|
|
|
|
|
2024-02-23 20:39:59 +00:00
|
|
|
|
string videoFragPath = Path.Combine(basePath, "video_yuv2rgba.frag.refresh");
|
|
|
|
|
|
2024-06-04 23:32:41 +00:00
|
|
|
|
Shader fullscreenVertShader;
|
2023-12-15 18:46:43 +00:00
|
|
|
|
|
2024-06-04 23:32:41 +00:00
|
|
|
|
Shader textVertShader;
|
|
|
|
|
Shader textFragShader;
|
2023-12-15 18:46:43 +00:00
|
|
|
|
|
2024-06-04 23:32:41 +00:00
|
|
|
|
Shader videoFragShader;
|
2024-02-23 20:39:59 +00:00
|
|
|
|
|
|
|
|
|
if (File.Exists(fullscreenVertPath))
|
2023-01-21 23:37:01 +00:00
|
|
|
|
{
|
2024-06-04 23:32:41 +00:00
|
|
|
|
fullscreenVertShader = new Shader(
|
|
|
|
|
this,
|
|
|
|
|
fullscreenVertPath,
|
|
|
|
|
"main",
|
|
|
|
|
ShaderStage.Vertex,
|
|
|
|
|
ShaderFormat.SECRET
|
|
|
|
|
);
|
2023-12-15 18:46:43 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// use defaults
|
|
|
|
|
var assembly = typeof(GraphicsDevice).Assembly;
|
2024-06-06 05:01:12 +00:00
|
|
|
|
using var vertStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.Fullscreen.vert.spv");
|
2024-06-04 23:32:41 +00:00
|
|
|
|
fullscreenVertShader = new Shader(
|
|
|
|
|
this,
|
|
|
|
|
vertStream,
|
|
|
|
|
"main",
|
|
|
|
|
ShaderStage.Vertex,
|
|
|
|
|
ShaderFormat.SPIRV
|
|
|
|
|
);
|
2024-02-23 20:39:59 +00:00
|
|
|
|
}
|
2022-08-02 21:04:12 +00:00
|
|
|
|
|
2024-02-23 20:39:59 +00:00
|
|
|
|
if (File.Exists(videoFragPath))
|
|
|
|
|
{
|
2024-06-04 23:32:41 +00:00
|
|
|
|
videoFragShader = new Shader(
|
|
|
|
|
this,
|
|
|
|
|
videoFragPath,
|
|
|
|
|
"main",
|
|
|
|
|
ShaderStage.Fragment,
|
|
|
|
|
ShaderFormat.SECRET
|
|
|
|
|
);
|
2024-02-23 20:39:59 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// use defaults
|
|
|
|
|
var assembly = typeof(GraphicsDevice).Assembly;
|
2024-06-06 05:01:12 +00:00
|
|
|
|
using var fragStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.VideoYUV2RGBA.frag.spv");
|
2024-06-04 23:32:41 +00:00
|
|
|
|
videoFragShader = new Shader(
|
|
|
|
|
this,
|
|
|
|
|
fragStream,
|
|
|
|
|
"main",
|
|
|
|
|
ShaderStage.Fragment,
|
|
|
|
|
ShaderFormat.SPIRV
|
|
|
|
|
);
|
2023-01-21 23:37:01 +00:00
|
|
|
|
}
|
2023-09-19 06:18:21 +00:00
|
|
|
|
|
2023-12-15 18:46:43 +00:00
|
|
|
|
if (File.Exists(textVertPath) && File.Exists(textFragPath))
|
|
|
|
|
{
|
2024-06-04 23:32:41 +00:00
|
|
|
|
textVertShader = new Shader(
|
|
|
|
|
this,
|
|
|
|
|
textVertPath,
|
|
|
|
|
"main",
|
|
|
|
|
ShaderStage.Vertex,
|
|
|
|
|
ShaderFormat.SECRET
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
textFragShader = new Shader(
|
|
|
|
|
this,
|
|
|
|
|
textFragPath,
|
|
|
|
|
"main",
|
|
|
|
|
ShaderStage.Fragment,
|
|
|
|
|
ShaderFormat.SECRET
|
|
|
|
|
);
|
2023-12-15 18:46:43 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// use defaults
|
|
|
|
|
var assembly = typeof(GraphicsDevice).Assembly;
|
|
|
|
|
|
2024-06-06 05:01:12 +00:00
|
|
|
|
using var vertStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.TextTransform.vert.spv");
|
|
|
|
|
using var fragStream = assembly.GetManifestResourceStream("MoonWorks.Graphics.StockShaders.TextMSDF.frag.spv");
|
2023-12-15 18:46:43 +00:00
|
|
|
|
|
2024-06-04 23:32:41 +00:00
|
|
|
|
textVertShader = new Shader(
|
|
|
|
|
this,
|
|
|
|
|
vertStream,
|
|
|
|
|
"main",
|
|
|
|
|
ShaderStage.Fragment,
|
|
|
|
|
ShaderFormat.SPIRV
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
textFragShader = new Shader(
|
|
|
|
|
this,
|
|
|
|
|
fragStream,
|
|
|
|
|
"main",
|
|
|
|
|
ShaderStage.Fragment,
|
|
|
|
|
ShaderFormat.SPIRV
|
|
|
|
|
);
|
2023-12-15 18:46:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VideoPipeline = new GraphicsPipeline(
|
|
|
|
|
this,
|
|
|
|
|
new GraphicsPipelineCreateInfo
|
|
|
|
|
{
|
|
|
|
|
AttachmentInfo = new GraphicsPipelineAttachmentInfo(
|
|
|
|
|
new ColorAttachmentDescription(
|
|
|
|
|
TextureFormat.R8G8B8A8,
|
|
|
|
|
ColorAttachmentBlendState.None
|
|
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
DepthStencilState = DepthStencilState.Disable,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
VertexShader = fullscreenVertShader,
|
|
|
|
|
FragmentShader = videoFragShader,
|
|
|
|
|
FragmentShaderResourceInfo = new GraphicsPipelineResourceInfo
|
|
|
|
|
{
|
|
|
|
|
SamplerCount = 3
|
|
|
|
|
},
|
2023-12-15 18:46:43 +00:00
|
|
|
|
VertexInputState = VertexInputState.Empty,
|
|
|
|
|
RasterizerState = RasterizerState.CCW_CullNone,
|
|
|
|
|
PrimitiveType = PrimitiveType.TriangleList,
|
|
|
|
|
MultisampleState = MultisampleState.None
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
2024-06-04 23:32:41 +00:00
|
|
|
|
TextVertexShader = textVertShader;
|
|
|
|
|
TextVertexShaderInfo = new GraphicsPipelineResourceInfo();
|
|
|
|
|
|
|
|
|
|
TextFragmentShader = textFragShader;
|
|
|
|
|
TextFragmentShaderInfo = new GraphicsPipelineResourceInfo
|
|
|
|
|
{
|
|
|
|
|
SamplerCount = 1
|
|
|
|
|
};
|
2024-02-23 20:39:59 +00:00
|
|
|
|
|
2023-12-15 18:46:43 +00:00
|
|
|
|
TextVertexInputState = VertexInputState.CreateSingleBinding<Font.Vertex>();
|
|
|
|
|
|
|
|
|
|
PointSampler = new Sampler(this, SamplerCreateInfo.PointClamp);
|
|
|
|
|
LinearSampler = new Sampler(this, SamplerCreateInfo.LinearClamp);
|
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
FencePool = new FencePool(this);
|
2024-01-18 20:27:34 +00:00
|
|
|
|
CommandBufferPool = new CommandBufferPool(this);
|
2022-02-23 05:14:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 20:19:41 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Prepares a window so that frames can be presented to it.
|
|
|
|
|
/// </summary>
|
2024-06-04 23:32:41 +00:00
|
|
|
|
/// <param name="swapchainComposition">The desired composition of the swapchain. Ignore this unless you are using HDR or tonemapping.</param>
|
2023-09-19 20:19:41 +00:00
|
|
|
|
/// <param name="presentMode">The desired presentation mode for the window. Roughly equivalent to V-Sync.</param>
|
|
|
|
|
/// <returns>True if successfully claimed.</returns>
|
2024-06-04 23:32:41 +00:00
|
|
|
|
public bool ClaimWindow(
|
|
|
|
|
Window window,
|
|
|
|
|
SwapchainComposition swapchainComposition,
|
|
|
|
|
PresentMode presentMode
|
|
|
|
|
) {
|
2023-10-04 21:45:17 +00:00
|
|
|
|
if (window.Claimed)
|
|
|
|
|
{
|
|
|
|
|
Logger.LogError("Window already claimed!");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-04 23:32:41 +00:00
|
|
|
|
var success = Conversions.IntToBool(
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_ClaimWindow(
|
2022-09-29 22:22:50 +00:00
|
|
|
|
Handle,
|
|
|
|
|
window.Handle,
|
2024-06-05 19:34:24 +00:00
|
|
|
|
(Refresh.SwapchainComposition) swapchainComposition,
|
|
|
|
|
(Refresh.PresentMode) presentMode
|
2022-09-29 22:22:50 +00:00
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
window.Claimed = true;
|
2024-06-04 23:32:41 +00:00
|
|
|
|
window.SwapchainComposition = swapchainComposition;
|
2022-09-29 22:22:50 +00:00
|
|
|
|
window.SwapchainFormat = GetSwapchainFormat(window);
|
2024-06-04 23:32:41 +00:00
|
|
|
|
|
2022-12-13 08:52:35 +00:00
|
|
|
|
if (window.SwapchainTexture == null)
|
|
|
|
|
{
|
2024-01-16 06:19:59 +00:00
|
|
|
|
window.SwapchainTexture = new Texture(this, window.SwapchainFormat);
|
2022-12-13 08:52:35 +00:00
|
|
|
|
}
|
2022-09-29 22:22:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 20:19:41 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Unclaims a window, making it unavailable for presenting and freeing associated resources.
|
|
|
|
|
/// </summary>
|
2022-09-29 22:22:50 +00:00
|
|
|
|
public void UnclaimWindow(Window window)
|
|
|
|
|
{
|
2023-10-04 21:45:17 +00:00
|
|
|
|
if (window.Claimed)
|
|
|
|
|
{
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_UnclaimWindow(
|
2023-10-04 21:45:17 +00:00
|
|
|
|
Handle,
|
|
|
|
|
window.Handle
|
|
|
|
|
);
|
|
|
|
|
window.Claimed = false;
|
|
|
|
|
|
|
|
|
|
// The swapchain texture doesn't actually have a permanent texture reference, so we zero the handle before disposing.
|
|
|
|
|
window.SwapchainTexture.Handle = IntPtr.Zero;
|
|
|
|
|
window.SwapchainTexture.Dispose();
|
|
|
|
|
window.SwapchainTexture = null;
|
|
|
|
|
}
|
2022-09-29 22:22:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 20:19:41 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Changes the present mode of a claimed window. Does nothing if the window is not claimed.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="window"></param>
|
|
|
|
|
/// <param name="presentMode"></param>
|
2024-06-04 23:32:41 +00:00
|
|
|
|
public void SetSwapchainParameters(
|
|
|
|
|
Window window,
|
|
|
|
|
SwapchainComposition swapchainComposition,
|
|
|
|
|
PresentMode presentMode
|
|
|
|
|
) {
|
2023-09-19 20:19:41 +00:00
|
|
|
|
if (!window.Claimed)
|
|
|
|
|
{
|
2023-10-04 21:45:17 +00:00
|
|
|
|
Logger.LogError("Cannot set present mode on unclaimed window!");
|
2023-09-19 20:19:41 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_SetSwapchainParameters(
|
2022-09-29 22:22:50 +00:00
|
|
|
|
Handle,
|
|
|
|
|
window.Handle,
|
2024-06-05 19:34:24 +00:00
|
|
|
|
(Refresh.SwapchainComposition) swapchainComposition,
|
|
|
|
|
(Refresh.PresentMode) presentMode
|
2022-09-29 22:22:50 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 20:19:41 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Acquires a command buffer.
|
|
|
|
|
/// This is the start of your rendering process.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2022-02-23 05:14:32 +00:00
|
|
|
|
public CommandBuffer AcquireCommandBuffer()
|
|
|
|
|
{
|
2024-01-18 20:27:34 +00:00
|
|
|
|
var commandBuffer = CommandBufferPool.Obtain();
|
2024-06-05 19:34:24 +00:00
|
|
|
|
commandBuffer.SetHandle(Refresh.Refresh_AcquireCommandBuffer(Handle));
|
2024-01-18 20:27:34 +00:00
|
|
|
|
#if DEBUG
|
|
|
|
|
commandBuffer.ResetStateTracking();
|
|
|
|
|
#endif
|
|
|
|
|
return commandBuffer;
|
2022-02-23 05:14:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Submits a command buffer to the GPU for processing.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Submit(CommandBuffer commandBuffer)
|
|
|
|
|
{
|
2024-01-18 20:27:34 +00:00
|
|
|
|
#if DEBUG
|
|
|
|
|
if (commandBuffer.Submitted)
|
|
|
|
|
{
|
|
|
|
|
throw new System.InvalidOperationException("Command buffer already submitted!");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_Submit(
|
2023-09-19 06:18:21 +00:00
|
|
|
|
commandBuffer.Handle
|
|
|
|
|
);
|
2024-01-18 20:27:34 +00:00
|
|
|
|
|
|
|
|
|
CommandBufferPool.Return(commandBuffer);
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
|
commandBuffer.Submitted = true;
|
|
|
|
|
#endif
|
2023-09-19 06:18:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Submits a command buffer to the GPU for processing and acquires a fence associated with the submission.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public Fence SubmitAndAcquireFence(CommandBuffer commandBuffer)
|
2022-12-13 08:34:16 +00:00
|
|
|
|
{
|
2024-06-05 19:34:24 +00:00
|
|
|
|
var fenceHandle = Refresh.Refresh_SubmitAndAcquireFence(
|
2023-09-19 06:18:21 +00:00
|
|
|
|
commandBuffer.Handle
|
|
|
|
|
);
|
2022-12-13 08:34:16 +00:00
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
var fence = FencePool.Obtain();
|
|
|
|
|
fence.SetHandle(fenceHandle);
|
2022-12-13 08:34:16 +00:00
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
return fence;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Wait for the graphics device to become idle.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Wait()
|
|
|
|
|
{
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_Wait(Handle);
|
2023-09-19 06:18:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Waits for the given fence to become signaled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public unsafe void WaitForFences(Fence fence)
|
|
|
|
|
{
|
2024-06-04 23:32:41 +00:00
|
|
|
|
var fenceHandle = fence.Handle;
|
2023-09-19 06:18:21 +00:00
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_WaitForFences(
|
2022-12-13 08:34:16 +00:00
|
|
|
|
Handle,
|
|
|
|
|
1,
|
2023-09-19 06:18:21 +00:00
|
|
|
|
1,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
&fenceHandle
|
2022-12-13 08:34:16 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Wait for one or more fences to become signaled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="waitAll">If true, will wait for all given fences to be signaled.</param>
|
|
|
|
|
public unsafe void WaitForFences(
|
|
|
|
|
Fence fenceOne,
|
|
|
|
|
Fence fenceTwo,
|
|
|
|
|
bool waitAll
|
2022-12-13 08:34:16 +00:00
|
|
|
|
) {
|
2023-09-19 06:18:21 +00:00
|
|
|
|
var handlePtr = stackalloc nint[2];
|
|
|
|
|
handlePtr[0] = fenceOne.Handle;
|
|
|
|
|
handlePtr[1] = fenceTwo.Handle;
|
2022-12-13 08:34:16 +00:00
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_WaitForFences(
|
2022-12-13 08:34:16 +00:00
|
|
|
|
Handle,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
Conversions.BoolToInt(waitAll),
|
2022-12-13 08:34:16 +00:00
|
|
|
|
2,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
handlePtr
|
2022-12-13 08:34:16 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Wait for one or more fences to become signaled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="waitAll">If true, will wait for all given fences to be signaled.</param>
|
|
|
|
|
public unsafe void WaitForFences(
|
|
|
|
|
Fence fenceOne,
|
|
|
|
|
Fence fenceTwo,
|
|
|
|
|
Fence fenceThree,
|
|
|
|
|
bool waitAll
|
2022-12-13 08:34:16 +00:00
|
|
|
|
) {
|
2023-09-19 06:18:21 +00:00
|
|
|
|
var handlePtr = stackalloc nint[3];
|
|
|
|
|
handlePtr[0] = fenceOne.Handle;
|
|
|
|
|
handlePtr[1] = fenceTwo.Handle;
|
|
|
|
|
handlePtr[2] = fenceThree.Handle;
|
2022-12-13 08:34:16 +00:00
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_WaitForFences(
|
2022-12-13 08:34:16 +00:00
|
|
|
|
Handle,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
Conversions.BoolToInt(waitAll),
|
2022-12-13 08:34:16 +00:00
|
|
|
|
3,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
handlePtr
|
2022-12-13 08:34:16 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Wait for one or more fences to become signaled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="waitAll">If true, will wait for all given fences to be signaled.</param>
|
|
|
|
|
public unsafe void WaitForFences(
|
|
|
|
|
Fence fenceOne,
|
|
|
|
|
Fence fenceTwo,
|
|
|
|
|
Fence fenceThree,
|
|
|
|
|
Fence fenceFour,
|
|
|
|
|
bool waitAll
|
2022-12-13 08:34:16 +00:00
|
|
|
|
) {
|
2023-09-19 06:18:21 +00:00
|
|
|
|
var handlePtr = stackalloc nint[4];
|
|
|
|
|
handlePtr[0] = fenceOne.Handle;
|
|
|
|
|
handlePtr[1] = fenceTwo.Handle;
|
|
|
|
|
handlePtr[2] = fenceThree.Handle;
|
|
|
|
|
handlePtr[3] = fenceFour.Handle;
|
2022-12-13 08:34:16 +00:00
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_WaitForFences(
|
2022-12-13 08:34:16 +00:00
|
|
|
|
Handle,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
Conversions.BoolToInt(waitAll),
|
2022-12-13 08:34:16 +00:00
|
|
|
|
4,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
handlePtr
|
2022-12-13 08:34:16 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Wait for one or more fences to become signaled.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="waitAll">If true, will wait for all given fences to be signaled.</param>
|
2024-06-04 23:32:41 +00:00
|
|
|
|
public unsafe void WaitForFences(Span<Fence> fences, bool waitAll)
|
2022-02-23 05:14:32 +00:00
|
|
|
|
{
|
2023-09-19 06:18:21 +00:00
|
|
|
|
var handlePtr = stackalloc nint[fences.Length];
|
2022-02-23 05:14:32 +00:00
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
for (var i = 0; i < fences.Length; i += 1)
|
2022-02-23 05:14:32 +00:00
|
|
|
|
{
|
2023-09-19 06:18:21 +00:00
|
|
|
|
handlePtr[i] = fences[i].Handle;
|
2022-02-23 05:14:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_WaitForFences(
|
2022-02-23 05:14:32 +00:00
|
|
|
|
Handle,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
Conversions.BoolToInt(waitAll),
|
2023-09-19 06:18:21 +00:00
|
|
|
|
4,
|
2024-06-04 23:32:41 +00:00
|
|
|
|
handlePtr
|
2022-02-23 05:14:32 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-19 06:18:21 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns true if the fence is signaled, indicating that the associated command buffer has finished processing.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <exception cref="InvalidOperationException">Throws if the fence query indicates that the graphics device has been lost.</exception>
|
|
|
|
|
public bool QueryFence(Fence fence)
|
2022-02-23 05:14:32 +00:00
|
|
|
|
{
|
2024-06-05 19:34:24 +00:00
|
|
|
|
var result = Refresh.Refresh_QueryFence(Handle, fence.Handle);
|
2023-09-19 06:18:21 +00:00
|
|
|
|
|
|
|
|
|
if (result < 0)
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("The graphics device has been lost.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Release reference to an acquired fence, enabling it to be reused.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void ReleaseFence(Fence fence)
|
|
|
|
|
{
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_ReleaseFence(Handle, fence.Handle);
|
2023-09-19 06:18:21 +00:00
|
|
|
|
fence.Handle = IntPtr.Zero;
|
|
|
|
|
FencePool.Return(fence);
|
2022-02-23 05:14:32 +00:00
|
|
|
|
}
|
2021-01-20 03:33:27 +00:00
|
|
|
|
|
2022-09-29 22:22:50 +00:00
|
|
|
|
private TextureFormat GetSwapchainFormat(Window window)
|
2022-03-02 07:21:42 +00:00
|
|
|
|
{
|
2024-06-04 23:32:41 +00:00
|
|
|
|
if (!window.Claimed)
|
|
|
|
|
{
|
|
|
|
|
throw new System.ArgumentException("Cannot get swapchain format of unclaimed window!");
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
return (TextureFormat) Refresh.Refresh_GetSwapchainTextureFormat(Handle, window.Handle);
|
2022-03-02 07:21:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-20 23:18:06 +00:00
|
|
|
|
internal void AddResourceReference(GCHandle resourceReference)
|
2022-02-23 05:14:32 +00:00
|
|
|
|
{
|
|
|
|
|
lock (resources)
|
|
|
|
|
{
|
|
|
|
|
resources.Add(resourceReference);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-20 23:18:06 +00:00
|
|
|
|
internal void RemoveResourceReference(GCHandle resourceReference)
|
2022-02-23 05:14:32 +00:00
|
|
|
|
{
|
|
|
|
|
lock (resources)
|
|
|
|
|
{
|
|
|
|
|
resources.Remove(resourceReference);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (!IsDisposed)
|
|
|
|
|
{
|
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
|
|
|
|
lock (resources)
|
|
|
|
|
{
|
2023-12-15 18:46:43 +00:00
|
|
|
|
// Dispose video players first to avoid race condition on threaded decoding
|
|
|
|
|
foreach (var resource in resources)
|
|
|
|
|
{
|
|
|
|
|
if (resource.Target is VideoPlayer player)
|
|
|
|
|
{
|
|
|
|
|
player.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dispose everything else
|
2023-11-20 23:18:06 +00:00
|
|
|
|
foreach (var resource in resources)
|
2022-02-22 22:29:50 +00:00
|
|
|
|
{
|
2023-11-21 01:09:22 +00:00
|
|
|
|
if (resource.Target is IDisposable disposable)
|
2022-02-23 05:14:32 +00:00
|
|
|
|
{
|
2023-11-20 23:18:06 +00:00
|
|
|
|
disposable.Dispose();
|
2022-02-23 05:14:32 +00:00
|
|
|
|
}
|
2022-02-22 22:29:50 +00:00
|
|
|
|
}
|
2022-02-23 05:14:32 +00:00
|
|
|
|
resources.Clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-05 19:34:24 +00:00
|
|
|
|
Refresh.Refresh_DestroyDevice(Handle);
|
2023-10-04 21:45:17 +00:00
|
|
|
|
|
2022-02-23 05:14:32 +00:00
|
|
|
|
IsDisposed = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~GraphicsDevice()
|
|
|
|
|
{
|
|
|
|
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|
|
|
|
Dispose(disposing: false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
|
|
|
|
Dispose(disposing: true);
|
|
|
|
|
GC.SuppressFinalize(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-01-20 03:33:27 +00:00
|
|
|
|
}
|