Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
261 changes: 261 additions & 0 deletions src/Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6153,6 +6153,264 @@ static void TestMemoryUsage()
}
}

static void TestDataUploadingWithStagingBuffer()
{
wprintf(L"Testing data uploading with staging buffer...\n");

// Generate some random data to fill the uniform buffer with.
const VkDeviceSize bufferSize = 65536;
std::vector<std::uint8_t> bufferData(bufferSize);
for (auto& bufferByte : bufferData) {
bufferByte = static_cast<std::uint8_t>(rand() % 256);
Comment thread
IAmNotHanni marked this conversation as resolved.
Outdated
}

VkBufferCreateInfo uniformBufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
uniformBufferCI.size = bufferSize;
uniformBufferCI.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; // Change this if you want to create another type of buffer.

VmaAllocationCreateInfo uniformBufferAllocCI = {};
uniformBufferAllocCI.usage = VMA_MEMORY_USAGE_AUTO;
uniformBufferAllocCI.flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
Comment thread
IAmNotHanni marked this conversation as resolved.
Outdated

VkBuffer uniformBuffer = VK_NULL_HANDLE;
VmaAllocation uniformBufferAlloc = {};
Comment thread
IAmNotHanni marked this conversation as resolved.
Outdated
VmaAllocationInfo uniformBufferAllocInfo = {};

VkResult result = vmaCreateBuffer(g_hAllocator, &uniformBufferCI, &uniformBufferAllocCI, &uniformBuffer, &uniformBufferAlloc, &uniformBufferAllocInfo);
TEST(result == VK_SUCCESS);

// We need to check if the uniform buffer really ended NOT up in mappable memory.
Comment thread
IAmNotHanni marked this conversation as resolved.
Outdated
VkMemoryPropertyFlags memPropFlags;
vmaGetAllocationMemoryProperties(g_hAllocator, uniformBufferAlloc, &memPropFlags);
TEST(!(memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));

VkBufferCreateInfo stagingBufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
stagingBufferCI.size = bufferSize;
stagingBufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;

VmaAllocationCreateInfo stagingBufferAllocCI = {};
stagingBufferAllocCI.usage = VMA_MEMORY_USAGE_AUTO;
stagingBufferAllocCI.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;

VkBuffer stagingBuffer = VK_NULL_HANDLE;
VmaAllocation stagingBufferAlloc = {};
VmaAllocationInfo stagingBufferAllocInfo = {};

result = vmaCreateBuffer(g_hAllocator, &stagingBufferCI, &stagingBufferAllocCI, &stagingBuffer, &stagingBufferAlloc, &stagingBufferAllocInfo);
TEST(result == VK_SUCCESS);

TEST(stagingBufferAllocInfo.pMappedData != nullptr);
Comment thread
IAmNotHanni marked this conversation as resolved.
std::memcpy(stagingBufferAllocInfo.pMappedData, bufferData.data(), bufferData.size());

result = vmaFlushAllocation(g_hAllocator, uniformBufferAlloc, 0, VK_WHOLE_SIZE);
TEST(result == VK_SUCCESS);

BeginSingleTimeCommands();

VkBufferMemoryBarrier bufferMemBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER };
bufferMemBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
bufferMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
bufferMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier.buffer = stagingBuffer;
bufferMemBarrier.offset = 0;
bufferMemBarrier.size = VK_WHOLE_SIZE;

vkCmdPipelineBarrier(g_hTemporaryCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &bufferMemBarrier, 0, nullptr);

VkBufferCopy bufferCopy = {};
bufferCopy.srcOffset = 0;
bufferCopy.dstOffset = 0;
bufferCopy.size = bufferSize;

vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingBuffer, uniformBuffer, 1, &bufferCopy);

VkBufferMemoryBarrier bufferMemBarrier2 = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER };
bufferMemBarrier2.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
bufferMemBarrier2.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT; // Change this if you want to create another type of buffer.
bufferMemBarrier2.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier2.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier2.buffer = uniformBuffer;
bufferMemBarrier2.offset = 0;
bufferMemBarrier2.size = VK_WHOLE_SIZE;

vkCmdPipelineBarrier(g_hTemporaryCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, nullptr, 1, &bufferMemBarrier2, 0, nullptr);

EndSingleTimeCommands();

