unit uvkuDevice; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Vulkan, uvkuBase, uvkuTypes; type ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuDescriptorImageInfo = class(TvkuStructure) Sampler: VkSampler; ImageView: VkImageView; ImageLayout: TVkImageLayout; function GetStructure: TVkDescriptorImageInfo; procedure SetStructure(const aData: TVkDescriptorImageInfo); end; TvkuDescriptorImageInfoList = specialize TvkuObjList; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuDescriptorBufferInfo = class(TvkuStructure) Buffer: VkBuffer; Offset: VkDeviceSize; Range: VkDeviceSize; function GetStructure: TVkDescriptorBufferInfo; procedure SetStructure(const aData: TVkDescriptorBufferInfo); end; TvkuDescriptorBufferInfoList = specialize TvkuObjList; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuWriteDescriptorSet = class(TvkuStructure) private fImageInfos: TvkuDescriptorImageInfoList; fBufferInfos: TvkuDescriptorBufferInfoList; fTexelBufferViews: TVkBufferViewList; fvkImageInfos: TVkDescriptorImageInfoArr; fvkBufferInfos: TVkDescriptorBufferInfoArr; public DstSet: VkDescriptorSet; DstBinding: VkUint32; DstArrayElement: VkUint32; DescriptorType: TVkDescriptorType; property ImageInfos: TvkuDescriptorImageInfoList read fImageInfos; property BufferInfos: TvkuDescriptorBufferInfoList read fBufferInfos; function GetStructure: TVkWriteDescriptorSet; procedure SetStructure(const aData: TVkWriteDescriptorSet); procedure AfterConstruction; override; procedure BeforeDestruction; override; end; TvkuWriteDescriptorSetList = specialize TvkuObjList; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuCopyDescriptorSet = class(TvkuStructure) public SrcSet: VkDescriptorSet; SrcBinding: VkUint32; SrcArrayElement: VkUint32; DstSet: VkDescriptorSet; DstBinding: VkUint32; DstArrayElement: VkUint32; DescriptorCount: VkUint32; function GetStructure: TVkCopyDescriptorSet; procedure SetStructure(const aData: TVkCopyDescriptorSet); end; TvkuCopyDescriptorSetList = specialize TvkuObjList; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuUpdateDescriptorSetHelper = class(TvkuCommandHelper) private fDeviceCommands: TVkDeviceCommands; fWriteDescriptorSets: TvkuWriteDescriptorSetList; fCopyDescriptorSets: TvkuCopyDescriptorSetList; public property WriteDescriptorSets: TvkuWriteDescriptorSetList read fWriteDescriptorSets; property CopyDescriptorSets: TvkuCopyDescriptorSetList read fCopyDescriptorSets; procedure Execute; constructor Create(const aDeviceCommands: TVkDeviceCommands); destructor Destroy; override; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuDevice = class(TvkuAllocHandle) private fHandle: VkDevice; fInstanceCommands: TVkInstanceCommands; fDeviceCommands: TVkDeviceCommands; procedure CreateHandle( const aPhyDevice: VkPhysicalDevice; const aCreateInfo: PVkDeviceCreateInfo); public property Handle: VkDevice read fHandle; property DeviceCommands: TVkDeviceCommands read fDeviceCommands; function GetQueue( const aQueueFamilyIndex: VkUint32; const aQueueIndex: VkUint32): VkQueue; function AllocateMemory( const aSize: VkUint32; const aMemoryTypeIndex: VkUint32; aAllocCallbacks: PVkAllocationCallbacks = nil): VkDeviceMemory; procedure FreeMemory( const aMemory: VkDeviceMemory; aAllocCallbacks: PVkAllocationCallbacks = nil); procedure WaitIdle; function UpdateDescriptorSet: TvkuUpdateDescriptorSetHelper; constructor Create( const aPhysicalDevice: VkPhysicalDevice; const aCreateInfo: TVkDeviceCreateInfo; const aInstanceCommands: TVkInstanceCommands; const aAllocCallbacks: PVkAllocationCallbacks = nil); constructor Create( const aHandle: VkDevice; const aOwnsHandle: Boolean; const aInstanceCommands: TVkInstanceCommands; const aAllocCallbacks: PVkAllocationCallbacks = nil); destructor Destroy; override; end; implementation uses uvkuUtils; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuDescriptorImageInfo//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuDescriptorImageInfo.GetStructure: TVkDescriptorImageInfo; begin FillByte(result, SizeOf(result), 0); result.sampler := Sampler; result.imageView := ImageView; result.imageLayout := ImageLayout; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuDescriptorImageInfo.SetStructure(const aData: TVkDescriptorImageInfo); begin Sampler := aData.sampler; ImageView := aData.imageView; ImageLayout := aData.imageLayout; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuDescriptorBufferInfo/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuDescriptorBufferInfo.GetStructure: TVkDescriptorBufferInfo; begin FillByte(result, SizeOf(result), 0); result.buffer := Buffer; result.offset := Offset; result.range := Range; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuDescriptorBufferInfo.SetStructure(const aData: TVkDescriptorBufferInfo); begin Buffer := aData.buffer; Offset := aData.offset; Range := aData.range; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuWriteDescriptorSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuWriteDescriptorSet.GetStructure: TVkWriteDescriptorSet; var c, i: Integer; begin c := fImageInfos.Length; if (c < fBufferInfos.Length) then c := fBufferInfos.Length; if (c < fTexelBufferViews.Length) then c := fTexelBufferViews.Length; SetLength(fvkImageInfos, fImageInfos.Length); if (fImageInfos.Length <> 0) and (fImageInfos.Length <> c) then raise TvkuException.Create('ImageInfos, BufferInfos and TexelBufferViews must be empty or must have the same size!'); for i := low(fvkImageInfos) to high(fvkImageInfos) do fvkImageInfos[i] := fImageInfos[i].GetStructure; SetLength(fvkBufferInfos, fBufferInfos.Length); if (fBufferInfos.Length <> 0) and (fBufferInfos.Length <> c) then raise TvkuException.Create('ImageInfos, BufferInfos and TexelBufferViews must be empty or must have the same size!'); for i := low(fvkBufferInfos) to high(fvkBufferInfos) do fvkBufferInfos[i] := fBufferInfos[i].GetStructure; if (fTexelBufferViews.Length <> 0) and (fTexelBufferViews.Length <> c) then raise TvkuException.Create('ImageInfos, BufferInfos and TexelBufferViews must be empty or must have the same size!'); FillByte(result, SizeOf(result), 0); result.sType := VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; result.pNext := nil; result.dstSet := DstSet; result.dstBinding := DstBinding; result.dstArrayElement := DstArrayElement; result.descriptorCount := c; result.descriptorType := DescriptorType; result.pImageInfo := @fvkImageInfos[0]; result.pBufferInfo := @fvkBufferInfos[0]; result.pTexelBufferView := fTexelBufferViews.PData; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuWriteDescriptorSet.SetStructure(const aData: TVkWriteDescriptorSet); var i: Integer; begin if Assigned(aData.pImageInfo) then begin fImageInfos.Length := aData.descriptorCount; for i := 0 to fImageInfos.Length-1 do fImageInfos[i].SetStructure((aData.pImageInfo + i)^); end; if Assigned(aData.pBufferInfo) then begin fBufferInfos.Length := aData.descriptorCount; for i := 0 to fBufferInfos.Length-1 do fBufferInfos[i].SetStructure((aData.pBufferInfo + i)^); end; fTexelBufferViews.SetData(aData.pTexelBufferView, aData.descriptorCount); DstSet := aData.dstSet; DstBinding := aData.dstBinding; DstArrayElement := aData.dstArrayElement; DescriptorType := aData.descriptorType; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuWriteDescriptorSet.AfterConstruction; begin inherited AfterConstruction; fImageInfos := TvkuDescriptorImageInfoList.Create; fBufferInfos := TvkuDescriptorBufferInfoList.Create; fTexelBufferViews := TVkBufferViewList.Create; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuWriteDescriptorSet.BeforeDestruction; begin FreeAndNil(fImageInfos); FreeAndNil(fBufferInfos); FreeAndNil(fTexelBufferViews); inherited BeforeDestruction; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuCopyDescriptorSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuCopyDescriptorSet.GetStructure: TVkCopyDescriptorSet; begin result.sType := VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET; result.pNext := nil; result.srcSet := SrcSet; result.srcBinding := SrcBinding; result.srcArrayElement := SrcArrayElement; result.dstSet := DstSet; result.dstBinding := DstBinding; result.dstArrayElement := DstArrayElement; result.descriptorCount := DescriptorCount; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuCopyDescriptorSet.SetStructure(const aData: TVkCopyDescriptorSet); begin SrcSet := aData.srcSet; SrcBinding := aData.srcBinding; SrcArrayElement := aData.srcArrayElement; DstSet := aData.dstSet; DstBinding := aData.dstBinding; DstArrayElement := aData.dstArrayElement; DescriptorCount := aData.descriptorCount; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuUpdateDescriptorSetHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuUpdateDescriptorSetHelper.Execute; var i: Integer; vkWriteDescriptorSets: array of TVkWriteDescriptorSet; vkCopyDescriptorSets: array of TVkCopyDescriptorSet; begin SetLength(vkWriteDescriptorSets, fWriteDescriptorSets.Length); for i := low(vkWriteDescriptorSets) to high(vkWriteDescriptorSets) do vkWriteDescriptorSets[i] := fWriteDescriptorSets[i].GetStructure; SetLength(vkCopyDescriptorSets, fCopyDescriptorSets.Length); for i := low(vkCopyDescriptorSets) to high(vkCopyDescriptorSets) do vkCopyDescriptorSets[i] := fCopyDescriptorSets[i].GetStructure; fDeviceCommands.vkUpdateDescriptorSets( fDeviceCommands.Device, Length(vkWriteDescriptorSets), @vkWriteDescriptorSets[0], Length(vkCopyDescriptorSets), @vkCopyDescriptorSets[0]); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TvkuUpdateDescriptorSetHelper.Create(const aDeviceCommands: TVkDeviceCommands); begin inherited Create; fDeviceCommands := aDeviceCommands; fWriteDescriptorSets := TvkuWriteDescriptorSetList.Create; fCopyDescriptorSets := TvkuCopyDescriptorSetList.Create; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TvkuUpdateDescriptorSetHelper.Destroy; begin FreeAndNil(fCopyDescriptorSets); FreeAndNil(fWriteDescriptorSets); inherited Destroy; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuDevice///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuDevice.CreateHandle(const aPhyDevice: VkPhysicalDevice; const aCreateInfo: PVkDeviceCreateInfo); var err: TVkResult; begin if not Assigned(fInstanceCommands.vkCreateDevice) then raise TvkuInvalidFuncPtrException.Create('vkCreateDevice'); err := fInstanceCommands.vkCreateDevice(aPhyDevice, aCreateInfo, AllocCallbacks, @fHandle); if (err <> VK_SUCCESS) then raise TvkuErrorException.Create('unable to create device', err); fDeviceCommands := LoadDeviceCommands(fInstanceCommands.Instance, fHandle); if not Assigned(fDeviceCommands) then raise TvkuException.Create('unable to load device commands'); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuDevice.GetQueue(const aQueueFamilyIndex: VkUint32; const aQueueIndex: VkUint32): VkQueue; begin if not Assigned(fDeviceCommands.vkGetDeviceQueue) then raise TvkuInvalidFuncPtrException.Create('vkGetDeviceQueue'); fDeviceCommands.vkGetDeviceQueue(fHandle, aQueueFamilyIndex, aQueueIndex, @result); if (result = VK_INVALID_HANDLE) then raise TvkuException.Create('unable to get device queue'); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuDevice.AllocateMemory(const aSize: VkUint32; const aMemoryTypeIndex: VkUint32; aAllocCallbacks: PVkAllocationCallbacks): VkDeviceMemory; var AllocInfo: TVkMemoryAllocateInfo; err: TVkResult; begin FillByte(AllocInfo, SizeOf(AllocInfo), 0); AllocInfo.sType := VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; AllocInfo.pNext := nil; AllocInfo.allocationSize := aSize; AllocInfo.memoryTypeIndex := aMemoryTypeIndex; if not Assigned(aAllocCallbacks) then aAllocCallbacks := AllocCallbacks; err := fDeviceCommands.vkAllocateMemory(fHandle, @AllocInfo, aAllocCallbacks, @result); if (err <> VK_SUCCESS) then raise TvkuErrorException.Create('unable to allocate device memory', err); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuDevice.FreeMemory(const aMemory: VkDeviceMemory; aAllocCallbacks: PVkAllocationCallbacks); begin if not Assigned(aAllocCallbacks) then aAllocCallbacks := AllocCallbacks; fDeviceCommands.vkFreeMemory(fHandle, aMemory, aAllocCallbacks); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuDevice.WaitIdle; var err: TVkResult; begin err := fDeviceCommands.vkDeviceWaitIdle(fHandle); if (err <> VK_SUCCESS) then raise TvkuErrorException.Create('unable to wait for device idle', err); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuDevice.UpdateDescriptorSet: TvkuUpdateDescriptorSetHelper; begin result := TvkuUpdateDescriptorSetHelper.Create(fDeviceCommands); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TvkuDevice.Create(const aPhysicalDevice: VkPhysicalDevice; const aCreateInfo: TVkDeviceCreateInfo; const aInstanceCommands: TVkInstanceCommands; const aAllocCallbacks: PVkAllocationCallbacks); begin inherited Create; fHandle := nil; fInstanceCommands := aInstanceCommands; SetAllocCallbacks(aAllocCallbacks); CreateHandle(aPhysicalDevice, @aCreateInfo); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TvkuDevice.Create(const aHandle: VkDevice; const aOwnsHandle: Boolean; const aInstanceCommands: TVkInstanceCommands; const aAllocCallbacks: PVkAllocationCallbacks); begin inherited Create; fHandle := aHandle; fInstanceCommands := aInstanceCommands; OwnsHandle := aOwnsHandle; SetAllocCallbacks(aAllocCallbacks); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TvkuDevice.Destroy; begin if OwnsHandle and (fHandle <> VK_INVALID_HANDLE) then fDeviceCommands.vkDestroyDevice(fHandle, AllocCallbacks); fHandle := VK_INVALID_HANDLE; FreeAndNil(fDeviceCommands); inherited Destroy; end; end.