Debug mode bounds checks for buffer and texture upload
parent
eaa9266521
commit
df3f38a67b
|
@ -1767,6 +1767,7 @@ namespace MoonWorks.Graphics
|
|||
#if DEBUG
|
||||
AssertRenderPassInactive("Cannot copy during render pass!");
|
||||
AssertNonEmptyCopy(dataLengthInBytes);
|
||||
AssertBufferBoundsCheck(buffer.Size, bufferOffsetInBytes, dataLengthInBytes);
|
||||
#endif
|
||||
|
||||
Refresh.Refresh_SetBufferData(
|
||||
|
@ -1803,6 +1804,7 @@ namespace MoonWorks.Graphics
|
|||
#if DEBUG
|
||||
AssertRenderPassInactive("Cannot copy during render pass!");
|
||||
AssertNonEmptyCopy(dataLengthInBytes);
|
||||
AssertBufferBoundsCheck(buffer.Size, bufferOffsetInBytes, dataLengthInBytes);
|
||||
#endif
|
||||
|
||||
fixed (T* ptr = data)
|
||||
|
@ -1847,17 +1849,19 @@ namespace MoonWorks.Graphics
|
|||
{
|
||||
var elementSize = Marshal.SizeOf<T>();
|
||||
var dataLengthInBytes = (uint) (elementSize * numElements);
|
||||
var offsetLengthInBytes = (uint) elementSize * bufferOffsetInElements;
|
||||
|
||||
#if DEBUG
|
||||
AssertRenderPassInactive("Cannot copy during render pass!");
|
||||
AssertNonEmptyCopy((uint) (elementSize * numElements));
|
||||
AssertBufferBoundsCheck(buffer.Size, offsetLengthInBytes, dataLengthInBytes);
|
||||
#endif
|
||||
|
||||
Refresh.Refresh_SetBufferData(
|
||||
Device.Handle,
|
||||
Handle,
|
||||
buffer.Handle,
|
||||
(uint) elementSize * bufferOffsetInElements,
|
||||
offsetLengthInBytes,
|
||||
dataPtr,
|
||||
dataLengthInBytes
|
||||
);
|
||||
|
@ -1888,12 +1892,13 @@ namespace MoonWorks.Graphics
|
|||
/// <param name="data">A span of data to copy into the texture.</param>
|
||||
public unsafe void SetTextureData<T>(in TextureSlice textureSlice, Span<T> data) where T : unmanaged
|
||||
{
|
||||
var dataLengthInBytes = (uint) (data.Length * Marshal.SizeOf<T>());
|
||||
|
||||
#if DEBUG
|
||||
AssertRenderPassInactive("Cannot copy during render pass!");
|
||||
AssertTextureBoundsCheck(textureSlice.Size, dataLengthInBytes);
|
||||
#endif
|
||||
|
||||
var size = sizeof(T);
|
||||
|
||||
fixed (T* ptr = data)
|
||||
{
|
||||
Refresh.Refresh_SetTextureData(
|
||||
|
@ -1901,7 +1906,7 @@ namespace MoonWorks.Graphics
|
|||
Handle,
|
||||
textureSlice.ToRefreshTextureSlice(),
|
||||
(IntPtr) ptr,
|
||||
(uint) (data.Length * size)
|
||||
dataLengthInBytes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1926,6 +1931,7 @@ namespace MoonWorks.Graphics
|
|||
{
|
||||
#if DEBUG
|
||||
AssertRenderPassInactive("Cannot copy during render pass!");
|
||||
AssertTextureBoundsCheck(textureSlice.Size, dataLengthInBytes);
|
||||
#endif
|
||||
|
||||
Refresh.Refresh_SetTextureData(
|
||||
|
@ -2027,6 +2033,7 @@ namespace MoonWorks.Graphics
|
|||
{
|
||||
#if DEBUG
|
||||
AssertRenderPassInactive("Cannot copy during render pass!");
|
||||
AssertBufferBoundsCheck(buffer.Size, 0, textureSlice.Size);
|
||||
#endif
|
||||
|
||||
var refreshTextureSlice = textureSlice.ToRefreshTextureSlice();
|
||||
|
@ -2209,6 +2216,22 @@ namespace MoonWorks.Graphics
|
|||
throw new System.InvalidOperationException("SetBufferData must have a length greater than 0 bytes!");
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertBufferBoundsCheck(uint bufferLengthInBytes, uint offsetInBytes, uint copyLengthInBytes)
|
||||
{
|
||||
if (copyLengthInBytes > bufferLengthInBytes + offsetInBytes)
|
||||
{
|
||||
throw new System.InvalidOperationException($"SetBufferData overflow! buffer length {bufferLengthInBytes}, offset {offsetInBytes}, copy length {copyLengthInBytes}");
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertTextureBoundsCheck(uint textureSizeInBytes, uint dataLengthInBytes)
|
||||
{
|
||||
if (dataLengthInBytes > textureSizeInBytes)
|
||||
{
|
||||
throw new System.InvalidOperationException($"SetTextureData overflow! texture size {textureSizeInBytes}, data size {dataLengthInBytes}");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ namespace MoonWorks.Graphics
|
|||
window.SwapchainFormat = GetSwapchainFormat(window);
|
||||
if (window.SwapchainTexture == null)
|
||||
{
|
||||
window.SwapchainTexture = new Texture(this);
|
||||
window.SwapchainTexture = new Texture(this, window.SwapchainFormat);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace MoonWorks.Graphics
|
|||
public uint LevelCount { get; }
|
||||
public SampleCount SampleCount { get; }
|
||||
public TextureUsageFlags UsageFlags { get; }
|
||||
public uint Size { get; }
|
||||
|
||||
// FIXME: this allocates a delegate instance
|
||||
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyTexture;
|
||||
|
@ -296,6 +297,7 @@ namespace MoonWorks.Graphics
|
|||
LevelCount = textureCreateInfo.LevelCount;
|
||||
SampleCount = textureCreateInfo.SampleCount;
|
||||
UsageFlags = textureCreateInfo.UsageFlags;
|
||||
Size = Width * Height * BytesPerPixel(Format) / BlockSizeSquared(Format);
|
||||
}
|
||||
|
||||
public static implicit operator TextureSlice(Texture t) => new TextureSlice(t);
|
||||
|
@ -303,12 +305,13 @@ namespace MoonWorks.Graphics
|
|||
// Used by AcquireSwapchainTexture.
|
||||
// Should not be tracked, because swapchain textures are managed by Vulkan.
|
||||
internal Texture(
|
||||
GraphicsDevice device
|
||||
GraphicsDevice device,
|
||||
TextureFormat format
|
||||
) : base(device)
|
||||
{
|
||||
Handle = IntPtr.Zero;
|
||||
|
||||
Format = TextureFormat.R8G8B8A8;
|
||||
Format = format;
|
||||
Width = 0;
|
||||
Height = 0;
|
||||
Depth = 1;
|
||||
|
@ -316,6 +319,7 @@ namespace MoonWorks.Graphics
|
|||
LevelCount = 1;
|
||||
SampleCount = SampleCount.One;
|
||||
UsageFlags = TextureUsageFlags.ColorTarget;
|
||||
Size = Width * Height * BytesPerPixel(Format) / BlockSizeSquared(Format);
|
||||
}
|
||||
|
||||
// DDS loading extension, based on MojoDDS
|
||||
|
@ -644,5 +648,96 @@ namespace MoonWorks.Graphics
|
|||
|
||||
NativeMemory.Free(pixelsPtr);
|
||||
}
|
||||
|
||||
public static uint BytesPerPixel(TextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case TextureFormat.R8:
|
||||
case TextureFormat.R8_UINT:
|
||||
return 1;
|
||||
case TextureFormat.R5G6B5:
|
||||
case TextureFormat.B4G4R4A4:
|
||||
case TextureFormat.A1R5G5B5:
|
||||
case TextureFormat.R16_SFLOAT:
|
||||
case TextureFormat.R8G8_SNORM:
|
||||
case TextureFormat.R8G8_UINT:
|
||||
case TextureFormat.R16_UINT:
|
||||
case TextureFormat.D16:
|
||||
return 2;
|
||||
case TextureFormat.D16S8:
|
||||
return 3;
|
||||
case TextureFormat.R8G8B8A8:
|
||||
case TextureFormat.B8G8R8A8:
|
||||
case TextureFormat.R32_SFLOAT:
|
||||
case TextureFormat.R16G16:
|
||||
case TextureFormat.R16G16_SFLOAT:
|
||||
case TextureFormat.R8G8B8A8_SNORM:
|
||||
case TextureFormat.A2R10G10B10:
|
||||
case TextureFormat.R8G8B8A8_UINT:
|
||||
case TextureFormat.R16G16_UINT:
|
||||
case TextureFormat.D32:
|
||||
return 4;
|
||||
case TextureFormat.D32S8:
|
||||
return 5;
|
||||
case TextureFormat.R16G16B16A16_SFLOAT:
|
||||
case TextureFormat.R16G16B16A16:
|
||||
case TextureFormat.R32G32_SFLOAT:
|
||||
case TextureFormat.R16G16B16A16_UINT:
|
||||
case TextureFormat.BC1:
|
||||
return 8;
|
||||
case TextureFormat.R32G32B32A32_SFLOAT:
|
||||
case TextureFormat.BC2:
|
||||
case TextureFormat.BC3:
|
||||
case TextureFormat.BC7:
|
||||
return 16;
|
||||
default:
|
||||
Logger.LogError("Texture format not recognized!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static uint BlockSizeSquared(TextureFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case TextureFormat.BC1:
|
||||
case TextureFormat.BC2:
|
||||
case TextureFormat.BC3:
|
||||
case TextureFormat.BC7:
|
||||
return 16;
|
||||
case TextureFormat.R8G8B8A8:
|
||||
case TextureFormat.B8G8R8A8:
|
||||
case TextureFormat.R5G6B5:
|
||||
case TextureFormat.A1R5G5B5:
|
||||
case TextureFormat.B4G4R4A4:
|
||||
case TextureFormat.A2R10G10B10:
|
||||
case TextureFormat.R16G16:
|
||||
case TextureFormat.R16G16B16A16:
|
||||
case TextureFormat.R8:
|
||||
case TextureFormat.R8G8_SNORM:
|
||||
case TextureFormat.R8G8B8A8_SNORM:
|
||||
case TextureFormat.R16_SFLOAT:
|
||||
case TextureFormat.R16G16_SFLOAT:
|
||||
case TextureFormat.R16G16B16A16_SFLOAT:
|
||||
case TextureFormat.R32_SFLOAT:
|
||||
case TextureFormat.R32G32_SFLOAT:
|
||||
case TextureFormat.R32G32B32A32_SFLOAT:
|
||||
case TextureFormat.R8_UINT:
|
||||
case TextureFormat.R8G8_UINT:
|
||||
case TextureFormat.R8G8B8A8_UINT:
|
||||
case TextureFormat.R16_UINT:
|
||||
case TextureFormat.R16G16_UINT:
|
||||
case TextureFormat.R16G16B16A16_UINT:
|
||||
case TextureFormat.D16:
|
||||
case TextureFormat.D32:
|
||||
case TextureFormat.D16S8:
|
||||
case TextureFormat.D32S8:
|
||||
return 1;
|
||||
default:
|
||||
Logger.LogError("Texture format not recognized!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace MoonWorks.Graphics
|
|||
public uint Layer { get; }
|
||||
public uint Level { get; }
|
||||
|
||||
public uint Size => (uint) (Rectangle.W * Rectangle.H * Texture.BytesPerPixel(Texture.Format) / Texture.BlockSizeSquared(Texture.Format));
|
||||
|
||||
public TextureSlice(Texture texture)
|
||||
{
|
||||
Texture = texture;
|
||||
|
|
Loading…
Reference in New Issue