vmaDestroyBuffer(g_hAllocator, stagingBuffer, stagingBufferAlloc);
vmaDestroyBuffer(g_hAllocator, uniformBuffer, uniformBufferAlloc);
}

static void TestDataUploadingWithMappedMemory() {
wprintf(L"Testing data uploading with mapped memory and memcpy...\n");

// Generate some random data to fill the uniform buffer with.
const VkDeviceSize bufferSize = 65536;
std::vector<std::uint8_t> bufferData(bufferSize);
for (auto& bufferByte : bufferData) {
bufferByte = static_cast<std::uint8_t>(rand() % 256);
}

VkBufferCreateInfo uniformBufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
uniformBufferCI.size = bufferSize;
uniformBufferCI.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; // Change this if you want to create another type of buffer.

VmaAllocationCreateInfo uniformBufferAllocCI = {};
uniformBufferAllocCI.usage = VMA_MEMORY_USAGE_AUTO;
uniformBufferAllocCI.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; // We want memory to be mapped so we can use memcpy to update it

VkBuffer uniformBuffer = VK_NULL_HANDLE;
VmaAllocation uniformBufferAlloc = {};
VmaAllocationInfo uniformBufferAllocInfo = {};

VkResult result = vmaCreateBuffer(g_hAllocator, &uniformBufferCI, &uniformBufferAllocCI, &uniformBuffer, &uniformBufferAlloc, &uniformBufferAllocInfo);
TEST(result == VK_SUCCESS);

// We need to check if the uniform buffer really ended up in mappable memory.
VkMemoryPropertyFlags memPropFlags;
vmaGetAllocationMemoryProperties(g_hAllocator, uniformBufferAlloc, &memPropFlags);
TEST(memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);

TEST(uniformBufferAllocInfo.pMappedData != nullptr);
std::memcpy(uniformBufferAllocInfo.pMappedData, bufferData.data(), bufferData.size());

// We don't need to check for VK_MEMORY_PROPERTY_HOST_COHERENT_BIT because both vmaFlushAllocation and vmaInvalidateAllocation check for this internally.
result = vmaFlushAllocation(g_hAllocator, uniformBufferAlloc, 0, VK_WHOLE_SIZE);
TEST(result == VK_SUCCESS);

BeginSingleTimeCommands();

VkBufferMemoryBarrier bufferMemBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER };
bufferMemBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
bufferMemBarrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT; // Change this if you want to create another type of buffer.
bufferMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier.buffer = uniformBuffer;
bufferMemBarrier.offset = 0;
bufferMemBarrier.size = VK_WHOLE_SIZE;

vkCmdPipelineBarrier(g_hTemporaryCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, nullptr, 1, &bufferMemBarrier, 0, nullptr);

EndSingleTimeCommands();

vmaDestroyBuffer(g_hAllocator, uniformBuffer, uniformBufferAlloc);
}

