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