using System; using MoonWorks.Math; using RefreshCS; namespace MoonWorks.Graphics { /// /// Command buffers are used to apply render state and issue draw calls. /// NOTE: it is not recommended to hold references to command buffers long term. /// public class CommandBuffer { public GraphicsDevice Device { get; } public IntPtr Handle { get; internal set; } // called from RefreshDevice internal CommandBuffer(GraphicsDevice device) { Device = device; Handle = IntPtr.Zero; } /// /// Begins a render pass. /// All render state, resource binding, and draw commands must be made within a render pass. /// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass. /// /// The render pass object to begin. /// The framebuffer used by the render pass. /// The screen area of the render pass. /// Clear values for the depth/stencil buffer. This is ignored if the render pass does not clear. public unsafe void BeginRenderPass( RenderPass renderPass, Framebuffer framebuffer, in Rect renderArea, in DepthStencilValue depthStencilClearValue ) { Refresh.Refresh_BeginRenderPass( Device.Handle, Handle, renderPass.Handle, framebuffer.Handle, renderArea.ToRefresh(), IntPtr.Zero, 0, depthStencilClearValue.ToRefresh() ); } /// /// Begins a render pass. /// All render state, resource binding, and draw commands must be made within a render pass. /// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass. /// /// The render pass object to begin. /// The framebuffer used by the render pass. /// The screen area of the render pass. /// Clear values for the depth/stencil buffer. This is ignored if the render pass does not clear. /// Color clear values for each render target in the framebuffer. public unsafe void BeginRenderPass( RenderPass renderPass, Framebuffer framebuffer, in Rect renderArea, in DepthStencilValue depthStencilClearValue, params Vector4[] clearColors ) { Refresh.Vec4* colors = stackalloc Refresh.Vec4[clearColors.Length]; for (var i = 0; i < clearColors.Length; i++) { colors[i] = new Refresh.Vec4 { x = clearColors[i].X, y = clearColors[i].Y, z = clearColors[i].Z, w = clearColors[i].W }; } Refresh.Refresh_BeginRenderPass( Device.Handle, Handle, renderPass.Handle, framebuffer.Handle, renderArea.ToRefresh(), (IntPtr) colors, (uint)clearColors.Length, depthStencilClearValue.ToRefresh() ); } /// /// Begins a render pass. /// All render state, resource binding, and draw commands must be made within a render pass. /// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass. /// /// The render pass object to begin. /// The framebuffer used by the render pass. /// The screen area of the render pass. /// Color clear values for each render target in the framebuffer. public unsafe void BeginRenderPass( RenderPass renderPass, Framebuffer framebuffer, in Rect renderArea, params Vector4[] clearColors ) { Refresh.Vec4* colors = stackalloc Refresh.Vec4[clearColors.Length]; for (var i = 0; i < clearColors.Length; i++) { colors[i] = new Refresh.Vec4 { x = clearColors[i].X, y = clearColors[i].Y, z = clearColors[i].Z, w = clearColors[i].W }; } Refresh.Refresh_BeginRenderPass( Device.Handle, Handle, renderPass.Handle, framebuffer.Handle, renderArea.ToRefresh(), (IntPtr) colors, (uint) clearColors.Length, IntPtr.Zero ); } /// /// Begins a render pass. /// All render state, resource binding, and draw commands must be made within a render pass. /// It is an error to call this after calling BeginRenderPass but before calling EndRenderPass. /// /// The render pass object to begin. /// The framebuffer used by the render pass. /// The screen area of the render pass. public unsafe void BeginRenderPass( RenderPass renderPass, Framebuffer framebuffer, in Rect renderArea ) { Refresh.Refresh_BeginRenderPass( Device.Handle, Handle, renderPass.Handle, framebuffer.Handle, renderArea.ToRefresh(), IntPtr.Zero, 0, IntPtr.Zero ); } /// /// Binds a compute pipeline so that compute work may be dispatched. /// /// The compute pipeline to bind. public void BindComputePipeline( ComputePipeline computePipeline ) { Refresh.Refresh_BindComputePipeline( Device.Handle, Handle, computePipeline.Handle ); } /// /// Binds buffers to be used in the compute shader. /// /// A set of buffers to bind. public unsafe void BindComputeBuffers( params Buffer[] buffers ) { var bufferPtrs = stackalloc IntPtr[buffers.Length]; for (var i = 0; i < buffers.Length; i += 1) { bufferPtrs[i] = buffers[i].Handle; } Refresh.Refresh_BindComputeBuffers( Device.Handle, Handle, (IntPtr) bufferPtrs ); } /// /// Binds textures to be used in the compute shader. /// /// A set of textures to bind. public unsafe void BindComputeTextures( params Texture[] textures ) { var texturePtrs = stackalloc IntPtr[textures.Length]; for (var i = 0; i < textures.Length; i += 1) { texturePtrs[i] = textures[i].Handle; } Refresh.Refresh_BindComputeTextures( Device.Handle, Handle, (IntPtr) texturePtrs ); } /// /// Binds a graphics pipeline so that rendering work may be performed. /// /// The graphics pipeline to bind. public void BindGraphicsPipeline( GraphicsPipeline graphicsPipeline ) { Refresh.Refresh_BindGraphicsPipeline( Device.Handle, Handle, graphicsPipeline.Handle ); } /// /// Binds vertex buffers to be used by subsequent draw calls. /// /// The index of the first buffer to bind. /// Buffers to bind and their associated offsets. public unsafe void BindVertexBuffers( uint firstBinding, params BufferBinding[] bufferBindings ) { var bufferPtrs = stackalloc IntPtr[bufferBindings.Length]; var offsets = stackalloc ulong[bufferBindings.Length]; for (var i = 0; i < bufferBindings.Length; i += 1) { bufferPtrs[i] = bufferBindings[i].Buffer.Handle; offsets[i] = bufferBindings[i].Offset; } Refresh.Refresh_BindVertexBuffers( Device.Handle, Handle, firstBinding, (uint) bufferBindings.Length, (IntPtr) bufferPtrs, (IntPtr) offsets ); } /// /// Binds vertex buffers to be used by subsequent draw calls. /// /// The buffers to bind. public unsafe void BindVertexBuffers( params Buffer[] buffers ) { var bufferPtrs = stackalloc IntPtr[buffers.Length]; var offsets = stackalloc ulong[buffers.Length]; for (var i = 0; i < buffers.Length; i += 1) { bufferPtrs[i] = buffers[i].Handle; offsets[i] = 0; } Refresh.Refresh_BindVertexBuffers( Device.Handle, Handle, 0, (uint) buffers.Length, (IntPtr) bufferPtrs, (IntPtr) offsets ); } /// /// Binds an index buffer to be used by subsequent draw calls. /// /// The index buffer to bind. /// The size in bytes of the index buffer elements. /// The offset index for the buffer. public void BindIndexBuffer( Buffer indexBuffer, IndexElementSize indexElementSize, uint offset = 0 ) { Refresh.Refresh_BindIndexBuffer( Device.Handle, Handle, indexBuffer.Handle, offset, (Refresh.IndexElementSize) indexElementSize ); } /// /// Binds samplers to be used by the vertex shader. /// /// An array of texture-sampler pairs to bind. /// The number of texture-sampler pairs from the array to bind. public unsafe void BindVertexSamplers( TextureSamplerBinding[] textureSamplerBindings, int length ) { var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length]; var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length]; for (var i = 0; i < length; i += 1) { texturePtrs[i] = textureSamplerBindings[i].Texture.Handle; samplerPtrs[i] = textureSamplerBindings[i].Sampler.Handle; } Refresh.Refresh_BindVertexSamplers( Device.Handle, Handle, (IntPtr) texturePtrs, (IntPtr) samplerPtrs ); } /// /// Binds samplers to be used by the vertex shader. /// /// The texture-sampler pairs to bind. public unsafe void BindVertexSamplers( params TextureSamplerBinding[] textureSamplerBindings ) { BindVertexSamplers(textureSamplerBindings, textureSamplerBindings.Length); } /// /// Binds samplers to be used by the fragment shader. /// /// An array of texture-sampler pairs to bind. /// The number of texture-sampler pairs from the given array to bind. public unsafe void BindFragmentSamplers( TextureSamplerBinding[] textureSamplerBindings, int length ) { var texturePtrs = stackalloc IntPtr[textureSamplerBindings.Length]; var samplerPtrs = stackalloc IntPtr[textureSamplerBindings.Length]; for (var i = 0; i < length; i += 1) { texturePtrs[i] = textureSamplerBindings[i].Texture.Handle; samplerPtrs[i] = textureSamplerBindings[i].Sampler.Handle; } Refresh.Refresh_BindFragmentSamplers( Device.Handle, Handle, (IntPtr) texturePtrs, (IntPtr) samplerPtrs ); } /// /// Binds samplers to be used by the fragment shader. /// /// An array of texture-sampler pairs to bind. public unsafe void BindFragmentSamplers( params TextureSamplerBinding[] textureSamplerBindings ) { BindFragmentSamplers(textureSamplerBindings, textureSamplerBindings.Length); } /// /// Clears the render targets on the current framebuffer to a single color or depth/stencil value. /// NOTE: It is recommended that you clear when beginning render passes unless you have a good reason to clear mid-pass. /// /// The area of the framebuffer to clear. /// Whether to clear colors, depth, or stencil value, or multiple. /// The depth/stencil clear values. Will be ignored if color is not provided in ClearOptions. /// The color clear values. Must provide one per render target. Can be omitted if depth/stencil is not cleared. public unsafe void Clear( in Rect clearRect, ClearOptionsFlags clearOptions, in DepthStencilValue depthStencilClearValue, params Vector4[] clearColors ) { Refresh.Vec4* colors = stackalloc Refresh.Vec4[clearColors.Length]; for (var i = 0; i < clearColors.Length; i++) { colors[i] = new Refresh.Vec4 { x = clearColors[i].X, y = clearColors[i].Y, z = clearColors[i].Z, w = clearColors[i].W }; } Refresh.Refresh_Clear( Device.Handle, Handle, clearRect.ToRefresh(), (Refresh.ClearOptionsFlags)clearOptions, (IntPtr) colors, (uint) clearColors.Length, depthStencilClearValue.ToRefresh() ); } /// /// Draws using instanced rendering. /// It is an error to call this method unless two vertex buffers have been bound. /// /// The starting index offset for the vertex buffer. /// The starting index offset for the index buffer. /// The number of primitives to draw. /// The number of instances to draw. /// An offset value obtained from PushVertexShaderUniforms. If no uniforms are required then use 0. /// An offset value obtained from PushFragmentShaderUniforms. If no uniforms are required the use 0. public void DrawInstancedPrimitives( uint baseVertex, uint startIndex, uint primitiveCount, uint instanceCount, uint vertexParamOffset, uint fragmentParamOffset ) { Refresh.Refresh_DrawInstancedPrimitives( Device.Handle, Handle, baseVertex, startIndex, primitiveCount, instanceCount, vertexParamOffset, fragmentParamOffset ); } /// /// Draws using a vertex buffer and an index buffer. /// /// The starting index offset for the vertex buffer. /// The starting index offset for the index buffer. /// The number of primitives to draw. /// An offset value obtained from PushVertexShaderUniforms. If no uniforms are required then use 0. /// An offset value obtained from PushFragmentShaderUniforms. If no uniforms are required the use 0. public void DrawIndexedPrimitives( uint baseVertex, uint startIndex, uint primitiveCount, uint vertexParamOffset, uint fragmentParamOffset ) { Refresh.Refresh_DrawIndexedPrimitives( Device.Handle, Handle, baseVertex, startIndex, primitiveCount, vertexParamOffset, fragmentParamOffset ); } /// /// Draws using a vertex buffer. /// /// /// /// /// public void DrawPrimitives( uint vertexStart, uint primitiveCount, uint vertexParamOffset, uint fragmentParamOffset ) { Refresh.Refresh_DrawPrimitives( Device.Handle, Handle, vertexStart, primitiveCount, vertexParamOffset, fragmentParamOffset ); } /// /// Ends the current render pass. /// This must be called before beginning another render pass or submitting the command buffer. /// public void EndRenderPass() { Refresh.Refresh_EndRenderPass( Device.Handle, Handle ); } /// /// Prepares a texture to be presented to the screen. /// /// The texture to present. /// The area of the screen to present to. /// The filter to use when the texture size differs from the destination rectangle. public void QueuePresent( in Texture texture, in Rect destinationRectangle, Filter filter ) { var refreshRect = destinationRectangle.ToRefresh(); var refreshTextureSlice = new Refresh.TextureSlice { texture = texture.Handle, rectangle = new Refresh.Rect { x = 0, y = 0, w = (int)texture.Width, h = (int)texture.Height }, layer = 0, level = 0, depth = 0 }; Refresh.Refresh_QueuePresent( Device.Handle, Handle, refreshTextureSlice, refreshRect, (Refresh.Filter)filter ); } /// /// Prepares a texture slice to be presented to the screen. /// /// The texture slice to present. /// The area of the screen to present to. /// The filter to use when the texture size differs from the destination rectangle. public void QueuePresent( in TextureSlice textureSlice, in Rect destinationRectangle, Filter filter ) { var refreshTextureSlice = textureSlice.ToRefreshTextureSlice(); var refreshRect = destinationRectangle.ToRefresh(); Refresh.Refresh_QueuePresent( Device.Handle, Handle, refreshTextureSlice, refreshRect, (Refresh.Filter) filter ); } /// /// Prepares a texture slice to be presented to the screen. /// This particular variant of this method will present to the entire window area. /// /// The texture slice to present. /// The filter to use when the texture size differs from the window size. public void QueuePresent( in TextureSlice textureSlice, Filter filter ) { Refresh.Refresh_QueuePresent( Device.Handle, Handle, textureSlice.ToRefreshTextureSlice(), IntPtr.Zero, (Refresh.Filter) filter ); } /// /// Prepares a texture to be presented to the screen. /// This particular variant of this method will present to the entire window area. /// /// The texture to present. /// The filter to use when the texture size differs from the window size. public void QueuePresent( Texture texture, Filter filter ) { var refreshTextureSlice = new Refresh.TextureSlice { texture = texture.Handle, rectangle = new Refresh.Rect { x = 0, y = 0, w = (int) texture.Width, h = (int) texture.Height }, layer = 0, level = 0, depth = 0 }; Refresh.Refresh_QueuePresent( Device.Handle, Handle, refreshTextureSlice, IntPtr.Zero, (Refresh.Filter) filter ); } /// /// Performs an asynchronous texture-to-texture copy on the GPU. /// /// The texture slice to copy from. /// The texture slice to copy to. /// The filter to use if the sizes of the texture slices differ. public void CopyTextureToTexture( in TextureSlice sourceTextureSlice, in TextureSlice destinationTextureSlice, Filter filter ) { var sourceRefreshTextureSlice = sourceTextureSlice.ToRefreshTextureSlice(); var destRefreshTextureSlice = destinationTextureSlice.ToRefreshTextureSlice(); Refresh.Refresh_CopyTextureToTexture( Device.Handle, Handle, sourceRefreshTextureSlice, destRefreshTextureSlice, (Refresh.Filter) filter ); } /// /// Performs an asynchronous texture-to-buffer copy. /// Note that the buffer is not guaranteed to be filled until you call GraphicsDevice.Wait() /// /// /// public void CopyTextureToBuffer( in TextureSlice textureSlice, Buffer buffer ) { var refreshTextureSlice = textureSlice.ToRefreshTextureSlice(); Refresh.Refresh_CopyTextureToBuffer( Device.Handle, Handle, refreshTextureSlice, buffer.Handle ); } } }