Refresh 2 changes
parent
bb7e45b9a3
commit
39496c37ea
|
@ -1 +1 @@
|
||||||
Subproject commit b5325e6d0329eeb35b074091a569a5f679852d28
|
Subproject commit ad0b168c4794ee0377c825b0149a0d21bd856e43
|
|
@ -5,10 +5,10 @@
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct BufferBinding
|
public struct BufferBinding
|
||||||
{
|
{
|
||||||
public Buffer Buffer;
|
public GpuBuffer Buffer;
|
||||||
public ulong Offset;
|
public ulong Offset;
|
||||||
|
|
||||||
public BufferBinding(Buffer buffer, ulong offset)
|
public BufferBinding(GpuBuffer buffer, ulong offset)
|
||||||
{
|
{
|
||||||
Buffer = buffer;
|
Buffer = buffer;
|
||||||
Offset = offset;
|
Offset = offset;
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
namespace MoonWorks.Graphics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A texture-level pair to be used when binding compute textures.
|
||||||
|
/// </summary>
|
||||||
|
public struct TextureLevelBinding
|
||||||
|
{
|
||||||
|
public Texture Texture;
|
||||||
|
public uint MipLevel;
|
||||||
|
|
||||||
|
public TextureLevelBinding(Texture texture, uint mipLevel = 0)
|
||||||
|
{
|
||||||
|
Texture = texture;
|
||||||
|
MipLevel = mipLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -47,8 +47,26 @@ namespace MoonWorks.Graphics.Font
|
||||||
out float distanceRange
|
out float distanceRange
|
||||||
);
|
);
|
||||||
|
|
||||||
var texture = Texture.FromImageFile(graphicsDevice, commandBuffer, Path.ChangeExtension(fontPath, ".png"));
|
var imagePath = Path.ChangeExtension(fontPath, ".png");
|
||||||
|
ImageUtils.ImageInfoFromFile(imagePath, out var width, out var height, out var sizeInBytes);
|
||||||
|
var texture = Texture.CreateTexture2D(graphicsDevice, width, height, TextureFormat.R8G8B8A8, TextureUsageFlags.Sampler);
|
||||||
|
|
||||||
|
var cpuBuffer = new CpuBuffer(graphicsDevice, sizeInBytes);
|
||||||
|
ImageUtils.DecodeIntoCpuBuffer(
|
||||||
|
imagePath,
|
||||||
|
cpuBuffer,
|
||||||
|
0,
|
||||||
|
SetDataOptions.Overwrite
|
||||||
|
);
|
||||||
|
|
||||||
|
commandBuffer.BeginCopyPass();
|
||||||
|
commandBuffer.UploadToTexture(
|
||||||
|
cpuBuffer,
|
||||||
|
texture
|
||||||
|
);
|
||||||
|
commandBuffer.EndCopyPass();
|
||||||
|
|
||||||
|
cpuBuffer.Dispose();
|
||||||
NativeMemory.Free(fontFileByteBuffer);
|
NativeMemory.Free(fontFileByteBuffer);
|
||||||
NativeMemory.Free(atlasFileByteBuffer);
|
NativeMemory.Free(atlasFileByteBuffer);
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,12 @@ namespace MoonWorks.Graphics.Font
|
||||||
private GraphicsDevice GraphicsDevice { get; }
|
private GraphicsDevice GraphicsDevice { get; }
|
||||||
public IntPtr Handle { get; }
|
public IntPtr Handle { get; }
|
||||||
|
|
||||||
public Buffer VertexBuffer { get; protected set; } = null;
|
public GpuBuffer VertexBuffer { get; protected set; } = null;
|
||||||
public Buffer IndexBuffer { get; protected set; } = null;
|
public GpuBuffer IndexBuffer { get; protected set; } = null;
|
||||||
public uint PrimitiveCount { get; protected set; }
|
public uint PrimitiveCount { get; protected set; }
|
||||||
|
|
||||||
|
private CpuBuffer TransferBuffer;
|
||||||
|
|
||||||
public Font CurrentFont { get; private set; }
|
public Font CurrentFont { get; private set; }
|
||||||
|
|
||||||
private byte* StringBytes;
|
private byte* StringBytes;
|
||||||
|
@ -30,8 +32,10 @@ namespace MoonWorks.Graphics.Font
|
||||||
StringBytesLength = 128;
|
StringBytesLength = 128;
|
||||||
StringBytes = (byte*) NativeMemory.Alloc((nuint) StringBytesLength);
|
StringBytes = (byte*) NativeMemory.Alloc((nuint) StringBytesLength);
|
||||||
|
|
||||||
VertexBuffer = Buffer.Create<Vertex>(GraphicsDevice, BufferUsageFlags.Vertex, INITIAL_VERTEX_COUNT);
|
VertexBuffer = GpuBuffer.Create<Vertex>(GraphicsDevice, BufferUsageFlags.Vertex, INITIAL_VERTEX_COUNT);
|
||||||
IndexBuffer = Buffer.Create<uint>(GraphicsDevice, BufferUsageFlags.Index, INITIAL_INDEX_COUNT);
|
IndexBuffer = GpuBuffer.Create<uint>(GraphicsDevice, BufferUsageFlags.Index, INITIAL_INDEX_COUNT);
|
||||||
|
|
||||||
|
TransferBuffer = CpuBuffer.Create<byte>(GraphicsDevice, VertexBuffer.Size + IndexBuffer.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this to initialize or reset the batch.
|
// Call this to initialize or reset the batch.
|
||||||
|
@ -93,22 +97,38 @@ namespace MoonWorks.Graphics.Font
|
||||||
out uint indexDataLengthInBytes
|
out uint indexDataLengthInBytes
|
||||||
);
|
);
|
||||||
|
|
||||||
|
var vertexSpan = new Span<byte>((void*) vertexDataPointer, (int) vertexDataLengthInBytes);
|
||||||
|
var indexSpan = new Span<byte>((void*) indexDataPointer, (int) indexDataLengthInBytes);
|
||||||
|
|
||||||
|
var newTransferBufferNeeded = false;
|
||||||
|
|
||||||
if (VertexBuffer.Size < vertexDataLengthInBytes)
|
if (VertexBuffer.Size < vertexDataLengthInBytes)
|
||||||
{
|
{
|
||||||
VertexBuffer.Dispose();
|
VertexBuffer.Dispose();
|
||||||
VertexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Vertex, vertexDataLengthInBytes);
|
VertexBuffer = new GpuBuffer(GraphicsDevice, BufferUsageFlags.Vertex, vertexDataLengthInBytes);
|
||||||
|
newTransferBufferNeeded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IndexBuffer.Size < indexDataLengthInBytes)
|
if (IndexBuffer.Size < indexDataLengthInBytes)
|
||||||
{
|
{
|
||||||
IndexBuffer.Dispose();
|
IndexBuffer.Dispose();
|
||||||
IndexBuffer = new Buffer(GraphicsDevice, BufferUsageFlags.Index, vertexDataLengthInBytes);
|
IndexBuffer = new GpuBuffer(GraphicsDevice, BufferUsageFlags.Index, vertexDataLengthInBytes);
|
||||||
|
newTransferBufferNeeded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newTransferBufferNeeded)
|
||||||
|
{
|
||||||
|
TransferBuffer.Dispose();
|
||||||
|
TransferBuffer = new CpuBuffer(GraphicsDevice, VertexBuffer.Size + IndexBuffer.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexDataLengthInBytes > 0 && indexDataLengthInBytes > 0)
|
if (vertexDataLengthInBytes > 0 && indexDataLengthInBytes > 0)
|
||||||
{
|
{
|
||||||
commandBuffer.SetBufferData(VertexBuffer, vertexDataPointer, 0, vertexDataLengthInBytes);
|
TransferBuffer.SetData(vertexSpan, SetDataOptions.Discard);
|
||||||
commandBuffer.SetBufferData(IndexBuffer, indexDataPointer, 0, indexDataLengthInBytes);
|
TransferBuffer.SetData(indexSpan, (uint) vertexSpan.Length, SetDataOptions.Overwrite);
|
||||||
|
|
||||||
|
commandBuffer.UploadToBuffer(TransferBuffer, VertexBuffer, new BufferCopy(0, 0, (uint) vertexSpan.Length));
|
||||||
|
commandBuffer.UploadToBuffer(TransferBuffer, IndexBuffer, new BufferCopy((uint) vertexSpan.Length, 0, (uint) indexSpan.Length));
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimitiveCount = vertexCount / 2;
|
PrimitiveCount = vertexCount / 2;
|
||||||
|
@ -123,12 +143,12 @@ namespace MoonWorks.Graphics.Font
|
||||||
));
|
));
|
||||||
commandBuffer.BindVertexBuffers(VertexBuffer);
|
commandBuffer.BindVertexBuffers(VertexBuffer);
|
||||||
commandBuffer.BindIndexBuffer(IndexBuffer, IndexElementSize.ThirtyTwo);
|
commandBuffer.BindIndexBuffer(IndexBuffer, IndexElementSize.ThirtyTwo);
|
||||||
|
commandBuffer.PushVertexShaderUniforms(transformMatrix);
|
||||||
|
commandBuffer.PushFragmentShaderUniforms(CurrentFont.DistanceRange);
|
||||||
commandBuffer.DrawIndexedPrimitives(
|
commandBuffer.DrawIndexedPrimitives(
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
PrimitiveCount,
|
PrimitiveCount
|
||||||
commandBuffer.PushVertexShaderUniforms(transformMatrix),
|
|
||||||
commandBuffer.PushFragmentShaderUniforms(CurrentFont.DistanceRange)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using RefreshCS;
|
||||||
|
|
||||||
|
namespace MoonWorks.Graphics
|
||||||
|
{
|
||||||
|
public static class ImageUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets pointer to pixel data from compressed image byte data.
|
||||||
|
///
|
||||||
|
/// The returned pointer must be freed by calling FreePixelData.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe IntPtr GetPixelDataFromBytes(
|
||||||
|
Span<byte> data,
|
||||||
|
out uint width,
|
||||||
|
out uint height,
|
||||||
|
out uint sizeInBytes
|
||||||
|
) {
|
||||||
|
fixed (byte* ptr = data)
|
||||||
|
{
|
||||||
|
var pixelData =
|
||||||
|
Refresh.Refresh_Image_Load(
|
||||||
|
(nint) ptr,
|
||||||
|
data.Length,
|
||||||
|
out var w,
|
||||||
|
out var h,
|
||||||
|
out var len
|
||||||
|
);
|
||||||
|
|
||||||
|
width = (uint) w;
|
||||||
|
height = (uint) h;
|
||||||
|
sizeInBytes = (uint) len;
|
||||||
|
|
||||||
|
return pixelData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets pointer to pixel data from a compressed image stream.
|
||||||
|
///
|
||||||
|
/// The returned pointer must be freed by calling FreePixelData.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe IntPtr GetPixelDataFromStream(
|
||||||
|
Stream stream,
|
||||||
|
out uint width,
|
||||||
|
out uint height,
|
||||||
|
out uint sizeInBytes
|
||||||
|
) {
|
||||||
|
var length = stream.Length;
|
||||||
|
var buffer = NativeMemory.Alloc((nuint) length);
|
||||||
|
var span = new Span<byte>(buffer, (int) length);
|
||||||
|
stream.ReadExactly(span);
|
||||||
|
|
||||||
|
var pixelData = GetPixelDataFromBytes(span, out width, out height, out sizeInBytes);
|
||||||
|
|
||||||
|
NativeMemory.Free(buffer);
|
||||||
|
|
||||||
|
return pixelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets pointer to pixel data from a compressed image file.
|
||||||
|
///
|
||||||
|
/// The returned pointer must be freed by calling FreePixelData.
|
||||||
|
/// </summary>
|
||||||
|
public static IntPtr GetPixelDataFromFile(
|
||||||
|
string path,
|
||||||
|
out uint width,
|
||||||
|
out uint height,
|
||||||
|
out uint sizeInBytes
|
||||||
|
) {
|
||||||
|
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
|
return GetPixelDataFromStream(fileStream, out width, out height, out sizeInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get metadata from compressed image bytes.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe bool ImageInfoFromBytes(
|
||||||
|
Span<byte> data,
|
||||||
|
out uint width,
|
||||||
|
out uint height,
|
||||||
|
out uint sizeInBytes
|
||||||
|
) {
|
||||||
|
fixed (byte* ptr = data)
|
||||||
|
{
|
||||||
|
var result =
|
||||||
|
Refresh.Refresh_Image_Info(
|
||||||
|
(nint) ptr,
|
||||||
|
data.Length,
|
||||||
|
out var w,
|
||||||
|
out var h,
|
||||||
|
out var len
|
||||||
|
);
|
||||||
|
|
||||||
|
width = (uint) w;
|
||||||
|
height = (uint) h;
|
||||||
|
sizeInBytes = (uint) len;
|
||||||
|
|
||||||
|
return Conversions.ByteToBool(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get metadata from a compressed image stream.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe bool ImageInfoFromStream(
|
||||||
|
Stream stream,
|
||||||
|
out uint width,
|
||||||
|
out uint height,
|
||||||
|
out uint sizeInBytes
|
||||||
|
) {
|
||||||
|
var length = stream.Length;
|
||||||
|
var buffer = NativeMemory.Alloc((nuint) length);
|
||||||
|
var span = new Span<byte>(buffer, (int) length);
|
||||||
|
stream.ReadExactly(span);
|
||||||
|
|
||||||
|
var result = ImageInfoFromBytes(span, out width, out height, out sizeInBytes);
|
||||||
|
|
||||||
|
NativeMemory.Free(buffer);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get metadata from a compressed image file.
|
||||||
|
/// </summary>
|
||||||
|
public static bool ImageInfoFromFile(
|
||||||
|
string path,
|
||||||
|
out uint width,
|
||||||
|
out uint height,
|
||||||
|
out uint sizeInBytes
|
||||||
|
) {
|
||||||
|
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
|
return ImageInfoFromStream(fileStream, out width, out height, out sizeInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Frees pixel data obtained from GetPixelData methods.
|
||||||
|
/// </summary>
|
||||||
|
public static void FreePixelData(IntPtr pixels)
|
||||||
|
{
|
||||||
|
Refresh.Refresh_Image_Free(pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes image data into a CpuBuffer to prepare for image upload.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe uint DecodeIntoCpuBuffer(
|
||||||
|
Span<byte> data,
|
||||||
|
CpuBuffer cpuBuffer,
|
||||||
|
uint bufferOffsetInBytes,
|
||||||
|
SetDataOptions option
|
||||||
|
) {
|
||||||
|
var pixelData = GetPixelDataFromBytes(data, out var w, out var h, out var sizeInBytes);
|
||||||
|
var length = cpuBuffer.SetData(new Span<byte>((void*) pixelData, (int) sizeInBytes), bufferOffsetInBytes, option);
|
||||||
|
FreePixelData(pixelData);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes an image stream into a CpuBuffer to prepare for image upload.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe uint DecodeIntoCpuBuffer(
|
||||||
|
Stream stream,
|
||||||
|
CpuBuffer cpuBuffer,
|
||||||
|
uint bufferOffsetInBytes,
|
||||||
|
SetDataOptions option
|
||||||
|
) {
|
||||||
|
var pixelData = GetPixelDataFromStream(stream, out var w, out var h, out var sizeInBytes);
|
||||||
|
var length = cpuBuffer.SetData(new Span<byte>((void*) pixelData, (int) sizeInBytes), bufferOffsetInBytes, option);
|
||||||
|
FreePixelData(pixelData);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes an image file into a CpuBuffer to prepare for image upload.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe uint DecodeIntoCpuBuffer(
|
||||||
|
string path,
|
||||||
|
CpuBuffer cpuBuffer,
|
||||||
|
uint bufferOffsetInBytes,
|
||||||
|
SetDataOptions option
|
||||||
|
) {
|
||||||
|
var pixelData = GetPixelDataFromFile(path, out var w, out var h, out var sizeInBytes);
|
||||||
|
var length = cpuBuffer.SetData(new Span<byte>((void*) pixelData, (int) sizeInBytes), bufferOffsetInBytes, option);
|
||||||
|
FreePixelData(pixelData);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves pixel data contained in a CpuBuffer to a PNG file.
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe void SavePNG(
|
||||||
|
string path,
|
||||||
|
CpuBuffer cpuBuffer,
|
||||||
|
uint bufferOffsetInBytes,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
bool bgra
|
||||||
|
) {
|
||||||
|
var sizeInBytes = width * height * 4;
|
||||||
|
|
||||||
|
var pixelsPtr = NativeMemory.Alloc((nuint) sizeInBytes);
|
||||||
|
var pixelsSpan = new Span<byte>(pixelsPtr, sizeInBytes);
|
||||||
|
|
||||||
|
cpuBuffer.GetData(pixelsSpan, bufferOffsetInBytes);
|
||||||
|
|
||||||
|
if (bgra)
|
||||||
|
{
|
||||||
|
// if data is bgra, we have to swap the R and B channels
|
||||||
|
var rgbaPtr = NativeMemory.Alloc((nuint) sizeInBytes);
|
||||||
|
var rgbaSpan = new Span<byte>(rgbaPtr, sizeInBytes);
|
||||||
|
|
||||||
|
for (var i = 0; i < sizeInBytes; i += 4)
|
||||||
|
{
|
||||||
|
rgbaSpan[i] = pixelsSpan[i + 2];
|
||||||
|
rgbaSpan[i + 1] = pixelsSpan[i + 1];
|
||||||
|
rgbaSpan[i + 2] = pixelsSpan[i];
|
||||||
|
rgbaSpan[i + 3] = pixelsSpan[i + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeMemory.Free(pixelsPtr);
|
||||||
|
pixelsPtr = rgbaPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Refresh.Refresh_Image_SavePNG(path, (nint) pixelsPtr, width, height);
|
||||||
|
NativeMemory.Free(pixelsPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -297,6 +297,12 @@ namespace MoonWorks.Graphics
|
||||||
IntOpaqueWhite
|
IntOpaqueWhite
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum SetDataOptions
|
||||||
|
{
|
||||||
|
Discard,
|
||||||
|
Overwrite
|
||||||
|
}
|
||||||
|
|
||||||
public enum Backend
|
public enum Backend
|
||||||
{
|
{
|
||||||
DontCare,
|
DontCare,
|
||||||
|
|
|
@ -354,4 +354,60 @@ namespace MoonWorks.Graphics
|
||||||
FirstInstance = firstInstance;
|
FirstInstance = firstInstance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct BufferCopy
|
||||||
|
{
|
||||||
|
public uint SrcOffset;
|
||||||
|
public uint DstOffset;
|
||||||
|
public uint Size;
|
||||||
|
|
||||||
|
public BufferCopy(
|
||||||
|
uint srcOffset,
|
||||||
|
uint dstOffset,
|
||||||
|
uint size
|
||||||
|
) {
|
||||||
|
SrcOffset = srcOffset;
|
||||||
|
DstOffset = dstOffset;
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Refresh.BufferCopy ToRefresh()
|
||||||
|
{
|
||||||
|
return new Refresh.BufferCopy
|
||||||
|
{
|
||||||
|
srcOffset = SrcOffset,
|
||||||
|
dstOffset = DstOffset,
|
||||||
|
size = Size
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct BufferImageCopy
|
||||||
|
{
|
||||||
|
public uint BufferOffset;
|
||||||
|
public uint BufferStride; // if 0, image assumed to be tightly packed
|
||||||
|
public uint BufferImageHeight; // if 0, image assumed to be tightly packed
|
||||||
|
|
||||||
|
public BufferImageCopy(
|
||||||
|
uint bufferOffset,
|
||||||
|
uint bufferStride,
|
||||||
|
uint bufferImageHeight
|
||||||
|
) {
|
||||||
|
BufferOffset = bufferOffset;
|
||||||
|
BufferStride = bufferStride;
|
||||||
|
BufferImageHeight = bufferImageHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Refresh.BufferImageCopy ToRefresh()
|
||||||
|
{
|
||||||
|
return new Refresh.BufferImageCopy
|
||||||
|
{
|
||||||
|
bufferOffset = BufferOffset,
|
||||||
|
bufferStride = BufferStride,
|
||||||
|
bufferImageHeight = BufferImageHeight
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace MoonWorks.Graphics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A convenience structure for simultaneously creating resources and uploading their data.
|
||||||
|
///
|
||||||
|
/// Note that Upload must be called after the Create methods for the data to actually be uploaded.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe class ResourceInitializer : GraphicsResource
|
||||||
|
{
|
||||||
|
CpuBuffer TransferBuffer;
|
||||||
|
|
||||||
|
byte* data;
|
||||||
|
uint dataOffset = 0;
|
||||||
|
uint dataSize = 1024;
|
||||||
|
|
||||||
|
List<(GpuBuffer, uint, uint)> BufferUploads = new List<(GpuBuffer, uint, uint)>();
|
||||||
|
List<(Texture, uint, uint)> TextureUploads = new List<(Texture, uint, uint)>();
|
||||||
|
|
||||||
|
public ResourceInitializer(GraphicsDevice device) : base(device)
|
||||||
|
{
|
||||||
|
data = (byte*) NativeMemory.Alloc(dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a GpuBuffer with data to be uploaded.
|
||||||
|
/// </summary>
|
||||||
|
public GpuBuffer CreateBuffer<T>(Span<T> data, BufferUsageFlags usageFlags) where T : unmanaged
|
||||||
|
{
|
||||||
|
var lengthInBytes = (uint) (Marshal.SizeOf<T>() * data.Length);
|
||||||
|
var gpuBuffer = new GpuBuffer(Device, usageFlags, lengthInBytes);
|
||||||
|
|
||||||
|
BufferUploads.Add((gpuBuffer, dataOffset, lengthInBytes));
|
||||||
|
|
||||||
|
ResizeDataIfNeeded(lengthInBytes);
|
||||||
|
|
||||||
|
fixed (void* spanPtr = data)
|
||||||
|
{
|
||||||
|
CopyData(spanPtr, lengthInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gpuBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a 2D Texture from compressed image data to be uploaded.
|
||||||
|
/// </summary>
|
||||||
|
public Texture CreateTexture2D(Span<byte> data)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
TextureUploads.Add((texture, dataOffset, lengthInBytes));
|
||||||
|
|
||||||
|
ResizeDataIfNeeded(lengthInBytes);
|
||||||
|
CopyData((void*) pixelData, lengthInBytes);
|
||||||
|
ImageUtils.FreePixelData(pixelData);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a 2D Texture from a compressed image stream to be uploaded.
|
||||||
|
/// </summary>
|
||||||
|
public Texture CreateTexture2D(Stream stream)
|
||||||
|
{
|
||||||
|
var length = stream.Length;
|
||||||
|
var buffer = NativeMemory.Alloc((nuint) length);
|
||||||
|
var span = new Span<byte>(buffer, (int) length);
|
||||||
|
stream.ReadExactly(span);
|
||||||
|
|
||||||
|
var texture = CreateTexture2D(span);
|
||||||
|
|
||||||
|
NativeMemory.Free(buffer);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a 2D Texture from a compressed image file to be uploaded.
|
||||||
|
/// </summary>
|
||||||
|
public Texture CreateTexture2D(string path)
|
||||||
|
{
|
||||||
|
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
|
return CreateTexture2D(fileStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uploads all the data corresponding to the created resources.
|
||||||
|
/// </summary>
|
||||||
|
public void Upload()
|
||||||
|
{
|
||||||
|
if (TransferBuffer == null || TransferBuffer.Size < dataSize)
|
||||||
|
{
|
||||||
|
TransferBuffer?.Dispose();
|
||||||
|
TransferBuffer = new CpuBuffer(Device, dataSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransferBuffer.SetData(data, new BufferCopy(0, 0, dataSize), SetDataOptions.Discard);
|
||||||
|
|
||||||
|
var commandBuffer = Device.AcquireCommandBuffer();
|
||||||
|
|
||||||
|
commandBuffer.BeginCopyPass();
|
||||||
|
|
||||||
|
foreach (var (gpuBuffer, offset, size) in BufferUploads)
|
||||||
|
{
|
||||||
|
commandBuffer.UploadToBuffer(
|
||||||
|
TransferBuffer,
|
||||||
|
gpuBuffer,
|
||||||
|
new BufferCopy(
|
||||||
|
offset,
|
||||||
|
0,
|
||||||
|
size
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (texture, offset, size) in TextureUploads)
|
||||||
|
{
|
||||||
|
commandBuffer.UploadToTexture(
|
||||||
|
TransferBuffer,
|
||||||
|
texture,
|
||||||
|
new BufferImageCopy(
|
||||||
|
offset,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
commandBuffer.EndCopyPass();
|
||||||
|
Device.Submit(commandBuffer);
|
||||||
|
|
||||||
|
BufferUploads.Clear();
|
||||||
|
TextureUploads.Clear();
|
||||||
|
dataOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResizeDataIfNeeded(uint lengthInBytes)
|
||||||
|
{
|
||||||
|
if (dataOffset + lengthInBytes >= dataSize)
|
||||||
|
{
|
||||||
|
dataSize = dataOffset + lengthInBytes;
|
||||||
|
data = (byte*) NativeMemory.Realloc(data, dataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CopyData(void* ptr, uint lengthInBytes)
|
||||||
|
{
|
||||||
|
NativeMemory.Copy(ptr, data + dataOffset, lengthInBytes);
|
||||||
|
dataOffset += lengthInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!IsDisposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
TransferBuffer.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeMemory.Free(data);
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,141 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using RefreshCS;
|
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Buffers are generic data containers that can be used by the GPU.
|
|
||||||
/// </summary>
|
|
||||||
public class Buffer : RefreshResource
|
|
||||||
{
|
|
||||||
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyBuffer;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Size in bytes.
|
|
||||||
/// </summary>
|
|
||||||
public uint Size { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a buffer of appropriate size given a type and element count.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type that the buffer will contain.</typeparam>
|
|
||||||
/// <param name="device">The GraphicsDevice.</param>
|
|
||||||
/// <param name="usageFlags">Specifies how the buffer will be used.</param>
|
|
||||||
/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public unsafe static Buffer Create<T>(
|
|
||||||
GraphicsDevice device,
|
|
||||||
BufferUsageFlags usageFlags,
|
|
||||||
uint elementCount
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
return new Buffer(
|
|
||||||
device,
|
|
||||||
usageFlags,
|
|
||||||
(uint) Marshal.SizeOf<T>() * elementCount
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="device">An initialized GraphicsDevice.</param>
|
|
||||||
/// <param name="usageFlags">Specifies how the buffer will be used.</param>
|
|
||||||
/// <param name="sizeInBytes">The length of the array. Cannot be resized.</param>
|
|
||||||
public Buffer(
|
|
||||||
GraphicsDevice device,
|
|
||||||
BufferUsageFlags usageFlags,
|
|
||||||
uint sizeInBytes
|
|
||||||
) : base(device)
|
|
||||||
{
|
|
||||||
Handle = Refresh.Refresh_CreateBuffer(
|
|
||||||
device.Handle,
|
|
||||||
(Refresh.BufferUsageFlags) usageFlags,
|
|
||||||
sizeInBytes
|
|
||||||
);
|
|
||||||
Size = sizeInBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads data out of a buffer and into a span.
|
|
||||||
/// This operation is only guaranteed to read up-to-date data if GraphicsDevice.Wait or GraphicsDevice.WaitForFences is called first.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The span that data will be copied to.</param>
|
|
||||||
/// <param name="dataLengthInBytes">The length of the data to read.</param>
|
|
||||||
public unsafe void GetData<T>(
|
|
||||||
Span<T> data,
|
|
||||||
uint dataLengthInBytes
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if (dataLengthInBytes > Size)
|
|
||||||
{
|
|
||||||
Logger.LogWarn("Requested too many bytes from buffer!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataLengthInBytes > data.Length * Marshal.SizeOf<T>())
|
|
||||||
{
|
|
||||||
Logger.LogWarn("Data length is larger than the provided Span!");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fixed (T* ptr = data)
|
|
||||||
{
|
|
||||||
Refresh.Refresh_GetBufferData(
|
|
||||||
Device.Handle,
|
|
||||||
Handle,
|
|
||||||
(IntPtr) ptr,
|
|
||||||
dataLengthInBytes
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads data out of a buffer and into an array.
|
|
||||||
/// This operation is only guaranteed to read up-to-date data if GraphicsDevice.Wait or GraphicsDevice.WaitForFences is called first.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The span that data will be copied to.</param>
|
|
||||||
/// <param name="dataLengthInBytes">The length of the data to read.</param>
|
|
||||||
public unsafe void GetData<T>(
|
|
||||||
T[] data,
|
|
||||||
uint dataLengthInBytes
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
GetData(new Span<T>(data), dataLengthInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads data out of a buffer and into a span.
|
|
||||||
/// This operation is only guaranteed to read up-to-date data if GraphicsDevice.Wait or GraphicsDevice.WaitForFences is called first.
|
|
||||||
/// Fills the span with as much data from the buffer as it can.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The span that data will be copied to.</param>
|
|
||||||
public unsafe void GetData<T>(
|
|
||||||
Span<T> data
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
var lengthInBytes = System.Math.Min(data.Length * Marshal.SizeOf<T>(), Size);
|
|
||||||
GetData(data, (uint) lengthInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads data out of a buffer and into an array.
|
|
||||||
/// This operation is only guaranteed to read up-to-date data if GraphicsDevice.Wait or GraphicsDevice.WaitForFences is called first.
|
|
||||||
/// Fills the array with as much data from the buffer as it can.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The span that data will be copied to.</param>
|
|
||||||
public unsafe void GetData<T>(
|
|
||||||
T[] data
|
|
||||||
) where T : unmanaged
|
|
||||||
{
|
|
||||||
var lengthInBytes = System.Math.Min(data.Length * Marshal.SizeOf<T>(), Size);
|
|
||||||
GetData(new Span<T>(data), (uint) lengthInBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator BufferBinding(Buffer b)
|
|
||||||
{
|
|
||||||
return new BufferBinding(b, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using RefreshCS;
|
||||||
|
|
||||||
|
namespace MoonWorks.Graphics
|
||||||
|
{
|
||||||
|
public unsafe class CpuBuffer : RefreshResource
|
||||||
|
{
|
||||||
|
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyCpuBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size in bytes.
|
||||||
|
/// </summary>
|
||||||
|
public uint Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a buffer of requested size given a type and element count.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type that the buffer will contain.</typeparam>
|
||||||
|
/// <param name="device">The GraphicsDevice.</param>
|
||||||
|
/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public unsafe static CpuBuffer Create<T>(
|
||||||
|
GraphicsDevice device,
|
||||||
|
uint elementCount
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
return new CpuBuffer(
|
||||||
|
device,
|
||||||
|
(uint) Marshal.SizeOf<T>() * elementCount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a CpuBuffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">An initialized GraphicsDevice.</param>
|
||||||
|
/// <param name="sizeInBytes">The length of the buffer. Cannot be resized.</param>
|
||||||
|
public CpuBuffer(
|
||||||
|
GraphicsDevice device,
|
||||||
|
uint sizeInBytes
|
||||||
|
) : base(device)
|
||||||
|
{
|
||||||
|
Handle = Refresh.Refresh_CreateCpuBuffer(
|
||||||
|
device.Handle,
|
||||||
|
sizeInBytes
|
||||||
|
);
|
||||||
|
Size = sizeInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Immediately copies data from a data pointer to the CpuBuffer.
|
||||||
|
///
|
||||||
|
/// If setDataOption is DISCARD and this CpuBuffer was used in an Upload command,
|
||||||
|
/// that command will still use the correct data at the cost of increased memory usage.
|
||||||
|
///
|
||||||
|
/// If setDataOption is OVERWRITE and this CpuBuffer was used in an Upload command,
|
||||||
|
/// this could cause a data race.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe void SetData(
|
||||||
|
byte* dataPtr,
|
||||||
|
in BufferCopy copyParams,
|
||||||
|
SetDataOptions setDataOption
|
||||||
|
) {
|
||||||
|
Refresh.Refresh_SetData(
|
||||||
|
Device.Handle,
|
||||||
|
(nint) dataPtr,
|
||||||
|
Handle,
|
||||||
|
copyParams.ToRefresh(),
|
||||||
|
(Refresh.SetDataOptions) setDataOption
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Immediately copies data from a Span to the CpuBuffer.
|
||||||
|
/// Returns the length of the copy in bytes.
|
||||||
|
///
|
||||||
|
/// If setDataOption is DISCARD and this CpuBuffer was used in an Upload command,
|
||||||
|
/// that command will still use the correct data at the cost of increased memory usage.
|
||||||
|
///
|
||||||
|
/// If setDataOption is OVERWRITE and this CpuBuffer was used in an Upload command,
|
||||||
|
/// the data will be overwritten immediately, which could cause a data race.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe uint SetData<T>(
|
||||||
|
Span<T> data,
|
||||||
|
uint bufferOffsetInBytes,
|
||||||
|
SetDataOptions setDataOption
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
var elementSize = Marshal.SizeOf<T>();
|
||||||
|
var dataLengthInBytes = (uint) (elementSize * data.Length);
|
||||||
|
|
||||||
|
fixed (T* dataPtr = data)
|
||||||
|
{
|
||||||
|
SetData(
|
||||||
|
(byte*) dataPtr,
|
||||||
|
new BufferCopy(0, bufferOffsetInBytes, dataLengthInBytes),
|
||||||
|
setDataOption
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataLengthInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Immediately copies data from a Span to the CpuBuffer.
|
||||||
|
/// Returns the length of the copy in bytes.
|
||||||
|
///
|
||||||
|
/// If setDataOption is DISCARD and this CpuBuffer was used in an Upload command,
|
||||||
|
/// that command will still use the correct data at the cost of increased memory usage.
|
||||||
|
///
|
||||||
|
/// If setDataOption is OVERWRITE and this CpuBuffer was used in an Upload command,
|
||||||
|
/// the data will be overwritten immediately, which could cause a data race.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe uint SetData<T>(
|
||||||
|
Span<T> data,
|
||||||
|
SetDataOptions setDataOption
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
return SetData(data, 0, setDataOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Immediately copies data from the CpuBuffer into a data pointer.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe void GetData(
|
||||||
|
byte* dataPtr,
|
||||||
|
in BufferCopy copyParams
|
||||||
|
) {
|
||||||
|
Refresh.Refresh_GetData(
|
||||||
|
Device.Handle,
|
||||||
|
Handle,
|
||||||
|
(nint) dataPtr,
|
||||||
|
copyParams.ToRefresh()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Immediately copies data from the CpuBuffer into a Span.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe void GetData<T>(
|
||||||
|
Span<T> data,
|
||||||
|
uint bufferOffsetInBytes
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
var elementSize = Marshal.SizeOf<T>();
|
||||||
|
var dataLengthInBytes = (uint) (elementSize * data.Length);
|
||||||
|
|
||||||
|
fixed (T* dataPtr = data)
|
||||||
|
{
|
||||||
|
GetData(
|
||||||
|
(byte*) dataPtr,
|
||||||
|
new BufferCopy(bufferOffsetInBytes, 0, dataLengthInBytes)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using RefreshCS;
|
||||||
|
|
||||||
|
namespace MoonWorks.Graphics
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GpuBuffers are generic data containers that can be used by the GPU.
|
||||||
|
/// </summary>
|
||||||
|
public class GpuBuffer : RefreshResource
|
||||||
|
{
|
||||||
|
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyGpuBuffer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size in bytes.
|
||||||
|
/// </summary>
|
||||||
|
public uint Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a buffer of appropriate size given a type and element count.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type that the buffer will contain.</typeparam>
|
||||||
|
/// <param name="device">The GraphicsDevice.</param>
|
||||||
|
/// <param name="usageFlags">Specifies how the buffer will be used.</param>
|
||||||
|
/// <param name="elementCount">How many elements of type T the buffer will contain.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public unsafe static GpuBuffer Create<T>(
|
||||||
|
GraphicsDevice device,
|
||||||
|
BufferUsageFlags usageFlags,
|
||||||
|
uint elementCount
|
||||||
|
) where T : unmanaged
|
||||||
|
{
|
||||||
|
return new GpuBuffer(
|
||||||
|
device,
|
||||||
|
usageFlags,
|
||||||
|
(uint) Marshal.SizeOf<T>() * elementCount
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a buffer.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">An initialized GraphicsDevice.</param>
|
||||||
|
/// <param name="usageFlags">Specifies how the buffer will be used.</param>
|
||||||
|
/// <param name="sizeInBytes">The length of the array. Cannot be resized.</param>
|
||||||
|
public GpuBuffer(
|
||||||
|
GraphicsDevice device,
|
||||||
|
BufferUsageFlags usageFlags,
|
||||||
|
uint sizeInBytes
|
||||||
|
) : base(device)
|
||||||
|
{
|
||||||
|
Handle = Refresh.Refresh_CreateGpuBuffer(
|
||||||
|
device.Handle,
|
||||||
|
(Refresh.BufferUsageFlags) usageFlags,
|
||||||
|
sizeInBytes
|
||||||
|
);
|
||||||
|
Size = sizeInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator BufferBinding(GpuBuffer b)
|
||||||
|
{
|
||||||
|
return new BufferBinding(b, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,12 +61,11 @@ namespace MoonWorks.Graphics
|
||||||
refreshGraphicsPipelineCreateInfo.blendConstants[2] = blendConstants.B;
|
refreshGraphicsPipelineCreateInfo.blendConstants[2] = blendConstants.B;
|
||||||
refreshGraphicsPipelineCreateInfo.blendConstants[3] = blendConstants.A;
|
refreshGraphicsPipelineCreateInfo.blendConstants[3] = blendConstants.A;
|
||||||
|
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.backStencilState = depthStencilState.BackStencilState.ToRefresh();
|
refreshGraphicsPipelineCreateInfo.depthStencilState.stencilState = depthStencilState.StencilState.ToRefresh();
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.compareOp = (Refresh.CompareOp) depthStencilState.CompareOp;
|
refreshGraphicsPipelineCreateInfo.depthStencilState.compareOp = (Refresh.CompareOp) depthStencilState.CompareOp;
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.depthBoundsTestEnable = Conversions.BoolToByte(depthStencilState.DepthBoundsTestEnable);
|
refreshGraphicsPipelineCreateInfo.depthStencilState.depthBoundsTestEnable = Conversions.BoolToByte(depthStencilState.DepthBoundsTestEnable);
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.depthTestEnable = Conversions.BoolToByte(depthStencilState.DepthTestEnable);
|
refreshGraphicsPipelineCreateInfo.depthStencilState.depthTestEnable = Conversions.BoolToByte(depthStencilState.DepthTestEnable);
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.depthWriteEnable = Conversions.BoolToByte(depthStencilState.DepthWriteEnable);
|
refreshGraphicsPipelineCreateInfo.depthStencilState.depthWriteEnable = Conversions.BoolToByte(depthStencilState.DepthWriteEnable);
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.frontStencilState = depthStencilState.FrontStencilState.ToRefresh();
|
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.maxDepthBounds = depthStencilState.MaxDepthBounds;
|
refreshGraphicsPipelineCreateInfo.depthStencilState.maxDepthBounds = depthStencilState.MaxDepthBounds;
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.minDepthBounds = depthStencilState.MinDepthBounds;
|
refreshGraphicsPipelineCreateInfo.depthStencilState.minDepthBounds = depthStencilState.MinDepthBounds;
|
||||||
refreshGraphicsPipelineCreateInfo.depthStencilState.stencilTestEnable = Conversions.BoolToByte(depthStencilState.StencilTestEnable);
|
refreshGraphicsPipelineCreateInfo.depthStencilState.stencilTestEnable = Conversions.BoolToByte(depthStencilState.StencilTestEnable);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using RefreshCS;
|
using RefreshCS;
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
namespace MoonWorks.Graphics
|
||||||
|
@ -23,162 +22,6 @@ namespace MoonWorks.Graphics
|
||||||
// FIXME: this allocates a delegate instance
|
// FIXME: this allocates a delegate instance
|
||||||
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyTexture;
|
protected override Action<IntPtr, IntPtr> QueueDestroyFunction => Refresh.Refresh_QueueDestroyTexture;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a 2D Texture using PNG or QOI data from raw byte data.
|
|
||||||
/// </summary>
|
|
||||||
public static unsafe Texture FromImageBytes(
|
|
||||||
GraphicsDevice device,
|
|
||||||
CommandBuffer commandBuffer,
|
|
||||||
Span<byte> data
|
|
||||||
) {
|
|
||||||
Texture texture;
|
|
||||||
|
|
||||||
fixed (byte *dataPtr = data)
|
|
||||||
{
|
|
||||||
var pixels = Refresh.Refresh_Image_Load((nint) dataPtr, data.Length, out var width, out var height, out var len);
|
|
||||||
|
|
||||||
TextureCreateInfo textureCreateInfo = new TextureCreateInfo();
|
|
||||||
textureCreateInfo.Width = (uint) width;
|
|
||||||
textureCreateInfo.Height = (uint) height;
|
|
||||||
textureCreateInfo.Depth = 1;
|
|
||||||
textureCreateInfo.Format = TextureFormat.R8G8B8A8;
|
|
||||||
textureCreateInfo.IsCube = false;
|
|
||||||
textureCreateInfo.LevelCount = 1;
|
|
||||||
textureCreateInfo.SampleCount = SampleCount.One;
|
|
||||||
textureCreateInfo.UsageFlags = TextureUsageFlags.Sampler;
|
|
||||||
|
|
||||||
texture = new Texture(device, textureCreateInfo);
|
|
||||||
commandBuffer.SetTextureData(texture, pixels, (uint) len);
|
|
||||||
|
|
||||||
Refresh.Refresh_Image_Free(pixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a 2D Texture using PNG or QOI data from a stream.
|
|
||||||
/// </summary>
|
|
||||||
public static unsafe Texture FromImageStream(
|
|
||||||
GraphicsDevice device,
|
|
||||||
CommandBuffer commandBuffer,
|
|
||||||
Stream stream
|
|
||||||
) {
|
|
||||||
var length = stream.Length;
|
|
||||||
var buffer = NativeMemory.Alloc((nuint) length);
|
|
||||||
var span = new Span<byte>(buffer, (int) length);
|
|
||||||
stream.ReadExactly(span);
|
|
||||||
|
|
||||||
var texture = FromImageBytes(device, commandBuffer, span);
|
|
||||||
|
|
||||||
NativeMemory.Free((void*) buffer);
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a 2D Texture using PNG or QOI data from a file.
|
|
||||||
/// </summary>
|
|
||||||
public static Texture FromImageFile(
|
|
||||||
GraphicsDevice device,
|
|
||||||
CommandBuffer commandBuffer,
|
|
||||||
string path
|
|
||||||
) {
|
|
||||||
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
|
||||||
return FromImageStream(device, commandBuffer, fileStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static unsafe void SetDataFromImageBytes(
|
|
||||||
CommandBuffer commandBuffer,
|
|
||||||
TextureSlice textureSlice,
|
|
||||||
Span<byte> data
|
|
||||||
) {
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
var pixels = Refresh.Refresh_Image_Load(
|
|
||||||
(nint) ptr,
|
|
||||||
(int) data.Length,
|
|
||||||
out var w,
|
|
||||||
out var h,
|
|
||||||
out var len
|
|
||||||
);
|
|
||||||
|
|
||||||
commandBuffer.SetTextureData(textureSlice, pixels, (uint) len);
|
|
||||||
|
|
||||||
Refresh.Refresh_Image_Free(pixels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets data for a texture slice using PNG or QOI data from a stream.
|
|
||||||
/// </summary>
|
|
||||||
public static unsafe void SetDataFromImageStream(
|
|
||||||
CommandBuffer commandBuffer,
|
|
||||||
TextureSlice textureSlice,
|
|
||||||
Stream stream
|
|
||||||
) {
|
|
||||||
var length = stream.Length;
|
|
||||||
var buffer = NativeMemory.Alloc((nuint) length);
|
|
||||||
var span = new Span<byte>(buffer, (int) length);
|
|
||||||
stream.ReadExactly(span);
|
|
||||||
|
|
||||||
SetDataFromImageBytes(commandBuffer, textureSlice, span);
|
|
||||||
|
|
||||||
NativeMemory.Free((void*) buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets data for a texture slice using PNG or QOI data from a file.
|
|
||||||
/// </summary>
|
|
||||||
public static void SetDataFromImageFile(
|
|
||||||
CommandBuffer commandBuffer,
|
|
||||||
TextureSlice textureSlice,
|
|
||||||
string path
|
|
||||||
) {
|
|
||||||
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
|
||||||
SetDataFromImageStream(commandBuffer, textureSlice, fileStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe static Texture LoadDDS(GraphicsDevice graphicsDevice, CommandBuffer commandBuffer, System.IO.Stream stream)
|
|
||||||
{
|
|
||||||
using var reader = new BinaryReader(stream);
|
|
||||||
Texture texture;
|
|
||||||
int faces;
|
|
||||||
ParseDDS(reader, out var format, out var width, out var height, out var levels, out var isCube);
|
|
||||||
|
|
||||||
if (isCube)
|
|
||||||
{
|
|
||||||
texture = CreateTextureCube(graphicsDevice, (uint) width, format, TextureUsageFlags.Sampler, (uint) levels);
|
|
||||||
faces = 6;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
texture = CreateTexture2D(graphicsDevice, (uint) width, (uint) height, format, TextureUsageFlags.Sampler, (uint) levels);
|
|
||||||
faces = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < faces; i += 1)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < levels; j += 1)
|
|
||||||
{
|
|
||||||
var levelWidth = width >> j;
|
|
||||||
var levelHeight = height >> j;
|
|
||||||
|
|
||||||
var levelSize = 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, new Rect(0, 0, levelWidth, levelHeight), 0, (uint) i, (uint) j);
|
|
||||||
commandBuffer.SetTextureData(textureSlice, (nint) byteBuffer, (uint) levelSize);
|
|
||||||
|
|
||||||
NativeMemory.Free(byteBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a 2D texture.
|
/// Creates a 2D texture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -590,65 +433,6 @@ namespace MoonWorks.Graphics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Asynchronously saves RGBA or BGRA pixel data to a file in PNG format. <br/>
|
|
||||||
/// Warning: this is expensive and will block to wait for data download from GPU! <br/>
|
|
||||||
/// You can avoid blocking by calling this method from a thread.
|
|
||||||
/// </summary>
|
|
||||||
public unsafe void SavePNG(string path)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
if (Format != TextureFormat.R8G8B8A8 && Format != TextureFormat.B8G8R8A8)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Texture format must be RGBA or BGRA!", "format");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var buffer = new Buffer(Device, 0, Width * Height * 4); // this creates garbage... oh well
|
|
||||||
|
|
||||||
// immediately request the data copy
|
|
||||||
var commandBuffer = Device.AcquireCommandBuffer();
|
|
||||||
commandBuffer.CopyTextureToBuffer(this, buffer);
|
|
||||||
var fence = Device.SubmitAndAcquireFence(commandBuffer);
|
|
||||||
|
|
||||||
var byteCount = buffer.Size;
|
|
||||||
|
|
||||||
var pixelsPtr = NativeMemory.Alloc((nuint) byteCount);
|
|
||||||
var pixelsSpan = new Span<byte>(pixelsPtr, (int) byteCount);
|
|
||||||
|
|
||||||
Device.WaitForFences(fence); // make sure the data transfer is done...
|
|
||||||
Device.ReleaseFence(fence); // and then release the fence
|
|
||||||
|
|
||||||
buffer.GetData(pixelsSpan);
|
|
||||||
|
|
||||||
if (Format == TextureFormat.B8G8R8A8)
|
|
||||||
{
|
|
||||||
var rgbaPtr = NativeMemory.Alloc((nuint) byteCount);
|
|
||||||
var rgbaSpan = new Span<byte>(rgbaPtr, (int) byteCount);
|
|
||||||
|
|
||||||
for (var i = 0; i < byteCount; i += 4)
|
|
||||||
{
|
|
||||||
rgbaSpan[i] = pixelsSpan[i + 2];
|
|
||||||
rgbaSpan[i + 1] = pixelsSpan[i + 1];
|
|
||||||
rgbaSpan[i + 2] = pixelsSpan[i];
|
|
||||||
rgbaSpan[i + 3] = pixelsSpan[i + 3];
|
|
||||||
}
|
|
||||||
|
|
||||||
Refresh.Refresh_Image_SavePNG(path, (nint) rgbaPtr, (int) Width, (int) Height);
|
|
||||||
|
|
||||||
NativeMemory.Free((void*) rgbaPtr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fixed (byte* ptr = pixelsSpan)
|
|
||||||
{
|
|
||||||
Refresh.Refresh_Image_SavePNG(path, (nint) ptr, (int) Width, (int) Height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NativeMemory.Free(pixelsPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint BytesPerPixel(TextureFormat format)
|
public static uint BytesPerPixel(TextureFormat format)
|
||||||
{
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
|
|
|
@ -11,14 +11,9 @@
|
||||||
public bool DepthTestEnable;
|
public bool DepthTestEnable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the stencil operation for back-facing primitives.
|
/// Describes the stencil operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StencilOpState BackStencilState;
|
public StencilOpState StencilState;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Describes the stencil operation for front-facing primitives.
|
|
||||||
/// </summary>
|
|
||||||
public StencilOpState FrontStencilState;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The comparison operator used in the depth test.
|
/// The comparison operator used in the depth test.
|
||||||
|
|
|
@ -8,36 +8,31 @@ namespace MoonWorks.Graphics
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct TextureSlice
|
public struct TextureSlice
|
||||||
{
|
{
|
||||||
public Texture Texture { get; }
|
public Texture Texture;
|
||||||
public Rect Rectangle { get; }
|
public uint MipLevel;
|
||||||
public uint Depth { get; }
|
public uint BaseLayer;
|
||||||
public uint Layer { get; }
|
public uint LayerCount;
|
||||||
public uint Level { get; }
|
public uint X;
|
||||||
|
public uint Y;
|
||||||
|
public uint Z;
|
||||||
|
public uint Width;
|
||||||
|
public uint Height;
|
||||||
|
public uint Depth;
|
||||||
|
|
||||||
public uint Size => (uint) (Rectangle.W * Rectangle.H * Texture.BytesPerPixel(Texture.Format) / Texture.BlockSizeSquared(Texture.Format));
|
public uint Size => (Width * Height * Depth * LayerCount * Texture.BytesPerPixel(Texture.Format) / Texture.BlockSizeSquared(Texture.Format)) >> (int) MipLevel;
|
||||||
|
|
||||||
public TextureSlice(Texture texture)
|
public TextureSlice(Texture texture)
|
||||||
{
|
{
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
Rectangle = new Rect
|
MipLevel = 0;
|
||||||
{
|
BaseLayer = 0;
|
||||||
X = 0,
|
LayerCount = (uint) (texture.IsCube ? 6 : 1);
|
||||||
Y = 0,
|
X = 0;
|
||||||
W = (int) texture.Width,
|
Y = 0;
|
||||||
H = (int) texture.Height
|
Z = 0;
|
||||||
};
|
Width = texture.Width;
|
||||||
Depth = 0;
|
Height = texture.Height;
|
||||||
Layer = 0;
|
Depth = texture.Depth;
|
||||||
Level = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextureSlice(Texture texture, Rect rectangle, uint depth = 0, uint layer = 0, uint level = 0)
|
|
||||||
{
|
|
||||||
Texture = texture;
|
|
||||||
Rectangle = rectangle;
|
|
||||||
Depth = depth;
|
|
||||||
Layer = layer;
|
|
||||||
Level = level;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Refresh.TextureSlice ToRefreshTextureSlice()
|
public Refresh.TextureSlice ToRefreshTextureSlice()
|
||||||
|
@ -45,10 +40,15 @@ namespace MoonWorks.Graphics
|
||||||
Refresh.TextureSlice textureSlice = new Refresh.TextureSlice
|
Refresh.TextureSlice textureSlice = new Refresh.TextureSlice
|
||||||
{
|
{
|
||||||
texture = Texture.Handle,
|
texture = Texture.Handle,
|
||||||
rectangle = Rectangle.ToRefresh(),
|
mipLevel = MipLevel,
|
||||||
depth = Depth,
|
baseLayer = BaseLayer,
|
||||||
layer = Layer,
|
layerCount = LayerCount,
|
||||||
level = Level
|
x = X,
|
||||||
|
y = Y,
|
||||||
|
z = Z,
|
||||||
|
w = Width,
|
||||||
|
h = Height,
|
||||||
|
d = Depth
|
||||||
};
|
};
|
||||||
|
|
||||||
return textureSlice;
|
return textureSlice;
|
||||||
|
|
|
@ -28,6 +28,8 @@ namespace MoonWorks.Video
|
||||||
private Texture vTexture = null;
|
private Texture vTexture = null;
|
||||||
private Sampler LinearSampler;
|
private Sampler LinearSampler;
|
||||||
|
|
||||||
|
private CpuBuffer TransferBuffer;
|
||||||
|
|
||||||
private int currentFrame;
|
private int currentFrame;
|
||||||
|
|
||||||
private Stopwatch timer;
|
private Stopwatch timer;
|
||||||
|
@ -53,6 +55,8 @@ namespace MoonWorks.Video
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
|
var needNewTransferBuffer = TransferBuffer == null;
|
||||||
|
|
||||||
if (RenderTexture == null)
|
if (RenderTexture == null)
|
||||||
{
|
{
|
||||||
RenderTexture = CreateRenderTexture(GraphicsDevice, video.Width, video.Height);
|
RenderTexture = CreateRenderTexture(GraphicsDevice, video.Width, video.Height);
|
||||||
|
@ -83,18 +87,31 @@ namespace MoonWorks.Video
|
||||||
{
|
{
|
||||||
yTexture.Dispose();
|
yTexture.Dispose();
|
||||||
yTexture = CreateSubTexture(GraphicsDevice, video.Width, video.Height);
|
yTexture = CreateSubTexture(GraphicsDevice, video.Width, video.Height);
|
||||||
|
needNewTransferBuffer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video.UVWidth != uTexture.Width || video.UVHeight != uTexture.Height)
|
if (video.UVWidth != uTexture.Width || video.UVHeight != uTexture.Height)
|
||||||
{
|
{
|
||||||
uTexture.Dispose();
|
uTexture.Dispose();
|
||||||
uTexture = CreateSubTexture(GraphicsDevice, video.UVWidth, video.UVHeight);
|
uTexture = CreateSubTexture(GraphicsDevice, video.UVWidth, video.UVHeight);
|
||||||
|
needNewTransferBuffer = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (video.UVWidth != vTexture.Width || video.UVHeight != vTexture.Height)
|
if (video.UVWidth != vTexture.Width || video.UVHeight != vTexture.Height)
|
||||||
{
|
{
|
||||||
vTexture.Dispose();
|
vTexture.Dispose();
|
||||||
vTexture = CreateSubTexture(GraphicsDevice, video.UVWidth, video.UVHeight);
|
vTexture = CreateSubTexture(GraphicsDevice, video.UVWidth, video.UVHeight);
|
||||||
|
needNewTransferBuffer = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needNewTransferBuffer)
|
||||||
|
{
|
||||||
|
if (TransferBuffer != null)
|
||||||
|
{
|
||||||
|
TransferBuffer.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransferBuffer = new CpuBuffer(Device, yTexture.Size + uTexture.Size + vTexture.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Video = video;
|
Video = video;
|
||||||
|
@ -235,17 +252,44 @@ namespace MoonWorks.Video
|
||||||
{
|
{
|
||||||
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
var commandBuffer = GraphicsDevice.AcquireCommandBuffer();
|
||||||
|
|
||||||
commandBuffer.SetTextureDataYUV(
|
var ySpan = new Span<byte>((void*) CurrentStream.yDataHandle, (int) CurrentStream.yDataLength);
|
||||||
|
var uSpan = new Span<byte>((void*) CurrentStream.uDataHandle, (int) CurrentStream.uvDataLength);
|
||||||
|
var vSpan = new Span<byte>((void*) CurrentStream.vDataHandle, (int) CurrentStream.uvDataLength);
|
||||||
|
|
||||||
|
TransferBuffer.SetData(ySpan, SetDataOptions.Discard);
|
||||||
|
TransferBuffer.SetData(uSpan, (uint) ySpan.Length, SetDataOptions.Overwrite);
|
||||||
|
TransferBuffer.SetData(vSpan, (uint) (ySpan.Length + uSpan.Length), SetDataOptions.Overwrite);
|
||||||
|
|
||||||
|
commandBuffer.UploadToTexture(
|
||||||
|
TransferBuffer,
|
||||||
yTexture,
|
yTexture,
|
||||||
|
new BufferImageCopy
|
||||||
|
{
|
||||||
|
BufferOffset = 0,
|
||||||
|
BufferStride = CurrentStream.yStride,
|
||||||
|
BufferImageHeight = yTexture.Height
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
commandBuffer.UploadToTexture(
|
||||||
|
TransferBuffer,
|
||||||
uTexture,
|
uTexture,
|
||||||
|
new BufferImageCopy{
|
||||||
|
BufferOffset = (uint) ySpan.Length,
|
||||||
|
BufferStride = CurrentStream.uvStride,
|
||||||
|
BufferImageHeight = uTexture.Height
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
commandBuffer.UploadToTexture(
|
||||||
|
TransferBuffer,
|
||||||
vTexture,
|
vTexture,
|
||||||
CurrentStream.yDataHandle,
|
new BufferImageCopy
|
||||||
CurrentStream.uDataHandle,
|
{
|
||||||
CurrentStream.vDataHandle,
|
BufferOffset = (uint) (ySpan.Length + uSpan.Length),
|
||||||
CurrentStream.yDataLength,
|
BufferStride = CurrentStream.uvStride,
|
||||||
CurrentStream.uvDataLength,
|
BufferImageHeight = vTexture.Height
|
||||||
CurrentStream.yStride,
|
}
|
||||||
CurrentStream.uvStride
|
|
||||||
);
|
);
|
||||||
|
|
||||||
commandBuffer.BeginRenderPass(
|
commandBuffer.BeginRenderPass(
|
||||||
|
@ -259,7 +303,7 @@ namespace MoonWorks.Video
|
||||||
new TextureSamplerBinding(vTexture, LinearSampler)
|
new TextureSamplerBinding(vTexture, LinearSampler)
|
||||||
);
|
);
|
||||||
|
|
||||||
commandBuffer.DrawPrimitives(0, 1, 0, 0);
|
commandBuffer.DrawPrimitives(0, 1);
|
||||||
|
|
||||||
commandBuffer.EndRenderPass();
|
commandBuffer.EndRenderPass();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue