unit uvkuImage; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Vulkan, uvkuBase; type ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TvkuImage = class(TvkuAllocHandle) private fHandle: VkImage; fDeviceCommands: TVkDeviceCommands; procedure CreateHandle(const aCreateInfo: TVkImageCreateInfo); public property Handle: VkImage read fHandle; property DeviceCommands: TVkDeviceCommands read fDeviceCommands; function GetMemoryBarrier( const aAspectMask: VkImageAspectFlags; const aOldLayout: TVkImageLayout; const aNewLayout: TVkImageLayout): TVkImageMemoryBarrier; constructor Create( const aCreateInfo: TVkImageCreateInfo; const aDeviceCommands: TVkDeviceCommands; const aAllocCallbacks: PVkAllocationCallbacks = nil); constructor Create( const aHandle: VkImage; const aOwnsHandle: Boolean; const aDeviceCommands: TVkDeviceCommands; const aAllocCallbacks: PVkAllocationCallbacks = nil); destructor Destroy; override; end; implementation uses uvkuUtils; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TvkuImage////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TvkuImage.CreateHandle(const aCreateInfo: TVkImageCreateInfo); var err: TVkResult; begin err := fDeviceCommands.vkCreateImage(fDeviceCommands.Device, @aCreateInfo, AllocCallbacks, @fHandle); if (err < VK_SUCCESS) then TvkuErrorException.Create('unable to create image', err); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TvkuImage.GetMemoryBarrier( const aAspectMask: VkImageAspectFlags; const aOldLayout: TVkImageLayout; const aNewLayout: TVkImageLayout): TVkImageMemoryBarrier; var range: TVkImageSubresourceRange; begin FillByte(range, SizeOf(range), 0); range.aspectMask := aAspectMask; range.baseMipLevel := 0; range.levelCount := 1; range.baseArrayLayer := 0; range.layerCount := 1; FillByte(result, SizeOf(result), 0); result.sType := VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; result.pNext := nil; result.srcAccessMask := []; result.dstAccessMask := []; result.oldLayout := aOldLayout; result.newLayout := aNewLayout; result.srcQueueFamilyIndex := 0; result.dstQueueFamilyIndex := 0; result.image := fHandle; result.subresourceRange := range; case aOldLayout of // Undefined layout: // Note: Only allowed as initial layout! // Note: Make sure any writes to the image have been finished VK_IMAGE_LAYOUT_UNDEFINED: begin result.srcAccessMask := [ VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT ]; end; // Old layout is color attachment: // Note: Make sure any writes to the color buffer have been finished VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: begin result.srcAccessMask := [ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT ]; end; // Old layout is transfer source: // Note: Make sure any reads from the image have been finished VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: begin result.srcAccessMask := [ VK_ACCESS_TRANSFER_READ_BIT ]; end; // Old layout is shader read (sampler, input attachment): // Note: Make sure any shader reads from the image have been finished VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: begin result.srcAccessMask := [ VK_ACCESS_SHADER_READ_BIT ]; end; end; case aNewLayout of // New layout is transfer destination (copy, blit): // Note: Make sure any copyies to the image have been finished VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: begin result.dstAccessMask := [ VK_ACCESS_TRANSFER_WRITE_BIT ]; end; // New layout is transfer source (copy, blit): // Note: Make sure any reads from and writes to the image have been finished VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: begin result.srcAccessMask := result.srcAccessMask + [ VK_ACCESS_TRANSFER_READ_BIT ]; result.dstAccessMask := [ VK_ACCESS_TRANSFER_READ_BIT ]; end; // New layout is color attachment: // Note: Make sure any writes to the color buffer hav been finished VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: begin result.dstAccessMask := [ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT ]; result.srcAccessMask := [ VK_ACCESS_TRANSFER_READ_BIT ]; end; // New layout is depth attachment: // Note: Make sure any writes to depth/stencil buffer have been finished VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: begin result.dstAccessMask := result.dstAccessMask + [ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT ]; end; // New layout is shader read (sampler, input attachment): // Note: Make sure any writes to the image have been finished VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: begin result.srcAccessMask := [ VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT ]; result.dstAccessMask := [ VK_ACCESS_SHADER_READ_BIT ]; end; end; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TvkuImage.Create(const aCreateInfo: TVkImageCreateInfo; const aDeviceCommands: TVkDeviceCommands; const aAllocCallbacks: PVkAllocationCallbacks); begin inherited Create; fDeviceCommands := aDeviceCommands; SetAllocCallbacks(aAllocCallbacks); CreateHandle(aCreateInfo); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TvkuImage.Create(const aHandle: VkImage; const aOwnsHandle: Boolean; const aDeviceCommands: TVkDeviceCommands; const aAllocCallbacks: PVkAllocationCallbacks); begin inherited Create; fHandle := aHandle; fDeviceCommands := aDeviceCommands; OwnsHandle := aOwnsHandle; SetAllocCallbacks(aAllocCallbacks); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TvkuImage.Destroy; begin if OwnsHandle and (fHandle <> VK_INVALID_NDP_HANDLE) then fDeviceCommands.vkDestroyImage(fDeviceCommands.Device, fHandle, AllocCallbacks); fHandle := VK_INVALID_NDP_HANDLE; inherited Destroy; end; end.