add graphics state validation in debug mode

arm_test
cosmonaut 2022-09-07 13:07:17 -07:00
parent 5c080a4c42
commit d5a7daa524
1 changed files with 201 additions and 1 deletions

View File

@ -10,7 +10,12 @@ namespace MoonWorks.Graphics
public struct CommandBuffer public struct CommandBuffer
{ {
public GraphicsDevice Device { get; } public GraphicsDevice Device { get; }
public IntPtr Handle { get; internal set; } public IntPtr Handle { get; }
// some state for debug validation
GraphicsPipeline currentGraphicsPipeline = null;
ComputePipeline currentComputePipeline = null;
bool renderPassActive = false;
// called from RefreshDevice // called from RefreshDevice
internal CommandBuffer(GraphicsDevice device, IntPtr handle) internal CommandBuffer(GraphicsDevice device, IntPtr handle)
@ -61,6 +66,8 @@ namespace MoonWorks.Graphics
IntPtr.Zero IntPtr.Zero
); );
} }
renderPassActive = true;
} }
/// <summary> /// <summary>
@ -102,6 +109,8 @@ namespace MoonWorks.Graphics
&refreshDepthStencilAttachmentInfo &refreshDepthStencilAttachmentInfo
); );
} }
renderPassActive = true;
} }
/// <summary> /// <summary>
@ -146,6 +155,8 @@ namespace MoonWorks.Graphics
IntPtr.Zero IntPtr.Zero
); );
} }
renderPassActive = true;
} }
/// <summary> /// <summary>
@ -189,6 +200,8 @@ namespace MoonWorks.Graphics
&refreshDepthStencilAttachmentInfo &refreshDepthStencilAttachmentInfo
); );
} }
renderPassActive = true;
} }
/// <summary> /// <summary>
@ -204,6 +217,8 @@ namespace MoonWorks.Graphics
Handle, Handle,
computePipeline.Handle computePipeline.Handle
); );
currentComputePipeline = computePipeline;
} }
/// <summary> /// <summary>
@ -214,6 +229,20 @@ namespace MoonWorks.Graphics
params Buffer[] buffers params Buffer[] buffers
) )
{ {
#if DEBUG
AssertComputePipelineBound();
if (currentComputePipeline.ComputeShaderInfo.BufferBindingCount == 0)
{
throw new System.InvalidOperationException("The current compute shader does not take any buffers!");
}
if (currentComputePipeline.ComputeShaderInfo.BufferBindingCount < buffers.Length)
{
throw new System.InvalidOperationException("Buffer count exceeds the amount used by the current compute shader!");
}
#endif
var bufferPtrs = stackalloc IntPtr[buffers.Length]; var bufferPtrs = stackalloc IntPtr[buffers.Length];
for (var i = 0; i < buffers.Length; i += 1) for (var i = 0; i < buffers.Length; i += 1)
@ -236,6 +265,20 @@ namespace MoonWorks.Graphics
params Texture[] textures params Texture[] textures
) )
{ {
#if DEBUG
AssertComputePipelineBound();
if (currentComputePipeline.ComputeShaderInfo.ImageBindingCount == 0)
{
throw new System.InvalidOperationException("The current compute shader does not take any textures!");
}
if (currentComputePipeline.ComputeShaderInfo.ImageBindingCount < textures.Length)
{
throw new System.InvalidOperationException("Texture count exceeds the amount used by the current compute shader!");
}
#endif
var texturePtrs = stackalloc IntPtr[textures.Length]; var texturePtrs = stackalloc IntPtr[textures.Length];
for (var i = 0; i < textures.Length; i += 1) for (var i = 0; i < textures.Length; i += 1)
@ -264,6 +307,10 @@ namespace MoonWorks.Graphics
uint computeParamOffset uint computeParamOffset
) )
{ {
#if DEBUG
AssertComputePipelineBound();
#endif
Refresh.Refresh_DispatchCompute( Refresh.Refresh_DispatchCompute(
Device.Handle, Device.Handle,
Handle, Handle,
@ -287,6 +334,8 @@ namespace MoonWorks.Graphics
Handle, Handle,
graphicsPipeline.Handle graphicsPipeline.Handle
); );
currentGraphicsPipeline = graphicsPipeline;
} }
/// <summary> /// <summary>
@ -294,6 +343,10 @@ namespace MoonWorks.Graphics
/// </summary> /// </summary>
public void SetViewport(Viewport viewport) public void SetViewport(Viewport viewport)
{ {
#if DEBUG
AssertRenderPassActive();
#endif
Refresh.Refresh_SetViewport( Refresh.Refresh_SetViewport(
Device.Handle, Device.Handle,
Handle, Handle,
@ -306,6 +359,10 @@ namespace MoonWorks.Graphics
/// </summary> /// </summary>
public void SetScissor(Rect scissor) public void SetScissor(Rect scissor)
{ {
#if DEBUG
AssertRenderPassActive();
#endif
Refresh.Refresh_SetScissor( Refresh.Refresh_SetScissor(
Device.Handle, Device.Handle,
Handle, Handle,
@ -400,6 +457,20 @@ namespace MoonWorks.Graphics
int length int length
) )
{ {
#if DEBUG
AssertGraphicsPipelineBound();
if (currentGraphicsPipeline.VertexShaderInfo.SamplerBindingCount == 0)
{
throw new System.InvalidOperationException("The vertex shader of the current graphics pipeline does not take any samplers!");
}
if (currentGraphicsPipeline.VertexShaderInfo.SamplerBindingCount < length)
{
throw new System.InvalidOperationException("Vertex sampler count exceeds the amount used by the vertex shader!");
}
#endif
var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length]; var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length];
var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length]; var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length];
@ -438,6 +509,20 @@ namespace MoonWorks.Graphics
int length int length
) )
{ {
#if DEBUG
AssertGraphicsPipelineBound();
if (currentGraphicsPipeline.FragmentShaderInfo.SamplerBindingCount == 0)
{
throw new System.InvalidOperationException("The fragment shader of the current graphics pipeline does not take any samplers!");
}
if (currentGraphicsPipeline.FragmentShaderInfo.SamplerBindingCount < length)
{
throw new System.InvalidOperationException("Fragment sampler count exceeds the amount used by the fragment shader!");
}
#endif
var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length]; var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length];
var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length]; var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length];
@ -485,6 +570,14 @@ namespace MoonWorks.Graphics
params T[] uniforms params T[] uniforms
) where T : unmanaged ) where T : unmanaged
{ {
#if DEBUG
AssertGraphicsPipelineBound();
if (currentGraphicsPipeline.VertexShaderInfo.UniformBufferSize == 0)
{
throw new InvalidOperationException("The current vertex shader does not take a uniform buffer!");
}
#endif
fixed (T* ptr = &uniforms[0]) fixed (T* ptr = &uniforms[0])
{ {
return Refresh.Refresh_PushVertexShaderUniforms( return Refresh.Refresh_PushVertexShaderUniforms(
@ -504,6 +597,15 @@ namespace MoonWorks.Graphics
params T[] uniforms params T[] uniforms
) where T : unmanaged ) where T : unmanaged
{ {
#if DEBUG
AssertGraphicsPipelineBound();
if (currentGraphicsPipeline.FragmentShaderInfo.UniformBufferSize == 0)
{
throw new InvalidOperationException("The current fragment shader does not take a uniform buffer!");
}
#endif
fixed (T* ptr = &uniforms[0]) fixed (T* ptr = &uniforms[0])
{ {
return Refresh.Refresh_PushFragmentShaderUniforms( return Refresh.Refresh_PushFragmentShaderUniforms(
@ -523,6 +625,15 @@ namespace MoonWorks.Graphics
params T[] uniforms params T[] uniforms
) where T : unmanaged ) where T : unmanaged
{ {
#if DEBUG
AssertComputePipelineBound();
if (currentComputePipeline.ComputeShaderInfo.UniformBufferSize == 0)
{
throw new System.InvalidOperationException("The current compute shader does not take a uniform buffer!");
}
#endif
fixed (T* ptr = &uniforms[0]) fixed (T* ptr = &uniforms[0])
{ {
return Refresh.Refresh_PushComputeShaderUniforms( return Refresh.Refresh_PushComputeShaderUniforms(
@ -553,6 +664,10 @@ namespace MoonWorks.Graphics
uint fragmentParamOffset uint fragmentParamOffset
) )
{ {
#if DEBUG
AssertGraphicsPipelineBound();
#endif
Refresh.Refresh_DrawInstancedPrimitives( Refresh.Refresh_DrawInstancedPrimitives(
Device.Handle, Device.Handle,
Handle, Handle,
@ -581,6 +696,10 @@ namespace MoonWorks.Graphics
uint fragmentParamOffset uint fragmentParamOffset
) )
{ {
#if DEBUG
AssertGraphicsPipelineBound();
#endif
Refresh.Refresh_DrawIndexedPrimitives( Refresh.Refresh_DrawIndexedPrimitives(
Device.Handle, Device.Handle,
Handle, Handle,
@ -606,6 +725,10 @@ namespace MoonWorks.Graphics
uint fragmentParamOffset uint fragmentParamOffset
) )
{ {
#if DEBUG
AssertGraphicsPipelineBound();
#endif
Refresh.Refresh_DrawPrimitives( Refresh.Refresh_DrawPrimitives(
Device.Handle, Device.Handle,
Handle, Handle,
@ -634,6 +757,10 @@ namespace MoonWorks.Graphics
uint fragmentParamOffset uint fragmentParamOffset
) )
{ {
#if DEBUG
AssertGraphicsPipelineBound();
#endif
Refresh.Refresh_DrawPrimitivesIndirect( Refresh.Refresh_DrawPrimitivesIndirect(
Device.Handle, Device.Handle,
Handle, Handle,
@ -656,6 +783,9 @@ namespace MoonWorks.Graphics
Device.Handle, Device.Handle,
Handle Handle
); );
currentGraphicsPipeline = null;
renderPassActive = false;
} }
/// <summary> /// <summary>
@ -704,6 +834,10 @@ namespace MoonWorks.Graphics
uint bufferOffsetInBytes = 0 uint bufferOffsetInBytes = 0
) where T : unmanaged ) where T : unmanaged
{ {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
SetBufferData( SetBufferData(
buffer, buffer,
data, data,
@ -728,6 +862,10 @@ namespace MoonWorks.Graphics
uint dataLengthInBytes uint dataLengthInBytes
) )
{ {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
Refresh.Refresh_SetBufferData( Refresh.Refresh_SetBufferData(
Device.Handle, Device.Handle,
Handle, Handle,
@ -755,6 +893,10 @@ namespace MoonWorks.Graphics
uint numElements uint numElements
) where T : unmanaged ) where T : unmanaged
{ {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
var elementSize = sizeof(T); var elementSize = sizeof(T);
fixed (T* ptr = &data[0]) fixed (T* ptr = &data[0])
@ -778,6 +920,10 @@ namespace MoonWorks.Graphics
uint bufferOffsetInElements, uint bufferOffsetInElements,
uint numElements uint numElements
) where T : unmanaged { ) where T : unmanaged {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
Refresh.Refresh_SetBufferData( Refresh.Refresh_SetBufferData(
Device.Handle, Device.Handle,
Handle, Handle,
@ -804,6 +950,10 @@ namespace MoonWorks.Graphics
/// <param name="data">An array of data to copy into the texture.</param> /// <param name="data">An array of data to copy into the texture.</param>
public unsafe void SetTextureData<T>(in TextureSlice textureSlice, T[] data) where T : unmanaged public unsafe void SetTextureData<T>(in TextureSlice textureSlice, T[] data) where T : unmanaged
{ {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
var size = sizeof(T); var size = sizeof(T);
fixed (T* ptr = &data[0]) fixed (T* ptr = &data[0])
@ -826,6 +976,10 @@ namespace MoonWorks.Graphics
/// <param name="dataLengthInBytes">The amount of data to copy from the array.</param> /// <param name="dataLengthInBytes">The amount of data to copy from the array.</param>
public void SetTextureData(in TextureSlice textureSlice, IntPtr dataPtr, uint dataLengthInBytes) public void SetTextureData(in TextureSlice textureSlice, IntPtr dataPtr, uint dataLengthInBytes)
{ {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
Refresh.Refresh_SetTextureData( Refresh.Refresh_SetTextureData(
Device.Handle, Device.Handle,
Handle, Handle,
@ -850,6 +1004,10 @@ namespace MoonWorks.Graphics
/// </summary> /// </summary>
public void SetTextureDataYUV(Texture yTexture, Texture uTexture, Texture vTexture, IntPtr dataPtr, uint dataLengthInBytes) public void SetTextureDataYUV(Texture yTexture, Texture uTexture, Texture vTexture, IntPtr dataPtr, uint dataLengthInBytes)
{ {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
Refresh.Refresh_SetTextureDataYUV( Refresh.Refresh_SetTextureDataYUV(
Device.Handle, Device.Handle,
Handle, Handle,
@ -877,6 +1035,10 @@ namespace MoonWorks.Graphics
Filter filter Filter filter
) )
{ {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
var sourceRefreshTextureSlice = sourceTextureSlice.ToRefreshTextureSlice(); var sourceRefreshTextureSlice = sourceTextureSlice.ToRefreshTextureSlice();
var destRefreshTextureSlice = destinationTextureSlice.ToRefreshTextureSlice(); var destRefreshTextureSlice = destinationTextureSlice.ToRefreshTextureSlice();
@ -900,6 +1062,10 @@ namespace MoonWorks.Graphics
Buffer buffer Buffer buffer
) )
{ {
#if DEBUG
AssertRenderPassInactive("Cannot copy during render pass!");
#endif
var refreshTextureSlice = textureSlice.ToRefreshTextureSlice(); var refreshTextureSlice = textureSlice.ToRefreshTextureSlice();
Refresh.Refresh_CopyTextureToBuffer( Refresh.Refresh_CopyTextureToBuffer(
@ -909,5 +1075,39 @@ namespace MoonWorks.Graphics
buffer.Handle buffer.Handle
); );
} }
#if DEBUG
private void AssertRenderPassActive(string message = "No active render pass!")
{
if (!renderPassActive)
{
throw new System.InvalidOperationException(message);
}
}
private void AssertRenderPassInactive(string message = "Render pass is active!")
{
if (renderPassActive)
{
throw new System.InvalidCastException(message);
}
}
private void AssertGraphicsPipelineBound(string message = "No graphics pipeline is bound!")
{
if (currentGraphicsPipeline == null)
{
throw new System.InvalidOperationException(message);
}
}
private void AssertComputePipelineBound(string message = "No compute pipeline is bound!")
{
if (currentComputePipeline == null)
{
throw new System.InvalidOperationException(message);
}
}
#endif
} }
} }