unit uvkuCommandBuffer; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Vulkan, uvkuBase, uvkuTypes; type ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuRenderPassBeginInfo = class(TvkuStructure) private fClearValues: TVkClearValueList; public RenderPass: VkRenderPass; Framebuffer: VkFramebuffer; RenderArea: TVkRect2D; property ClearValues: TVkClearValueList read fClearValues; function GetStructure: TVkRenderPassBeginInfo; procedure SetStructure(const aData: TVkRenderPassBeginInfo); constructor Create; destructor Destroy; override; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuBeginRenderPassHelper = class(TvkuCommandHelper) private fRenderPassBeginInfo: TvkuRenderPassBeginInfo; fDeviceCommands: TVkDeviceCommands; fCommandBuffer: VkCommandBuffer; public property RenderPassBeginInfo: TvkuRenderPassBeginInfo read fRenderPassBeginInfo; procedure Execute(const aContents: TVkSubpassContents); constructor Create(const aCommandBuffer: VkCommandBuffer; const aDeviceCommands: TVkDeviceCommands); destructor Destroy; override; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuCommandBuffer = class(TvkuHandle) private fHandle: VkCommandBuffer; fCommandPool: VkCommandPool; fDeviceCommands: TVkDeviceCommands; public property Handle: VkCommandBuffer read fHandle; property CommandPool: VkCommandPool read fCommandPool; property DeviceCommands: TVkDeviceCommands read fDeviceCommands; procedure BeginCommand; procedure EndCommand; procedure PipelineBarrier( const aSrcStageMask: VkPipelineStageFlags; const aDstStageMask: VkPipelineStageFlags; const aDependencyFlags: VkDependencyFlags; const aMemoryBarriers: array of TVkMemoryBarrier; const aBufferMemoryBarriers: array of TVkBufferMemoryBarrier; const aImageMemoryBarriers: array of TVkImageMemoryBarrier); function BeginRenderPass: TvkuBeginRenderPassHelper; procedure EndRenderPass; procedure SetViewport( const aFirstViewport: VkUint32; const aViewports: array of TVkViewport); procedure SetScissors( const aFirstScissor: VkUint32; const aScissorss: array of TVkRect2D); procedure BindDescriptorSet( const aBindPoint: TVkPipelineBindPoint; const aLayout: VkPipelineLayout; const aFirstSet: VkUint32; const aDescriptorSets: array of VkDescriptorSet; const aDynamicOffsets: array of VkUint32); procedure BindPipeline( const aBindPoint: TVkPipelineBindPoint; const aPipeline: VkPipeline); procedure BindVertexBuffers( const aFirstBinding: VkUint32; const aBuffers: array of VkBuffer; const aOffsets: array of VkDeviceSize); procedure BindIndexBuffers( const aBuffer: VkBuffer; const aOffset: VkDeviceSize; const aIndexType: TVkIndexType); procedure DrawIndexed( const aIndexCount: VkUint32; const aInstanceCount: VkUint32; const aFirstIndex: VkUint32; const aVertexOffset: VkInt32; const aFirstInstance: VkUint32); constructor Create( const aHandle: VkCommandBuffer; const aOwnsHandle: Boolean; const aCommandPool: VkCommandPool; const aDeviceCommands: TVkDeviceCommands); destructor Destroy; override; end; implementation uses uvkuUtils; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuRenderPassBeginInfo//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuRenderPassBeginInfo.GetStructure: TVkRenderPassBeginInfo; begin FillByte(result, SizeOf(result), 0); result.sType := VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; result.pNext := nil; result.renderPass := RenderPass; result.framebuffer := Framebuffer; result.renderArea := RenderArea; result.clearValueCount := fClearValues.Length; result.pClearValues := fClearValues.PData; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuRenderPassBeginInfo.SetStructure(const aData: TVkRenderPassBeginInfo); begin RenderPass := aData.renderPass; Framebuffer := aData.framebuffer; RenderArea := aData.renderArea; ClearValues.SetData(aData.pClearValues, aData.clearValueCount); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TvkuRenderPassBeginInfo.Create; begin inherited Create; fClearValues := TVkClearValueList.Create; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TvkuRenderPassBeginInfo.Destroy; begin FreeAndNil(fClearValues); inherited Destroy; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuBeginRenderPassHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuBeginRenderPassHelper.Execute(const aContents: TVkSubpassContents); var info: TVkRenderPassBeginInfo; begin info := fRenderPassBeginInfo.GetStructure; fDeviceCommands.vkCmdBeginRenderPass(fCommandBuffer, @info, aContents); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TvkuBeginRenderPassHelper.Create(const aCommandBuffer: VkCommandBuffer; const aDeviceCommands: TVkDeviceCommands); begin inherited Create; fCommandBuffer := aCommandBuffer; fDeviceCommands := aDeviceCommands; fRenderPassBeginInfo := TvkuRenderPassBeginInfo.Create; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TvkuBeginRenderPassHelper.Destroy; begin FreeAndNil(fRenderPassBeginInfo); inherited Destroy; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuCommandBuffer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.BeginCommand; var Info: TVkCommandBufferBeginInfo; err: TVkResult; begin FillByte(Info, SizeOf(Info), 0); Info.sType := VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; Info.pNext := nil; Info.flags := []; // TODO Info.pInheritanceInfo := nil; // TODO err := DeviceCommands.vkBeginCommandBuffer(fHandle, @Info); if (err <> VK_SUCCESS) then raise TvkuErrorException.Create('unable to begin command buffer', err); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.EndCommand; var err: TVkResult; begin err := fDeviceCommands.vkEndCommandBuffer(fHandle); if (err <> VK_SUCCESS) then raise TvkuErrorException.Create('unable to end command buffer', err); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.PipelineBarrier(const aSrcStageMask: VkPipelineStageFlags; const aDstStageMask: VkPipelineStageFlags; const aDependencyFlags: VkDependencyFlags; const aMemoryBarriers: array of TVkMemoryBarrier; const aBufferMemoryBarriers: array of TVkBufferMemoryBarrier; const aImageMemoryBarriers: array of TVkImageMemoryBarrier); begin DeviceCommands.vkCmdPipelineBarrier( fHandle, aSrcStageMask, aDstStageMask, aDependencyFlags, Length(aMemoryBarriers), @aMemoryBarriers[0], Length(aBufferMemoryBarriers), @aBufferMemoryBarriers[0], Length(aImageMemoryBarriers), @aImageMemoryBarriers[0]); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuCommandBuffer.BeginRenderPass: TvkuBeginRenderPassHelper; begin result := TvkuBeginRenderPassHelper.Create(fHandle, fDeviceCommands); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.EndRenderPass; begin fDeviceCommands.vkCmdEndRenderPass(fHandle); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.SetViewport(const aFirstViewport: VkUint32; const aViewports: array of TVkViewport); begin fDeviceCommands.vkCmdSetViewport( fHandle, aFirstViewport, Length(aViewports), @aViewports[0]); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.SetScissors(const aFirstScissor: VkUint32; const aScissorss: array of TVkRect2D); begin fDeviceCommands.vkCmdSetScissor( fHandle, aFirstScissor, Length(aScissorss), @aScissorss[0]); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.BindDescriptorSet(const aBindPoint: TVkPipelineBindPoint; const aLayout: VkPipelineLayout; const aFirstSet: VkUint32; const aDescriptorSets: array of VkDescriptorSet; const aDynamicOffsets: array of VkUint32); var DescSetCount, DynOffsetCount: Integer; DescSets: PVkDescriptorSet; DynOffsets: PVkUint32; begin DescSetCount := Length(aDescriptorSets); DynOffsetCount := Length(aDynamicOffsets); if (DescSetCount > 0) then DescSets := @aDescriptorSets[0] else DescSets := nil; if (DynOffsetCount > 0) then DynOffsets := @aDynamicOffsets[0] else DynOffsets := nil; fDeviceCommands.vkCmdBindDescriptorSets( fHandle, aBindPoint, aLayout, aFirstSet, DescSetCount, DescSets, DynOffsetCount, DynOffsets); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.BindPipeline(const aBindPoint: TVkPipelineBindPoint; const aPipeline: VkPipeline); begin fDeviceCommands.vkCmdBindPipeline(fHandle, aBindPoint, aPipeline); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.BindVertexBuffers(const aFirstBinding: VkUint32; const aBuffers: array of VkBuffer; const aOffsets: array of VkDeviceSize); begin if (Length(aBuffers) <> Length(aOffsets)) then raise TvkuException.Create('aBuffers and aOffsets must have the same number of elements'); fDeviceCommands.vkCmdBindVertexBuffers( fHandle, aFirstBinding, Length(aBuffers), @aBuffers[0], @aOffsets[0]); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.BindIndexBuffers(const aBuffer: VkBuffer; const aOffset: VkDeviceSize; const aIndexType: TVkIndexType); begin fDeviceCommands.vkCmdBindIndexBuffer( fHandle, aBuffer, aOffset, aIndexType); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCommandBuffer.DrawIndexed(const aIndexCount: VkUint32; const aInstanceCount: VkUint32; const aFirstIndex: VkUint32; const aVertexOffset: VkInt32; const aFirstInstance: VkUint32); begin fDeviceCommands.vkCmdDrawIndexed( fHandle, aIndexCount, aInstanceCount, aFirstIndex, aVertexOffset, aFirstInstance); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TvkuCommandBuffer.Create(const aHandle: VkCommandBuffer; const aOwnsHandle: Boolean; const aCommandPool: VkCommandPool; const aDeviceCommands: TVkDeviceCommands); begin inherited Create; fHandle := aHandle; fCommandPool := aCommandPool; fDeviceCommands := aDeviceCommands; OwnsHandle := aOwnsHandle; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TvkuCommandBuffer.Destroy; begin if OwnsHandle and (fHandle <> VK_INVALID_HANDLE) then fDeviceCommands.vkFreeCommandBuffers(fDeviceCommands.Device, fCommandPool, 1, @fHandle); fHandle := VK_INVALID_HANDLE; inherited Destroy; end; end.