static void TestAdvancedDataUploading() {
wprintf(L"Testing advanced data uploading...\n");

// Generate some random data to fill the uniform buffer with.
const VkDeviceSize bufferSize = 65536;
std::vector<std::uint8_t> bufferData(bufferSize);
for (auto& bufferByte : bufferData) {
bufferByte = static_cast<std::uint8_t>(rand() % 256);
}

VkBufferCreateInfo uniformBufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
uniformBufferCI.size = bufferSize;
uniformBufferCI.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; // Change this if you want to create another type of buffer.

VmaAllocationCreateInfo uniformBufferAllocCI = {};
uniformBufferAllocCI.usage = VMA_MEMORY_USAGE_AUTO;
uniformBufferAllocCI.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;
Comment thread
IAmNotHanni marked this conversation as resolved.
Outdated

VkBuffer uniformBuffer = VK_NULL_HANDLE;
VmaAllocation uniformBufferAlloc = {};
VmaAllocationInfo uniformBufferAllocInfo = {};

VkResult result = vmaCreateBuffer(g_hAllocator, &uniformBufferCI, &uniformBufferAllocCI, &uniformBuffer, &uniformBufferAlloc, &uniformBufferAllocInfo);
TEST(result == VK_SUCCESS);

VkMemoryPropertyFlags memPropFlags;
vmaGetAllocationMemoryProperties(g_hAllocator, uniformBufferAlloc, &memPropFlags);

if (memPropFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
// The allocation ended up as mapped memory, meaning we can update it simply by using std::memcpy.
TEST(uniformBufferAllocInfo.pMappedData != nullptr);
std::memcpy(uniformBufferAllocInfo.pMappedData, bufferData.data(), bufferData.size());

// We don't need to check for VK_MEMORY_PROPERTY_HOST_COHERENT_BIT because both vmaFlushAllocation and vmaInvalidateAllocation check for this internally.
result = vmaFlushAllocation(g_hAllocator, uniformBufferAlloc, 0, VK_WHOLE_SIZE);
TEST(result == VK_SUCCESS);

BeginSingleTimeCommands();

VkBufferMemoryBarrier bufferMemBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER };
bufferMemBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
bufferMemBarrier.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT; // Change this if you want to create another type of buffer.
bufferMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier.buffer = uniformBuffer;
bufferMemBarrier.offset = 0;
bufferMemBarrier.size = VK_WHOLE_SIZE;

vkCmdPipelineBarrier(g_hTemporaryCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, nullptr, 1, &bufferMemBarrier, 0, nullptr);

EndSingleTimeCommands();
}
else {
// The allocation did not end up in mapped memory, so we need a staging buffer and a copy operation to update it.
VkBufferCreateInfo stagingBufferCI = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
stagingBufferCI.size = bufferSize;
stagingBufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;

VmaAllocationCreateInfo stagingBufferAllocCI = {};
stagingBufferAllocCI.usage = VMA_MEMORY_USAGE_AUTO;
stagingBufferAllocCI.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT;

VkBuffer stagingBuffer = VK_NULL_HANDLE;
VmaAllocation stagingBufferAlloc = {};
VmaAllocationInfo stagingBufferAllocInfo = {};

result = vmaCreateBuffer(g_hAllocator, &stagingBufferCI, &stagingBufferAllocCI, &stagingBuffer, &stagingBufferAlloc, &stagingBufferAllocInfo);
TEST(result == VK_SUCCESS);

TEST(stagingBufferAllocInfo.pMappedData != nullptr);
std::memcpy(stagingBufferAllocInfo.pMappedData, bufferData.data(), bufferData.size());

result = vmaFlushAllocation(g_hAllocator, uniformBufferAlloc, 0, VK_WHOLE_SIZE);
TEST(result == VK_SUCCESS);

BeginSingleTimeCommands();

VkBufferMemoryBarrier bufferMemBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER };
bufferMemBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
bufferMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
bufferMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier.buffer = stagingBuffer;
bufferMemBarrier.offset = 0;
bufferMemBarrier.size = VK_WHOLE_SIZE;

vkCmdPipelineBarrier(g_hTemporaryCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1, &bufferMemBarrier, 0, nullptr);

VkBufferCopy bufferCopy = {};
bufferCopy.srcOffset = 0;
bufferCopy.dstOffset = 0;
bufferCopy.size = bufferSize;

vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingBuffer, uniformBuffer, 1, &bufferCopy);

VkBufferMemoryBarrier bufferMemBarrier2 = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER };
bufferMemBarrier2.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
bufferMemBarrier2.dstAccessMask = VK_ACCESS_UNIFORM_READ_BIT; // Change this if you want to create another type of buffer.
bufferMemBarrier2.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier2.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
bufferMemBarrier2.buffer = uniformBuffer;
bufferMemBarrier2.offset = 0;
bufferMemBarrier2.size = VK_WHOLE_SIZE;

vkCmdPipelineBarrier(g_hTemporaryCommandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, nullptr, 1, &bufferMemBarrier2, 0, nullptr);

EndSingleTimeCommands();

vmaDestroyBuffer(g_hAllocator, stagingBuffer, stagingBufferAlloc);
}

vmaDestroyBuffer(g_hAllocator, uniformBuffer, uniformBufferAlloc);
}

static uint32_t FindDeviceCoherentMemoryTypeBits()
{
VkPhysicalDeviceMemoryProperties memProps;
Expand Down Expand Up @@ -8352,6 +8610,9 @@ void Test()
TestAllocationsInitialization();
#endif
TestMemoryUsage();
TestDataUploadingWithStagingBuffer();
TestDataUploadingWithMappedMemory();
TestAdvancedDataUploading();
TestDeviceCoherentMemory();
TestStatistics();
TestAliasing();
Expand Down