Added more graphics validation, misc api tweaks (#30)
* Refactored render pass attachment validation to avoid copy-pasting the asserts * Added validation for texture usage flags and null textures/samplers * Added an exception for when GraphicsPipeline/ComputePipeline creation fails * Changed TextureSamplerBinding so that it holds references to the Texture and Sampler classes, rather than just their handles * Removed the CommandBuffer.BindVertex/FragmentSamplers overloads that took a length parameter Co-authored-by: Caleb Cornett <caleb.cornett@outlook.com> Reviewed-on: #30 Co-authored-by: TheSpydog <thespydog@noreply.example.org> Co-committed-by: TheSpydog <thespydog@noreply.example.org>pull/31/head
							parent
							
								
									db38ada410
								
							
						
					
					
						commit
						1b38f8606b
					
				|  | @ -4,19 +4,13 @@ namespace MoonWorks.Graphics | ||||||
| { | { | ||||||
| 	public struct TextureSamplerBinding | 	public struct TextureSamplerBinding | ||||||
| 	{ | 	{ | ||||||
| 		public IntPtr TextureHandle; | 		public Texture Texture; | ||||||
| 		public IntPtr SamplerHandle; | 		public Sampler Sampler; | ||||||
| 
 | 
 | ||||||
| 		public TextureSamplerBinding(Texture texture, Sampler sampler) | 		public TextureSamplerBinding(Texture texture, Sampler sampler) | ||||||
| 		{ | 		{ | ||||||
| 			TextureHandle = texture.Handle; | 			Texture = texture; | ||||||
| 			SamplerHandle = sampler.Handle; | 			Sampler = sampler; | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		public TextureSamplerBinding(IntPtr textureHandle, IntPtr samplerHandle) |  | ||||||
| 		{ |  | ||||||
| 			TextureHandle = textureHandle; |  | ||||||
| 			SamplerHandle = samplerHandle; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -40,15 +40,7 @@ namespace MoonWorks.Graphics | ||||||
| 		) | 		) | ||||||
| 		{ | 		{ | ||||||
| #if DEBUG | #if DEBUG | ||||||
| 			if (colorAttachmentInfos.Length == 0) | 			AssertValidColorAttachments(colorAttachmentInfos, true); | ||||||
| 			{ |  | ||||||
| 				throw new System.ArgumentException("Render pass must contain at least one attachment!"); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (colorAttachmentInfos.Length > 4) |  | ||||||
| 			{ |  | ||||||
| 				throw new System.ArgumentException("Render pass cannot have more than 4 color attachments!"); |  | ||||||
| 			} |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 			var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length]; | 			var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length]; | ||||||
|  | @ -86,10 +78,8 @@ namespace MoonWorks.Graphics | ||||||
| 		) | 		) | ||||||
| 		{ | 		{ | ||||||
| #if DEBUG | #if DEBUG | ||||||
| 			if (colorAttachmentInfos.Length > 4) | 			AssertValidDepthAttachments(depthStencilAttachmentInfo); | ||||||
| 			{ | 			AssertValidColorAttachments(colorAttachmentInfos, false); | ||||||
| 				throw new System.ArgumentException("Render pass cannot have more than 4 color attachments!"); |  | ||||||
| 			} |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 			var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length]; | 			var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length]; | ||||||
|  | @ -129,15 +119,7 @@ namespace MoonWorks.Graphics | ||||||
| 		) | 		) | ||||||
| 		{ | 		{ | ||||||
| #if DEBUG | #if DEBUG | ||||||
| 			if (colorAttachmentInfos.Length == 0) | 			AssertValidColorAttachments(colorAttachmentInfos, true); | ||||||
| 			{ |  | ||||||
| 				throw new System.ArgumentException("Render pass must contain at least one attachment!"); |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if (colorAttachmentInfos.Length > 4) |  | ||||||
| 			{ |  | ||||||
| 				throw new System.ArgumentException("Render pass cannot have more than 4 color attachments!"); |  | ||||||
| 			} |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 			var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length]; | 			var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length]; | ||||||
|  | @ -177,10 +159,8 @@ namespace MoonWorks.Graphics | ||||||
| 		) | 		) | ||||||
| 		{ | 		{ | ||||||
| #if DEBUG | #if DEBUG | ||||||
| 			if (colorAttachmentInfos.Length > 4) | 			AssertValidDepthAttachments(depthStencilAttachmentInfo); | ||||||
| 			{ | 			AssertValidColorAttachments(colorAttachmentInfos, false); | ||||||
| 				throw new System.ArgumentException("Render pass cannot have more than 4 color attachments!"); |  | ||||||
| 			} |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 			var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length]; | 			var refreshColorAttachmentInfos = new Refresh.ColorAttachmentInfo[colorAttachmentInfos.Length]; | ||||||
|  | @ -453,11 +433,9 @@ namespace MoonWorks.Graphics | ||||||
| 		/// <summary> | 		/// <summary> | ||||||
| 		/// Binds samplers to be used by the vertex shader. | 		/// Binds samplers to be used by the vertex shader. | ||||||
| 		/// </summary> | 		/// </summary> | ||||||
| 		/// <param name="textureSamplerBindings">An array of texture-sampler pairs to bind.</param> | 		/// <param name="textureSamplerBindings">The texture-sampler pairs to bind.</param> | ||||||
| 		/// <param name="length">The number of texture-sampler pairs from the array to bind.</param> |  | ||||||
| 		public unsafe void BindVertexSamplers( | 		public unsafe void BindVertexSamplers( | ||||||
| 			TextureSamplerBinding[] textureSamplerBindings, | 			params TextureSamplerBinding[] textureSamplerBindings | ||||||
| 			int length |  | ||||||
| 		) | 		) | ||||||
| 		{ | 		{ | ||||||
| #if DEBUG | #if DEBUG | ||||||
|  | @ -468,7 +446,7 @@ namespace MoonWorks.Graphics | ||||||
| 				throw new System.InvalidOperationException("The vertex shader of the current graphics pipeline does not take any samplers!"); | 				throw new System.InvalidOperationException("The vertex shader of the current graphics pipeline does not take any samplers!"); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (currentGraphicsPipeline.VertexShaderInfo.SamplerBindingCount < length) | 			if (currentGraphicsPipeline.VertexShaderInfo.SamplerBindingCount < textureSamplerBindings.Length) | ||||||
| 			{ | 			{ | ||||||
| 				throw new System.InvalidOperationException("Vertex sampler count exceeds the amount used by the vertex shader!"); | 				throw new System.InvalidOperationException("Vertex sampler count exceeds the amount used by the vertex shader!"); | ||||||
| 			} | 			} | ||||||
|  | @ -477,10 +455,15 @@ namespace MoonWorks.Graphics | ||||||
| 			var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length]; | 			var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length]; | ||||||
| 			var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length]; | 			var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length]; | ||||||
| 
 | 
 | ||||||
| 			for (var i = 0; i < length; i += 1) | 			for (var i = 0; i < textureSamplerBindings.Length; i += 1) | ||||||
| 			{ | 			{ | ||||||
| 				texturePtrs[i] = textureSamplerBindings[i].TextureHandle; | #if DEBUG | ||||||
| 				samplerPtrs[i] = textureSamplerBindings[i].SamplerHandle; | 				AssertTextureSamplerBindingNonNull(textureSamplerBindings[i]); | ||||||
|  | 				AssertTextureBindingUsageFlags(textureSamplerBindings[i].Texture); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 				texturePtrs[i] = textureSamplerBindings[i].Texture.Handle; | ||||||
|  | 				samplerPtrs[i] = textureSamplerBindings[i].Sampler.Handle; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			Refresh.Refresh_BindVertexSamplers( | 			Refresh.Refresh_BindVertexSamplers( | ||||||
|  | @ -491,25 +474,12 @@ namespace MoonWorks.Graphics | ||||||
| 			); | 			); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/// <summary> |  | ||||||
| 		/// Binds samplers to be used by the vertex shader. |  | ||||||
| 		/// </summary> |  | ||||||
| 		/// <param name="textureSamplerBindings">The texture-sampler pairs to bind.</param> |  | ||||||
| 		public unsafe void BindVertexSamplers( |  | ||||||
| 			params TextureSamplerBinding[] textureSamplerBindings |  | ||||||
| 		) |  | ||||||
| 		{ |  | ||||||
| 			BindVertexSamplers(textureSamplerBindings, textureSamplerBindings.Length); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/// <summary> | 		/// <summary> | ||||||
| 		/// Binds samplers to be used by the fragment shader. | 		/// Binds samplers to be used by the fragment shader. | ||||||
| 		/// </summary> | 		/// </summary> | ||||||
| 		/// <param name="textureSamplerBindings">An array of texture-sampler pairs to bind.</param> | 		/// <param name="textureSamplerBindings">An array of texture-sampler pairs to bind.</param> | ||||||
| 		/// <param name="length">The number of texture-sampler pairs from the given array to bind.</param> |  | ||||||
| 		public unsafe void BindFragmentSamplers( | 		public unsafe void BindFragmentSamplers( | ||||||
| 			TextureSamplerBinding[] textureSamplerBindings, | 			params TextureSamplerBinding[] textureSamplerBindings | ||||||
| 			int length |  | ||||||
| 		) | 		) | ||||||
| 		{ | 		{ | ||||||
| #if DEBUG | #if DEBUG | ||||||
|  | @ -520,7 +490,7 @@ namespace MoonWorks.Graphics | ||||||
| 				throw new System.InvalidOperationException("The fragment shader of the current graphics pipeline does not take any samplers!"); | 				throw new System.InvalidOperationException("The fragment shader of the current graphics pipeline does not take any samplers!"); | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (currentGraphicsPipeline.FragmentShaderInfo.SamplerBindingCount < length) | 			if (currentGraphicsPipeline.FragmentShaderInfo.SamplerBindingCount < textureSamplerBindings.Length) | ||||||
| 			{ | 			{ | ||||||
| 				throw new System.InvalidOperationException("Fragment sampler count exceeds the amount used by the fragment shader!"); | 				throw new System.InvalidOperationException("Fragment sampler count exceeds the amount used by the fragment shader!"); | ||||||
| 			} | 			} | ||||||
|  | @ -529,21 +499,15 @@ namespace MoonWorks.Graphics | ||||||
| 			var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length]; | 			var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length]; | ||||||
| 			var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length]; | 			var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length]; | ||||||
| 
 | 
 | ||||||
| 			for (var i = 0; i < length; i += 1) | 			for (var i = 0; i < textureSamplerBindings.Length; i += 1) | ||||||
| 			{ | 			{ | ||||||
| 				#if DEBUG | #if DEBUG | ||||||
| 				if (textureSamplerBindings[i].TextureHandle == IntPtr.Zero) | 				AssertTextureSamplerBindingNonNull(textureSamplerBindings[i]); | ||||||
| 				{ | 				AssertTextureBindingUsageFlags(textureSamplerBindings[i].Texture); | ||||||
| 					throw new NullReferenceException("Texture binding must not be null!"); | #endif | ||||||
| 				} |  | ||||||
| 				if (textureSamplerBindings[i].TextureHandle == IntPtr.Zero) |  | ||||||
| 				{ |  | ||||||
| 					throw new NullReferenceException("Sampler binding must not be null!"); |  | ||||||
| 				} |  | ||||||
| 				#endif |  | ||||||
| 
 | 
 | ||||||
| 				texturePtrs[i] = textureSamplerBindings[i].TextureHandle; | 				texturePtrs[i] = textureSamplerBindings[i].Texture.Handle; | ||||||
| 				samplerPtrs[i] = textureSamplerBindings[i].SamplerHandle; | 				samplerPtrs[i] = textureSamplerBindings[i].Sampler.Handle; | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			Refresh.Refresh_BindFragmentSamplers( | 			Refresh.Refresh_BindFragmentSamplers( | ||||||
|  | @ -554,17 +518,6 @@ namespace MoonWorks.Graphics | ||||||
| 			); | 			); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		/// <summary> |  | ||||||
| 		/// Binds samplers to be used by the fragment shader. |  | ||||||
| 		/// </summary> |  | ||||||
| 		/// <param name="textureSamplerBindings">An array of texture-sampler pairs to bind.</param> |  | ||||||
| 		public unsafe void BindFragmentSamplers( |  | ||||||
| 			params TextureSamplerBinding[] textureSamplerBindings |  | ||||||
| 		) |  | ||||||
| 		{ |  | ||||||
| 			BindFragmentSamplers(textureSamplerBindings, textureSamplerBindings.Length); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		/// <summary> | 		/// <summary> | ||||||
| 		/// Pushes vertex shader uniforms to the device. | 		/// Pushes vertex shader uniforms to the device. | ||||||
| 		/// </summary> | 		/// </summary> | ||||||
|  | @ -581,6 +534,7 @@ namespace MoonWorks.Graphics | ||||||
| 				throw new InvalidOperationException("The current vertex shader does not take a uniform buffer!"); | 				throw new InvalidOperationException("The current vertex shader does not take a uniform buffer!"); | ||||||
| 			} | 			} | ||||||
| #endif | #endif | ||||||
|  | 
 | ||||||
| 			fixed (T* ptr = &uniforms[0]) | 			fixed (T* ptr = &uniforms[0]) | ||||||
| 			{ | 			{ | ||||||
| 				return Refresh.Refresh_PushVertexShaderUniforms( | 				return Refresh.Refresh_PushVertexShaderUniforms( | ||||||
|  | @ -1111,6 +1065,68 @@ namespace MoonWorks.Graphics | ||||||
| 				throw new System.InvalidOperationException(message); | 				throw new System.InvalidOperationException(message); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		private void AssertValidColorAttachments(ColorAttachmentInfo[] colorAttachmentInfos, bool atLeastOneRequired) | ||||||
|  | 		{ | ||||||
|  | 			if (atLeastOneRequired && colorAttachmentInfos.Length == 0) | ||||||
|  | 			{ | ||||||
|  | 				throw new System.ArgumentException("Render pass must contain at least one attachment!"); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (colorAttachmentInfos.Length > 4) | ||||||
|  | 			{ | ||||||
|  | 				throw new System.ArgumentException("Render pass cannot have more than 4 color attachments!"); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			for (int i = 0; i < colorAttachmentInfos.Length; i += 1) | ||||||
|  | 			{ | ||||||
|  | 				if (colorAttachmentInfos[i].Texture == null || | ||||||
|  | 					colorAttachmentInfos[i].Texture.Handle == IntPtr.Zero) | ||||||
|  | 				{ | ||||||
|  | 					throw new System.ArgumentException("Render pass color attachment Texture cannot be null!"); | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				if ((colorAttachmentInfos[i].Texture.UsageFlags & TextureUsageFlags.ColorTarget) == 0) | ||||||
|  | 				{ | ||||||
|  | 					throw new System.ArgumentException("Render pass color attachment UsageFlags must include TextureUsageFlags.ColorTarget!"); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		private void AssertValidDepthAttachments(DepthStencilAttachmentInfo depthStencilAttachmentInfo) | ||||||
|  | 		{ | ||||||
|  | 			if (depthStencilAttachmentInfo.Texture == null || | ||||||
|  | 				depthStencilAttachmentInfo.Texture.Handle == IntPtr.Zero) | ||||||
|  | 			{ | ||||||
|  | 				throw new System.ArgumentException("Render pass depth stencil attachment Texture cannot be null!"); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if ((depthStencilAttachmentInfo.Texture.UsageFlags & TextureUsageFlags.DepthStencilTarget) == 0) | ||||||
|  | 			{ | ||||||
|  | 				throw new System.ArgumentException("Render pass depth stencil attachment UsageFlags must include TextureUsageFlags.DepthStencilTarget!"); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		private void AssertTextureSamplerBindingNonNull(in TextureSamplerBinding binding) | ||||||
|  | 		{ | ||||||
|  | 			if (binding.Texture == null || binding.Texture.Handle == IntPtr.Zero) | ||||||
|  | 			{ | ||||||
|  | 				throw new NullReferenceException("Texture binding must not be null!"); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (binding.Sampler == null || binding.Sampler.Handle == IntPtr.Zero) | ||||||
|  | 			{ | ||||||
|  | 				throw new NullReferenceException("Sampler binding must not be null!"); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		private void AssertTextureBindingUsageFlags(Texture texture) | ||||||
|  | 		{ | ||||||
|  | 			if ((texture.UsageFlags & TextureUsageFlags.Sampler) == 0) | ||||||
|  | 			{ | ||||||
|  | 				throw new System.ArgumentException("The bound Texture's UsageFlags must include TextureUsageFlags.Sampler!"); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
| #endif | #endif | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -28,6 +28,10 @@ namespace MoonWorks.Graphics | ||||||
| 				device.Handle, | 				device.Handle, | ||||||
| 				refreshComputeShaderInfo | 				refreshComputeShaderInfo | ||||||
| 			); | 			); | ||||||
|  | 			if (Handle == IntPtr.Zero) | ||||||
|  | 			{ | ||||||
|  | 				throw new Exception("Could not create compute pipeline!"); | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			ComputeShaderInfo = computeShaderInfo; | 			ComputeShaderInfo = computeShaderInfo; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -102,6 +102,10 @@ namespace MoonWorks.Graphics | ||||||
| 			refreshGraphicsPipelineCreateInfo.attachmentInfo.hasDepthStencilAttachment = Conversions.BoolToByte(attachmentInfo.HasDepthStencilAttachment); | 			refreshGraphicsPipelineCreateInfo.attachmentInfo.hasDepthStencilAttachment = Conversions.BoolToByte(attachmentInfo.HasDepthStencilAttachment); | ||||||
| 
 | 
 | ||||||
| 			Handle = Refresh.Refresh_CreateGraphicsPipeline(device.Handle, refreshGraphicsPipelineCreateInfo); | 			Handle = Refresh.Refresh_CreateGraphicsPipeline(device.Handle, refreshGraphicsPipelineCreateInfo); | ||||||
|  | 			if (Handle == IntPtr.Zero) | ||||||
|  | 			{ | ||||||
|  | 				throw new Exception("Could not create graphics pipeline!"); | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			vertexAttributesHandle.Free(); | 			vertexAttributesHandle.Free(); | ||||||
| 			vertexBindingsHandle.Free(); | 			vertexBindingsHandle.Free(); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue