CreateTextureFromDDS + respect buffer alignment

what_if_no_video_threads
cosmonaut 2024-02-23 11:59:56 -08:00
parent 1eae01c95c
commit 8229e5dd33
1 changed files with 85 additions and 15 deletions

View File

@ -19,7 +19,7 @@ namespace MoonWorks.Graphics
uint dataSize = 1024; uint dataSize = 1024;
List<(GpuBuffer, uint, uint)> BufferUploads = new List<(GpuBuffer, uint, uint)>(); List<(GpuBuffer, uint, uint)> BufferUploads = new List<(GpuBuffer, uint, uint)>();
List<(Texture, uint, uint)> TextureUploads = new List<(Texture, uint, uint)>(); List<(TextureSlice, uint)> TextureUploads = new List<(TextureSlice, uint)>();
public ResourceInitializer(GraphicsDevice device) : base(device) public ResourceInitializer(GraphicsDevice device) : base(device)
{ {
@ -34,15 +34,14 @@ namespace MoonWorks.Graphics
var lengthInBytes = (uint) (Marshal.SizeOf<T>() * data.Length); var lengthInBytes = (uint) (Marshal.SizeOf<T>() * data.Length);
var gpuBuffer = new GpuBuffer(Device, usageFlags, lengthInBytes); var gpuBuffer = new GpuBuffer(Device, usageFlags, lengthInBytes);
BufferUploads.Add((gpuBuffer, dataOffset, lengthInBytes)); uint resourceOffset;
ResizeDataIfNeeded(lengthInBytes);
fixed (void* spanPtr = data) fixed (void* spanPtr = data)
{ {
CopyData(spanPtr, lengthInBytes); resourceOffset = CopyData(spanPtr, lengthInBytes);
} }
BufferUploads.Add((gpuBuffer, resourceOffset, lengthInBytes));
return gpuBuffer; return gpuBuffer;
} }
@ -53,12 +52,11 @@ namespace MoonWorks.Graphics
{ {
var pixelData = ImageUtils.GetPixelDataFromBytes(data, out var width, out var height, out var lengthInBytes); var pixelData = ImageUtils.GetPixelDataFromBytes(data, out var width, out var height, out var lengthInBytes);
var texture = Texture.CreateTexture2D(Device, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler); var texture = Texture.CreateTexture2D(Device, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
TextureUploads.Add((texture, dataOffset, lengthInBytes));
ResizeDataIfNeeded(lengthInBytes); var resourceOffset = CopyData((void*) pixelData, texture.Size);
CopyData((void*) pixelData, lengthInBytes);
ImageUtils.FreePixelData(pixelData); ImageUtils.FreePixelData(pixelData);
TextureUploads.Add((texture, resourceOffset));
return texture; return texture;
} }
@ -88,6 +86,66 @@ namespace MoonWorks.Graphics
return CreateTexture2D(fileStream); return CreateTexture2D(fileStream);
} }
public Texture CreateTextureFromDDS(Stream stream)
{
using var reader = new BinaryReader(stream);
Texture texture;
int faces;
ImageUtils.ParseDDS(reader, out var format, out var width, out var height, out var levels, out var isCube);
if (isCube)
{
texture = Texture.CreateTextureCube(Device, (uint) width, format, TextureUsageFlags.Sampler, (uint) levels);
faces = 6;
}
else
{
texture = Texture.CreateTexture2D(Device, (uint) width, (uint) height, format, TextureUsageFlags.Sampler, (uint) levels);
faces = 1;
}
for (int face = 0; face < faces; face += 1)
{
for (int level = 0; level < levels; level += 1)
{
var levelWidth = width >> level;
var levelHeight = height >> level;
var levelSize = ImageUtils.CalculateDDSLevelSize(levelWidth, levelHeight, format);
var byteBuffer = NativeMemory.Alloc((nuint) levelSize);
var byteSpan = new Span<byte>(byteBuffer, levelSize);
stream.ReadExactly(byteSpan);
var textureSlice = new TextureSlice
{
Texture = texture,
MipLevel = (uint) level,
BaseLayer = (uint) face,
LayerCount = 1,
X = 0,
Y = 0,
Z = 0,
Width = (uint) levelWidth,
Height = (uint) levelHeight,
Depth = 1
};
var resourceOffset = CopyDataAligned(byteBuffer, (uint) levelSize, Texture.TexelSize(format));
TextureUploads.Add((textureSlice, resourceOffset));
NativeMemory.Free(byteBuffer);
}
}
return texture;
}
public Texture CreateTextureFromDDS(string path)
{
var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
return CreateTextureFromDDS(stream);
}
/// <summary> /// <summary>
/// Uploads all the data corresponding to the created resources. /// Uploads all the data corresponding to the created resources.
/// </summary> /// </summary>
@ -119,11 +177,11 @@ namespace MoonWorks.Graphics
); );
} }
foreach (var (texture, offset, size) in TextureUploads) foreach (var (textureSlice, offset) in TextureUploads)
{ {
commandBuffer.UploadToTexture( commandBuffer.UploadToTexture(
TransferBuffer, TransferBuffer,
texture, textureSlice,
new BufferImageCopy( new BufferImageCopy(
offset, offset,
0, 0,
@ -140,19 +198,31 @@ namespace MoonWorks.Graphics
dataOffset = 0; dataOffset = 0;
} }
private void ResizeDataIfNeeded(uint lengthInBytes) private uint CopyData(void* ptr, uint lengthInBytes)
{ {
if (dataOffset + lengthInBytes >= dataSize) if (dataOffset + lengthInBytes >= dataSize)
{ {
dataSize = dataOffset + lengthInBytes; dataSize = dataOffset + lengthInBytes;
data = (byte*) NativeMemory.Realloc(data, dataSize); data = (byte*) NativeMemory.Realloc(data, dataSize);
} }
}
private void CopyData(void* ptr, uint lengthInBytes) var resourceOffset = dataOffset;
{
NativeMemory.Copy(ptr, data + dataOffset, lengthInBytes); NativeMemory.Copy(ptr, data + dataOffset, lengthInBytes);
dataOffset += lengthInBytes; dataOffset += lengthInBytes;
return resourceOffset;
}
private uint CopyDataAligned(void* ptr, uint lengthInBytes, uint alignment)
{
dataOffset = RoundToAlignment(dataOffset, alignment);
return CopyData(ptr, lengthInBytes);
}
private uint RoundToAlignment(uint value, uint alignment)
{
return alignment * ((value + alignment - 1) / alignment);
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)