WIP
This commit is contained in:
parent
bf447c1d1d
commit
47e9e3d3f2
|
@ -33,6 +33,8 @@ namespace SHADE
|
|||
};
|
||||
cmdBufferHdl->GetVkCommandBuffer().copyBuffer(stagingBuffer, vkBuffer, 1, ©Region);
|
||||
}
|
||||
|
||||
// TODO: Need to destroy staging buffer. Obviously not here but after the command has finished executing.
|
||||
}
|
||||
|
||||
vk::Buffer SHVkBuffer::GetVkBuffer(void) const noexcept
|
||||
|
|
|
@ -48,7 +48,6 @@ namespace SHADE
|
|||
vk::BufferUsageFlags bufferUsageFlags;
|
||||
|
||||
//! Reference to the allocator
|
||||
//VmaAllocator const& vmaAllocator;
|
||||
std::reference_wrapper<VmaAllocator const> vmaAllocator;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
|
|
@ -406,6 +406,12 @@ namespace SHADE
|
|||
|
||||
}
|
||||
|
||||
|
||||
//void SHVkCommandBuffer::PipelineBarrier(vk::PipelineStageFlags ) const noexcept
|
||||
//{
|
||||
// //vkCommandBuffer.pipelineBarrier()
|
||||
//}
|
||||
|
||||
/***************************************************************************/
|
||||
/*!
|
||||
|
||||
|
|
|
@ -114,6 +114,9 @@ namespace SHADE
|
|||
void DrawArrays (uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) const noexcept;
|
||||
void DrawIndexed (uint32_t indexCount, uint32_t firstIndex, uint32_t vertexOffset) const noexcept;
|
||||
|
||||
// memory barriers
|
||||
//void PipelineBarrier (void) const noexcept;
|
||||
|
||||
// Push Constant variable setting
|
||||
template <typename T>
|
||||
void SetPushConstantVariable(std::string variableName, T const& data) noexcept
|
||||
|
|
|
@ -5,16 +5,88 @@
|
|||
#include "Tools/SHLogger.h"
|
||||
#include "SHVkImageView.h"
|
||||
#include "Graphics/Instance/SHVkInstance.h"
|
||||
#include "Graphics/Buffers/SHVkBuffer.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/***************************************************************************/
|
||||
/*!
|
||||
|
||||
\brief
|
||||
If an image is a GPU only resource, we need to prep a staging buffer
|
||||
to use for transferring data to the GPU. #NoteToSelf: I don't really
|
||||
like this because its duplicate code. Should try to find a way to utilize
|
||||
the logical device for this.
|
||||
|
||||
\param data
|
||||
Data to transfer.
|
||||
|
||||
\param srcSize
|
||||
Size in bytes of the data.
|
||||
|
||||
*/
|
||||
/***************************************************************************/
|
||||
void SHVkImage::PrepStagingBuffer(void* data, uint32_t srcSize) noexcept
|
||||
{
|
||||
// For creation of buffer
|
||||
vk::BufferCreateInfo bufferInfo{};
|
||||
|
||||
// size stored same as GPU buffer
|
||||
bufferInfo.size = srcSize;
|
||||
|
||||
// We just want to set the transfer bit
|
||||
bufferInfo.usage = vk::BufferUsageFlagBits::eTransferSrc;
|
||||
|
||||
// sharing mode exclusive
|
||||
bufferInfo.sharingMode = vk::SharingMode::eExclusive;
|
||||
|
||||
// Set to auto detect bits
|
||||
VmaAllocationCreateInfo allocCreateInfo{};
|
||||
allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO;
|
||||
|
||||
// We want to just write all at once. Using random access bit could make this slow
|
||||
allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||
|
||||
// parameters of a vmaAllocation retrieved via vmaGetAllocationInfo
|
||||
VmaAllocationInfo allocInfo;
|
||||
|
||||
// results of allocation
|
||||
VmaAllocation stagingAlloc;
|
||||
|
||||
// To get around VMA's usage for C version of vulkan, create a temp first...,
|
||||
VkBuffer tempBuffer{};
|
||||
|
||||
// Create the buffer...
|
||||
vmaCreateBuffer(*vmaAllocator,
|
||||
&bufferInfo.operator VkBufferCreateInfo & (), // TODO: Verify if this works (can use renderdoc to check buffer variables?)
|
||||
&allocCreateInfo,
|
||||
&tempBuffer, &stagingAlloc, &allocInfo);
|
||||
|
||||
// then assign it to the hpp version
|
||||
stagingBuffer = tempBuffer;
|
||||
|
||||
// Just map, copy then unmap
|
||||
void* stagingBufferMappedPtr = nullptr;
|
||||
vmaMapMemory(*vmaAllocator, stagingAlloc, &stagingBufferMappedPtr);
|
||||
|
||||
if (stagingBufferMappedPtr)
|
||||
std::memcpy(static_cast<uint8_t*>(stagingBufferMappedPtr), static_cast<uint8_t*>(data), srcSize);
|
||||
|
||||
const VkDeviceSize offsets = 0;
|
||||
const VkDeviceSize sizes = srcSize;
|
||||
vmaFlushAllocations(*vmaAllocator, 1, &stagingAlloc, &offsets, &sizes);
|
||||
|
||||
vmaUnmapMemory(*vmaAllocator, stagingAlloc);
|
||||
}
|
||||
|
||||
SHVkImage::SHVkImage(
|
||||
VmaAllocator const& vmaAllocator,
|
||||
SHImageCreateParams const& imageDetails,
|
||||
unsigned char* data,
|
||||
uint32_t dataSize,
|
||||
VmaMemoryUsage memUsage,
|
||||
VmaAllocationCreateFlags allocFlags
|
||||
VmaAllocator const* allocator,
|
||||
SHImageCreateParams const& imageDetails,
|
||||
unsigned char* data,
|
||||
uint32_t dataSize,
|
||||
std::span<uint32_t> inMipOffsets,
|
||||
VmaMemoryUsage memUsage,
|
||||
VmaAllocationCreateFlags allocFlags
|
||||
) noexcept
|
||||
: imageType { imageDetails.imageType }
|
||||
, width{ imageDetails.width }
|
||||
|
@ -25,6 +97,11 @@ namespace SHADE
|
|||
, imageFormat{ imageDetails.imageFormat }
|
||||
, usageFlags{}
|
||||
, createFlags{}
|
||||
, vmaAllocator{allocator}
|
||||
, mipOffsets { inMipOffsets }
|
||||
, boundToCoherent{false}
|
||||
, randomAccessOptimized {false}
|
||||
, mappedPtr{nullptr}
|
||||
{
|
||||
for (auto& bit : imageDetails.usageBits)
|
||||
usageFlags |= bit;
|
||||
|
@ -66,7 +143,7 @@ namespace SHADE
|
|||
VmaAllocationInfo allocInfo{};
|
||||
|
||||
VkImage tempImage;
|
||||
auto result = vmaCreateImage(vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo&(), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
|
||||
auto result = vmaCreateImage(*vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo&(), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
SHVulkanDebugUtil::ReportVkError(vk::Result(result), "Failed to create vulkan image. ");
|
||||
|
@ -75,55 +152,43 @@ namespace SHADE
|
|||
|
||||
vkImage = tempImage;
|
||||
|
||||
//if (allocFlags & )
|
||||
// At this point the image and device memory have been created.
|
||||
|
||||
if (allocFlags & VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT)
|
||||
randomAccessOptimized = true;
|
||||
|
||||
// TODO: This constructor can only create a GPU only resource for now. Due to time constraint, I was trying to create a ctor
|
||||
// fast to finish up the ImGUI backend. In the future, there definitely needs to be more versatility to the constructor.
|
||||
|
||||
// Get the memory property flags
|
||||
VkMemoryPropertyFlags memPropFlags;
|
||||
vmaGetAllocationMemoryProperties(*vmaAllocator, alloc, &memPropFlags);
|
||||
|
||||
// mainly host visible. Can be cached (need to flush/invalidate), uncached (always coherent) and coherent (virtual).
|
||||
//if (memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
|
||||
//{
|
||||
// // If memory is marked to be coherent between CPU and GPU (no need flush/invalidate) (TODO: Verify if VMA_ALLOCATION_CREATE_MAPPED_BIT is used when VMA_MEMORY_USAGE_AUTO is set)
|
||||
// // TODO: also verify that coherent bit = pointer is already mapped
|
||||
// if (memPropFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
|
||||
// {
|
||||
// boundToCoherent = true;
|
||||
// mappedPtr = allocInfo.pMappedData;
|
||||
// }
|
||||
// else
|
||||
// mappedPtr = nullptr;
|
||||
|
||||
// if (data)
|
||||
// MapWriteUnmap(data, srcSize, 0, 0);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// We can prep first so that we can do transfers later via 1 cmd buffer recording
|
||||
PrepStagingBuffer(data, dataSize);
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
/*!
|
||||
|
||||
\brief
|
||||
This is mainly used for images that aren't created internally because
|
||||
they cannot be created in the traditional way (e.g. swapchain images).
|
||||
|
||||
\param inVkImage
|
||||
Image already created outside
|
||||
|
||||
\param width
|
||||
Width of the image
|
||||
|
||||
\param height
|
||||
Height of the image
|
||||
|
||||
\param depth
|
||||
Depth of the image
|
||||
|
||||
\param levels
|
||||
Number of levels in the image
|
||||
|
||||
\param arrayLayers
|
||||
if the image is an array, this value will be > 1.
|
||||
|
||||
\param imageFormat
|
||||
Format of the image
|
||||
|
||||
*/
|
||||
/***************************************************************************/
|
||||
SHVkImage::SHVkImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t arrayLayers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept
|
||||
: vkImage (inVkImage)
|
||||
, width{ inWidth }
|
||||
, height{ inHeight }
|
||||
, depth{ inDepth }
|
||||
, mipLevelCount{ levels }
|
||||
, layerCount{ arrayLayers }
|
||||
, imageFormat{ format }
|
||||
, usageFlags{flags}
|
||||
, alloc{}
|
||||
, imageType{type}
|
||||
, createFlags{}
|
||||
{
|
||||
}
|
||||
|
||||
SHVkImage::SHVkImage(VmaAllocator const& vmaAllocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept
|
||||
SHVkImage::SHVkImage(VmaAllocator const* allocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept
|
||||
: width {w}
|
||||
, height{h}
|
||||
, depth {1}
|
||||
|
@ -132,6 +197,7 @@ namespace SHADE
|
|||
, imageFormat{format}
|
||||
, usageFlags{usage}
|
||||
, createFlags {create}
|
||||
, vmaAllocator {allocator}
|
||||
{
|
||||
vk::ImageCreateInfo imageCreateInfo{};
|
||||
imageCreateInfo.imageType = vk::ImageType::e2D;
|
||||
|
@ -157,7 +223,7 @@ namespace SHADE
|
|||
VmaAllocationInfo allocInfo{};
|
||||
|
||||
VkImage tempImage;
|
||||
auto result = vmaCreateImage(vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
|
||||
auto result = vmaCreateImage(*vmaAllocator, &imageCreateInfo.operator VkImageCreateInfo & (), &allocCreateInfo, &tempImage, &alloc, &allocInfo);
|
||||
vkImage = tempImage;
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
|
@ -171,6 +237,69 @@ namespace SHADE
|
|||
return SHVkInstance::GetResourceManager().Create<SHVkImageView>(inLogicalDeviceHdl, parent, createParams);
|
||||
}
|
||||
|
||||
void SHVkImage::TransferToDeviceResource(Handle<SHVkCommandBuffer> const& cmdBufferHdl) noexcept
|
||||
{
|
||||
// prepare copy regions
|
||||
std::vector<vk::BufferImageCopy> copyRegions{mipOffsets.size()};
|
||||
|
||||
for (uint32_t i = 0; i < mipOffsets.size(); ++i)
|
||||
{
|
||||
copyRegions[i].bufferOffset = mipOffsets[i];
|
||||
copyRegions[i].bufferRowLength = 0; // for padding
|
||||
copyRegions[i].bufferImageHeight = 0; // for padding
|
||||
copyRegions[i].imageSubresource.aspectMask = vk::ImageAspectFlagBits::eColor; // TODO: Need to change this to base it off image format.
|
||||
copyRegions[i].imageSubresource.mipLevel = i;
|
||||
copyRegions[i].imageSubresource.baseArrayLayer = 0; // TODO: Array textures not supported yet
|
||||
copyRegions[i].imageSubresource.layerCount = layerCount;
|
||||
copyRegions[i].imageOffset = vk::Offset3D{ 0,0,0 };
|
||||
copyRegions[i].imageExtent = vk::Extent3D{ width >> i, height >> i, 1 };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SHVkImage::TransitionImage(vk::ImageLayout oldLayout, vk::ImageLayout newLayout) noexcept
|
||||
{
|
||||
vk::ImageMemoryBarrier barrier{};
|
||||
barrier.oldLayout = oldLayout;
|
||||
barrier.newLayout = newLayout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = vkImage;
|
||||
barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; // TODO: Need to change this to base it off image format.
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = mipLevelCount;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = layerCount;
|
||||
|
||||
vk::PipelineStageFlagBits srcStage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
vk::PipelineStageFlagBits dstStage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
|
||||
if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal)
|
||||
{
|
||||
srcStage = vk::PipelineStageFlagBits::eTopOfPipe;
|
||||
dstStage = vk::PipelineStageFlagBits::eTransfer;
|
||||
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eNone;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
}
|
||||
else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal)
|
||||
{
|
||||
srcStage = vk::PipelineStageFlagBits::eTransfer;
|
||||
|
||||
// TODO, what if we want to access in compute shader
|
||||
dstStage = vk::PipelineStageFlagBits::eFragmentShader;
|
||||
|
||||
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
|
||||
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
|
||||
}
|
||||
else
|
||||
{
|
||||
SHLOG_ERROR("Image layouts are invalid. ");
|
||||
}
|
||||
|
||||
//cmdBufferHdl
|
||||
}
|
||||
|
||||
void SHVkImage::LinkWithExteriorImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t layers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept
|
||||
{
|
||||
vkImage = inVkImage;
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace SHADE
|
|||
{
|
||||
class SHVkLogicalDevice;
|
||||
class SHVkImageView;
|
||||
class SHVkCommandBuffer;
|
||||
|
||||
struct SHImageCreateParams
|
||||
{
|
||||
|
@ -47,6 +48,12 @@ namespace SHADE
|
|||
/*-----------------------------------------------------------------------*/
|
||||
/* PRIVATE MEMBER VARIABLES */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
//! Pointer to the vma allocator. #NoteToSelf: Not super proud of this being a pointer.
|
||||
//! The only reason why this is a pointer is because a reference_wrapper cannot be default constructed.
|
||||
//! And the reason why we want a default constructor is because sometimes we don't want to create images
|
||||
//! but merely link them from outside (swapchain images)
|
||||
VmaAllocator const* vmaAllocator;
|
||||
|
||||
//! 1D, 2D or 3D
|
||||
vk::ImageType imageType = vk::ImageType::e2D;
|
||||
|
||||
|
@ -80,6 +87,29 @@ namespace SHADE
|
|||
//! allocation object containing details of an allocation
|
||||
VmaAllocation alloc{};
|
||||
|
||||
//! Whether or not this image is HOST_VISIBLE and random access optimized
|
||||
bool randomAccessOptimized;
|
||||
|
||||
//! Whether or not the memory the image is bound to is memory coherent (updates on CPU can be seen on GPU without flushing cache)
|
||||
bool boundToCoherent;
|
||||
|
||||
//! Persistently mapped pointer if applicable (will be void if image is
|
||||
//! not created with the correct flags). Note that this is only used for
|
||||
//! persistent mapping. One time updates do not use this pointer.
|
||||
void* mappedPtr;
|
||||
|
||||
//! Staging buffer for images purely in the GPU
|
||||
vk::Buffer stagingBuffer;
|
||||
|
||||
//! Mipmap offsets for initializing the vk::BufferImageCopy during transfer to GPU resource
|
||||
std::span<uint32_t> mipOffsets;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* PRIVATE MEMBER FUNCTIONS */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
void PrepStagingBuffer(void* data, uint32_t srcSize) noexcept;
|
||||
|
||||
|
||||
public:
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* CTOR AND DTOR */
|
||||
|
@ -87,16 +117,16 @@ namespace SHADE
|
|||
SHVkImage(void) noexcept = default;
|
||||
|
||||
SHVkImage(
|
||||
VmaAllocator const& vmaAllocator,
|
||||
SHImageCreateParams const& imageDetails,
|
||||
unsigned char* data,
|
||||
uint32_t dataSize,
|
||||
VmaMemoryUsage memUsage,
|
||||
VmaAllocationCreateFlags allocFlags
|
||||
VmaAllocator const* allocator,
|
||||
SHImageCreateParams const& imageDetails,
|
||||
unsigned char* data,
|
||||
uint32_t dataSize,
|
||||
std::span<uint32_t> inMipOffsets,
|
||||
VmaMemoryUsage memUsage,
|
||||
VmaAllocationCreateFlags allocFlags
|
||||
) noexcept;
|
||||
|
||||
SHVkImage(vk::Image inVkImage, vk::ImageType type, uint32_t inWidth, uint32_t inHeight, uint32_t inDepth, uint32_t arrayLayers, uint8_t levels, vk::Format format, vk::ImageUsageFlags flags) noexcept;
|
||||
SHVkImage(VmaAllocator const& vmaAllocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept;
|
||||
SHVkImage(VmaAllocator const* allocator, uint32_t w, uint32_t h, uint8_t levels, vk::Format format, vk::ImageUsageFlags usage, vk::ImageCreateFlags create) noexcept;
|
||||
|
||||
SHVkImage(SHVkImage&& rhs) noexcept = default;
|
||||
SHVkImage& operator=(SHVkImage && rhs) noexcept = default;
|
||||
|
@ -104,7 +134,9 @@ namespace SHADE
|
|||
/*-----------------------------------------------------------------------*/
|
||||
/* PUBLIC MEMBER FUNCTIONS */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
Handle<SHVkImageView> CreateImageView(Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) const noexcept;
|
||||
Handle<SHVkImageView> CreateImageView (Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl, Handle<SHVkImage> const& parent, SHImageViewDetails const& createParams) const noexcept;
|
||||
void TransferToDeviceResource (Handle<SHVkCommandBuffer> const& cmdBufferHdl) noexcept;
|
||||
void TransitionImage (vk::ImageLayout oldLayout, vk::ImageLayout newLayout) noexcept;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* GETTERS AND SETTERS */
|
||||
|
|
Loading…
Reference in New Issue