Merge pull request #11132 from K0bin/vma
Vulkan: Use VMA for memory allocations
This commit is contained in:
commit
06bd0a9086
|
@ -37,3 +37,6 @@
|
||||||
url = https://github.com/randy408/libspng.git
|
url = https://github.com/randy408/libspng.git
|
||||||
branch = v0.7.2
|
branch = v0.7.2
|
||||||
shallow = true
|
shallow = true
|
||||||
|
[submodule "Externals/VulkanMemoryAllocator"]
|
||||||
|
path = Externals/VulkanMemoryAllocator
|
||||||
|
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit c351692490513cdb0e5a2c925aaf7ea4a9b672f4
|
|
@ -52,6 +52,7 @@ PRIVATE
|
||||||
target_include_directories(videovulkan
|
target_include_directories(videovulkan
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}/Externals/Vulkan/Include
|
${CMAKE_SOURCE_DIR}/Externals/Vulkan/Include
|
||||||
|
${CMAKE_SOURCE_DIR}/Externals/VulkanMemoryAllocator/include
|
||||||
)
|
)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
|
|
|
@ -525,13 +525,6 @@ void CommandBufferManager::BeginCommandBuffer()
|
||||||
m_current_cmd_buffer = next_buffer_index;
|
m_current_cmd_buffer = next_buffer_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferManager::DeferBufferDestruction(VkBuffer object)
|
|
||||||
{
|
|
||||||
CmdBufferResources& cmd_buffer_resources = GetCurrentCmdBufferResources();
|
|
||||||
cmd_buffer_resources.cleanup_resources.push_back(
|
|
||||||
[object]() { vkDestroyBuffer(g_vulkan_context->GetDevice(), object, nullptr); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandBufferManager::DeferBufferViewDestruction(VkBufferView object)
|
void CommandBufferManager::DeferBufferViewDestruction(VkBufferView object)
|
||||||
{
|
{
|
||||||
CmdBufferResources& cmd_buffer_resources = GetCurrentCmdBufferResources();
|
CmdBufferResources& cmd_buffer_resources = GetCurrentCmdBufferResources();
|
||||||
|
@ -539,11 +532,12 @@ void CommandBufferManager::DeferBufferViewDestruction(VkBufferView object)
|
||||||
[object]() { vkDestroyBufferView(g_vulkan_context->GetDevice(), object, nullptr); });
|
[object]() { vkDestroyBufferView(g_vulkan_context->GetDevice(), object, nullptr); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferManager::DeferDeviceMemoryDestruction(VkDeviceMemory object)
|
void CommandBufferManager::DeferBufferDestruction(VkBuffer buffer, VmaAllocation alloc)
|
||||||
{
|
{
|
||||||
CmdBufferResources& cmd_buffer_resources = GetCurrentCmdBufferResources();
|
CmdBufferResources& cmd_buffer_resources = GetCurrentCmdBufferResources();
|
||||||
cmd_buffer_resources.cleanup_resources.push_back(
|
cmd_buffer_resources.cleanup_resources.push_back([buffer, alloc]() {
|
||||||
[object]() { vkFreeMemory(g_vulkan_context->GetDevice(), object, nullptr); });
|
vmaDestroyBuffer(g_vulkan_context->GetMemoryAllocator(), buffer, alloc);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferManager::DeferFramebufferDestruction(VkFramebuffer object)
|
void CommandBufferManager::DeferFramebufferDestruction(VkFramebuffer object)
|
||||||
|
@ -553,11 +547,11 @@ void CommandBufferManager::DeferFramebufferDestruction(VkFramebuffer object)
|
||||||
[object]() { vkDestroyFramebuffer(g_vulkan_context->GetDevice(), object, nullptr); });
|
[object]() { vkDestroyFramebuffer(g_vulkan_context->GetDevice(), object, nullptr); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferManager::DeferImageDestruction(VkImage object)
|
void CommandBufferManager::DeferImageDestruction(VkImage image, VmaAllocation alloc)
|
||||||
{
|
{
|
||||||
CmdBufferResources& cmd_buffer_resources = GetCurrentCmdBufferResources();
|
CmdBufferResources& cmd_buffer_resources = GetCurrentCmdBufferResources();
|
||||||
cmd_buffer_resources.cleanup_resources.push_back(
|
cmd_buffer_resources.cleanup_resources.push_back(
|
||||||
[object]() { vkDestroyImage(g_vulkan_context->GetDevice(), object, nullptr); });
|
[image, alloc]() { vmaDestroyImage(g_vulkan_context->GetMemoryAllocator(), image, alloc); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferManager::DeferImageViewDestruction(VkImageView object)
|
void CommandBufferManager::DeferImageViewDestruction(VkImageView object)
|
||||||
|
|
|
@ -86,11 +86,10 @@ public:
|
||||||
|
|
||||||
// Schedule a vulkan resource for destruction later on. This will occur when the command buffer
|
// Schedule a vulkan resource for destruction later on. This will occur when the command buffer
|
||||||
// is next re-used, and the GPU has finished working with the specified resource.
|
// is next re-used, and the GPU has finished working with the specified resource.
|
||||||
void DeferBufferDestruction(VkBuffer object);
|
|
||||||
void DeferBufferViewDestruction(VkBufferView object);
|
void DeferBufferViewDestruction(VkBufferView object);
|
||||||
void DeferDeviceMemoryDestruction(VkDeviceMemory object);
|
void DeferBufferDestruction(VkBuffer buffer, VmaAllocation alloc);
|
||||||
void DeferFramebufferDestruction(VkFramebuffer object);
|
void DeferFramebufferDestruction(VkFramebuffer object);
|
||||||
void DeferImageDestruction(VkImage object);
|
void DeferImageDestruction(VkImage object, VmaAllocation alloc);
|
||||||
void DeferImageViewDestruction(VkImageView object);
|
void DeferImageViewDestruction(VkImageView object);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -10,12 +10,13 @@
|
||||||
|
|
||||||
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
#include "VideoBackends/Vulkan/CommandBufferManager.h"
|
||||||
#include "VideoBackends/Vulkan/VulkanContext.h"
|
#include "VideoBackends/Vulkan/VulkanContext.h"
|
||||||
|
#include "VideoCommon/DriverDetails.h"
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
StagingBuffer::StagingBuffer(STAGING_BUFFER_TYPE type, VkBuffer buffer, VkDeviceMemory memory,
|
StagingBuffer::StagingBuffer(STAGING_BUFFER_TYPE type, VkBuffer buffer, VmaAllocation alloc,
|
||||||
VkDeviceSize size, bool coherent)
|
VkDeviceSize size, char* map_ptr)
|
||||||
: m_type(type), m_buffer(buffer), m_memory(memory), m_size(size), m_coherent(coherent)
|
: m_type(type), m_buffer(buffer), m_alloc(alloc), m_size(size), m_map_pointer(map_ptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +26,7 @@ StagingBuffer::~StagingBuffer()
|
||||||
if (m_map_pointer)
|
if (m_map_pointer)
|
||||||
Unmap();
|
Unmap();
|
||||||
|
|
||||||
g_command_buffer_mgr->DeferDeviceMemoryDestruction(m_memory);
|
g_command_buffer_mgr->DeferBufferDestruction(m_buffer, m_alloc);
|
||||||
g_command_buffer_mgr->DeferBufferDestruction(m_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StagingBuffer::BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer buffer,
|
void StagingBuffer::BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer buffer,
|
||||||
|
@ -51,49 +51,21 @@ void StagingBuffer::BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer
|
||||||
&buffer_info, 0, nullptr);
|
&buffer_info, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StagingBuffer::Map(VkDeviceSize offset, VkDeviceSize size)
|
bool StagingBuffer::Map()
|
||||||
{
|
{
|
||||||
m_map_offset = offset;
|
// The staging buffer is permanently mapped and VMA handles the mapping for us
|
||||||
if (size == VK_WHOLE_SIZE)
|
|
||||||
m_map_size = m_size - offset;
|
|
||||||
else
|
|
||||||
m_map_size = size;
|
|
||||||
|
|
||||||
ASSERT(!m_map_pointer);
|
|
||||||
ASSERT(m_map_offset + m_map_size <= m_size);
|
|
||||||
|
|
||||||
void* map_pointer;
|
|
||||||
VkResult res = vkMapMemory(g_vulkan_context->GetDevice(), m_memory, m_map_offset, m_map_size, 0,
|
|
||||||
&map_pointer);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkMapMemory failed: ");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_map_pointer = reinterpret_cast<char*>(map_pointer);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StagingBuffer::Unmap()
|
void StagingBuffer::Unmap()
|
||||||
{
|
{
|
||||||
ASSERT(m_map_pointer);
|
// The staging buffer is permanently mapped and VMA handles the unmapping for us
|
||||||
|
|
||||||
vkUnmapMemory(g_vulkan_context->GetDevice(), m_memory);
|
|
||||||
m_map_pointer = nullptr;
|
|
||||||
m_map_offset = 0;
|
|
||||||
m_map_size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StagingBuffer::FlushCPUCache(VkDeviceSize offset, VkDeviceSize size)
|
void StagingBuffer::FlushCPUCache(VkDeviceSize offset, VkDeviceSize size)
|
||||||
{
|
{
|
||||||
ASSERT(offset >= m_map_offset);
|
// vmaFlushAllocation checks whether the allocation uses a coherent memory type internally
|
||||||
if (m_coherent)
|
vmaFlushAllocation(g_vulkan_context->GetMemoryAllocator(), m_alloc, offset, size);
|
||||||
return;
|
|
||||||
|
|
||||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr, m_memory,
|
|
||||||
offset - m_map_offset, size};
|
|
||||||
vkFlushMappedMemoryRanges(g_vulkan_context->GetDevice(), 1, &range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StagingBuffer::InvalidateGPUCache(VkCommandBuffer command_buffer,
|
void StagingBuffer::InvalidateGPUCache(VkCommandBuffer command_buffer,
|
||||||
|
@ -101,7 +73,9 @@ void StagingBuffer::InvalidateGPUCache(VkCommandBuffer command_buffer,
|
||||||
VkPipelineStageFlagBits dest_pipeline_stage,
|
VkPipelineStageFlagBits dest_pipeline_stage,
|
||||||
VkDeviceSize offset, VkDeviceSize size)
|
VkDeviceSize offset, VkDeviceSize size)
|
||||||
{
|
{
|
||||||
if (m_coherent)
|
VkMemoryPropertyFlags flags = 0;
|
||||||
|
vmaGetAllocationMemoryProperties(g_vulkan_context->GetMemoryAllocator(), m_alloc, &flags);
|
||||||
|
if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) [[likely]]
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ASSERT((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
ASSERT((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
||||||
|
@ -114,7 +88,9 @@ void StagingBuffer::PrepareForGPUWrite(VkCommandBuffer command_buffer,
|
||||||
VkPipelineStageFlagBits dst_pipeline_stage,
|
VkPipelineStageFlagBits dst_pipeline_stage,
|
||||||
VkDeviceSize offset, VkDeviceSize size)
|
VkDeviceSize offset, VkDeviceSize size)
|
||||||
{
|
{
|
||||||
if (m_coherent)
|
VkMemoryPropertyFlags flags = 0;
|
||||||
|
vmaGetAllocationMemoryProperties(g_vulkan_context->GetMemoryAllocator(), m_alloc, &flags);
|
||||||
|
if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) [[likely]]
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ASSERT((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
ASSERT((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
||||||
|
@ -126,7 +102,9 @@ void StagingBuffer::FlushGPUCache(VkCommandBuffer command_buffer, VkAccessFlagBi
|
||||||
VkPipelineStageFlagBits src_pipeline_stage, VkDeviceSize offset,
|
VkPipelineStageFlagBits src_pipeline_stage, VkDeviceSize offset,
|
||||||
VkDeviceSize size)
|
VkDeviceSize size)
|
||||||
{
|
{
|
||||||
if (m_coherent)
|
VkMemoryPropertyFlags flags = 0;
|
||||||
|
vmaGetAllocationMemoryProperties(g_vulkan_context->GetMemoryAllocator(), m_alloc, &flags);
|
||||||
|
if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) [[likely]]
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ASSERT((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
ASSERT((offset + size) <= m_size || (offset < m_size && size == VK_WHOLE_SIZE));
|
||||||
|
@ -136,39 +114,32 @@ void StagingBuffer::FlushGPUCache(VkCommandBuffer command_buffer, VkAccessFlagBi
|
||||||
|
|
||||||
void StagingBuffer::InvalidateCPUCache(VkDeviceSize offset, VkDeviceSize size)
|
void StagingBuffer::InvalidateCPUCache(VkDeviceSize offset, VkDeviceSize size)
|
||||||
{
|
{
|
||||||
ASSERT(offset >= m_map_offset);
|
// vmaInvalidateAllocation checks whether the allocation uses a coherent memory type internally
|
||||||
if (m_coherent)
|
vmaInvalidateAllocation(g_vulkan_context->GetMemoryAllocator(), m_alloc, offset, size);
|
||||||
return;
|
|
||||||
|
|
||||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr, m_memory,
|
|
||||||
offset - m_map_offset, size};
|
|
||||||
vkInvalidateMappedMemoryRanges(g_vulkan_context->GetDevice(), 1, &range);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StagingBuffer::Read(VkDeviceSize offset, void* data, size_t size, bool invalidate_caches)
|
void StagingBuffer::Read(VkDeviceSize offset, void* data, size_t size, bool invalidate_caches)
|
||||||
{
|
{
|
||||||
ASSERT((offset + size) <= m_size);
|
ASSERT((offset + size) <= m_size);
|
||||||
ASSERT(offset >= m_map_offset && size <= (m_map_size + (offset - m_map_offset)));
|
|
||||||
if (invalidate_caches)
|
if (invalidate_caches)
|
||||||
InvalidateCPUCache(offset, size);
|
InvalidateCPUCache(offset, size);
|
||||||
|
|
||||||
memcpy(data, m_map_pointer + (offset - m_map_offset), size);
|
memcpy(data, m_map_pointer + offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StagingBuffer::Write(VkDeviceSize offset, const void* data, size_t size,
|
void StagingBuffer::Write(VkDeviceSize offset, const void* data, size_t size,
|
||||||
bool invalidate_caches)
|
bool invalidate_caches)
|
||||||
{
|
{
|
||||||
ASSERT((offset + size) <= m_size);
|
ASSERT((offset + size) <= m_size);
|
||||||
ASSERT(offset >= m_map_offset && size <= (m_map_size + (offset - m_map_offset)));
|
|
||||||
|
|
||||||
memcpy(m_map_pointer + (offset - m_map_offset), data, size);
|
memcpy(m_map_pointer + offset, data, size);
|
||||||
if (invalidate_caches)
|
if (invalidate_caches)
|
||||||
FlushCPUCache(offset, size);
|
FlushCPUCache(offset, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StagingBuffer::AllocateBuffer(STAGING_BUFFER_TYPE type, VkDeviceSize size,
|
bool StagingBuffer::AllocateBuffer(STAGING_BUFFER_TYPE type, VkDeviceSize size,
|
||||||
VkBufferUsageFlags usage, VkBuffer* out_buffer,
|
VkBufferUsageFlags usage, VkBuffer* out_buffer,
|
||||||
VkDeviceMemory* out_memory, bool* out_coherent)
|
VmaAllocation* out_alloc, char** out_map_ptr)
|
||||||
{
|
{
|
||||||
VkBufferCreateInfo buffer_create_info = {
|
VkBufferCreateInfo buffer_create_info = {
|
||||||
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType
|
||||||
|
@ -180,46 +151,60 @@ bool StagingBuffer::AllocateBuffer(STAGING_BUFFER_TYPE type, VkDeviceSize size,
|
||||||
0, // uint32_t queueFamilyIndexCount
|
0, // uint32_t queueFamilyIndexCount
|
||||||
nullptr // const uint32_t* pQueueFamilyIndices
|
nullptr // const uint32_t* pQueueFamilyIndices
|
||||||
};
|
};
|
||||||
VkResult res =
|
|
||||||
vkCreateBuffer(g_vulkan_context->GetDevice(), &buffer_create_info, nullptr, out_buffer);
|
VmaAllocationCreateInfo alloc_create_info = {};
|
||||||
if (res != VK_SUCCESS)
|
alloc_create_info.flags =
|
||||||
|
VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||||
|
alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO;
|
||||||
|
alloc_create_info.pool = VK_NULL_HANDLE;
|
||||||
|
alloc_create_info.pUserData = nullptr;
|
||||||
|
alloc_create_info.priority = 0.0;
|
||||||
|
alloc_create_info.preferredFlags = 0;
|
||||||
|
alloc_create_info.requiredFlags = 0;
|
||||||
|
|
||||||
|
if (DriverDetails::HasBug(DriverDetails::BUG_SLOW_CACHED_READBACK_MEMORY)) [[unlikely]]
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: ");
|
// If there is no memory type that is both CACHED and COHERENT,
|
||||||
return false;
|
// pick the one that is COHERENT
|
||||||
|
alloc_create_info.usage = VMA_MEMORY_USAGE_UNKNOWN;
|
||||||
|
alloc_create_info.requiredFlags =
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||||
|
alloc_create_info.preferredFlags = VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkMemoryRequirements requirements;
|
|
||||||
vkGetBufferMemoryRequirements(g_vulkan_context->GetDevice(), *out_buffer, &requirements);
|
|
||||||
|
|
||||||
u32 type_index;
|
|
||||||
if (type == STAGING_BUFFER_TYPE_UPLOAD)
|
|
||||||
type_index = g_vulkan_context->GetUploadMemoryType(requirements.memoryTypeBits, out_coherent);
|
|
||||||
else
|
else
|
||||||
type_index = g_vulkan_context->GetReadbackMemoryType(requirements.memoryTypeBits, out_coherent);
|
{
|
||||||
|
if (type == STAGING_BUFFER_TYPE_UPLOAD)
|
||||||
|
alloc_create_info.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT;
|
||||||
|
else
|
||||||
|
alloc_create_info.flags |= VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
VmaAllocationInfo alloc_info;
|
||||||
|
VkResult res = vmaCreateBuffer(g_vulkan_context->GetMemoryAllocator(), &buffer_create_info,
|
||||||
|
&alloc_create_info, out_buffer, out_alloc, &alloc_info);
|
||||||
|
|
||||||
|
if (type == STAGING_BUFFER_TYPE_UPLOAD)
|
||||||
|
{
|
||||||
|
VkMemoryPropertyFlags flags = 0;
|
||||||
|
vmaGetMemoryTypeProperties(g_vulkan_context->GetMemoryAllocator(), alloc_info.memoryType,
|
||||||
|
&flags);
|
||||||
|
if (!(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
|
||||||
|
{
|
||||||
|
WARN_LOG_FMT(VIDEO, "Vulkan: Failed to find a coherent memory type for uploads, this will "
|
||||||
|
"affect performance.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_map_ptr = reinterpret_cast<char*>(alloc_info.pMappedData);
|
||||||
|
|
||||||
VkMemoryAllocateInfo memory_allocate_info = {
|
|
||||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
requirements.size, // VkDeviceSize allocationSize
|
|
||||||
type_index // uint32_t memoryTypeIndex
|
|
||||||
};
|
|
||||||
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, out_memory);
|
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
LOG_VULKAN_ERROR(res, "vmaCreateBuffer failed: ");
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), *out_buffer, nullptr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = vkBindBufferMemory(g_vulkan_context->GetDevice(), *out_buffer, *out_memory, 0);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkBindBufferMemory failed: ");
|
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), *out_buffer, nullptr);
|
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), *out_memory, nullptr);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkMemoryPropertyFlags flags = 0;
|
||||||
|
vmaGetAllocationMemoryProperties(g_vulkan_context->GetMemoryAllocator(), *out_alloc, &flags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,12 +212,12 @@ std::unique_ptr<StagingBuffer> StagingBuffer::Create(STAGING_BUFFER_TYPE type, V
|
||||||
VkBufferUsageFlags usage)
|
VkBufferUsageFlags usage)
|
||||||
{
|
{
|
||||||
VkBuffer buffer;
|
VkBuffer buffer;
|
||||||
VkDeviceMemory memory;
|
VmaAllocation alloc;
|
||||||
bool coherent;
|
char* map_ptr;
|
||||||
if (!AllocateBuffer(type, size, usage, &buffer, &memory, &coherent))
|
if (!AllocateBuffer(type, size, usage, &buffer, &alloc, &map_ptr))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return std::make_unique<StagingBuffer>(type, buffer, memory, size, coherent);
|
return std::make_unique<StagingBuffer>(type, buffer, alloc, size, map_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -13,8 +13,8 @@ namespace Vulkan
|
||||||
class StagingBuffer
|
class StagingBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
StagingBuffer(STAGING_BUFFER_TYPE type, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize size,
|
StagingBuffer(STAGING_BUFFER_TYPE type, VkBuffer buffer, VmaAllocation allocation,
|
||||||
bool coherent);
|
VkDeviceSize size, char* map_ptr);
|
||||||
virtual ~StagingBuffer();
|
virtual ~StagingBuffer();
|
||||||
|
|
||||||
STAGING_BUFFER_TYPE GetType() const { return m_type; }
|
STAGING_BUFFER_TYPE GetType() const { return m_type; }
|
||||||
|
@ -23,9 +23,7 @@ public:
|
||||||
bool IsMapped() const { return m_map_pointer != nullptr; }
|
bool IsMapped() const { return m_map_pointer != nullptr; }
|
||||||
const char* GetMapPointer() const { return m_map_pointer; }
|
const char* GetMapPointer() const { return m_map_pointer; }
|
||||||
char* GetMapPointer() { return m_map_pointer; }
|
char* GetMapPointer() { return m_map_pointer; }
|
||||||
VkDeviceSize GetMapOffset() const { return m_map_offset; }
|
bool Map();
|
||||||
VkDeviceSize GetMapSize() const { return m_map_size; }
|
|
||||||
bool Map(VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE);
|
|
||||||
void Unmap();
|
void Unmap();
|
||||||
|
|
||||||
// Upload part 1: Prepare from device read from the CPU side
|
// Upload part 1: Prepare from device read from the CPU side
|
||||||
|
@ -60,7 +58,7 @@ public:
|
||||||
|
|
||||||
// Allocates the resources needed to create a staging buffer.
|
// Allocates the resources needed to create a staging buffer.
|
||||||
static bool AllocateBuffer(STAGING_BUFFER_TYPE type, VkDeviceSize size, VkBufferUsageFlags usage,
|
static bool AllocateBuffer(STAGING_BUFFER_TYPE type, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
VkBuffer* out_buffer, VkDeviceMemory* out_memory, bool* out_coherent);
|
VkBuffer* out_buffer, VmaAllocation* out_alloc, char** out_map_ptr);
|
||||||
|
|
||||||
// Wrapper for creating an barrier on a buffer
|
// Wrapper for creating an barrier on a buffer
|
||||||
static void BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer buffer,
|
static void BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer buffer,
|
||||||
|
@ -72,12 +70,9 @@ public:
|
||||||
protected:
|
protected:
|
||||||
STAGING_BUFFER_TYPE m_type;
|
STAGING_BUFFER_TYPE m_type;
|
||||||
VkBuffer m_buffer;
|
VkBuffer m_buffer;
|
||||||
VkDeviceMemory m_memory;
|
VmaAllocation m_alloc;
|
||||||
VkDeviceSize m_size;
|
VkDeviceSize m_size;
|
||||||
bool m_coherent;
|
|
||||||
|
|
||||||
char* m_map_pointer = nullptr;
|
char* m_map_pointer = nullptr;
|
||||||
VkDeviceSize m_map_offset = 0;
|
|
||||||
VkDeviceSize m_map_size = 0;
|
|
||||||
};
|
};
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -20,8 +20,7 @@ VKBoundingBox::~VKBoundingBox()
|
||||||
{
|
{
|
||||||
if (m_gpu_buffer != VK_NULL_HANDLE)
|
if (m_gpu_buffer != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), m_gpu_buffer, nullptr);
|
vmaDestroyBuffer(g_vulkan_context->GetMemoryAllocator(), m_gpu_buffer, m_gpu_allocation);
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), m_gpu_memory, nullptr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,47 +117,27 @@ bool VKBoundingBox::CreateGPUBuffer()
|
||||||
nullptr // const uint32_t* pQueueFamilyIndices
|
nullptr // const uint32_t* pQueueFamilyIndices
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VmaAllocationCreateInfo alloc_create_info = {};
|
||||||
|
alloc_create_info.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||||
|
alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||||
|
alloc_create_info.pool = VK_NULL_HANDLE;
|
||||||
|
alloc_create_info.pUserData = nullptr;
|
||||||
|
alloc_create_info.priority = 0.0;
|
||||||
|
alloc_create_info.requiredFlags = 0;
|
||||||
|
alloc_create_info.preferredFlags = 0;
|
||||||
|
|
||||||
VkBuffer buffer;
|
VkBuffer buffer;
|
||||||
VkResult res = vkCreateBuffer(g_vulkan_context->GetDevice(), &info, nullptr, &buffer);
|
VmaAllocation alloc;
|
||||||
|
VkResult res = vmaCreateBuffer(g_vulkan_context->GetMemoryAllocator(), &info, &alloc_create_info,
|
||||||
|
&buffer, &alloc, nullptr);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: ");
|
LOG_VULKAN_ERROR(res, "vmaCreateBuffer failed: ");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkMemoryRequirements memory_requirements;
|
|
||||||
vkGetBufferMemoryRequirements(g_vulkan_context->GetDevice(), buffer, &memory_requirements);
|
|
||||||
|
|
||||||
uint32_t memory_type_index = g_vulkan_context
|
|
||||||
->GetMemoryType(memory_requirements.memoryTypeBits,
|
|
||||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, false)
|
|
||||||
.value_or(0);
|
|
||||||
VkMemoryAllocateInfo memory_allocate_info = {
|
|
||||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
memory_requirements.size, // VkDeviceSize allocationSize
|
|
||||||
memory_type_index // uint32_t memoryTypeIndex
|
|
||||||
};
|
|
||||||
VkDeviceMemory memory;
|
|
||||||
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, &memory);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = vkBindBufferMemory(g_vulkan_context->GetDevice(), buffer, memory, 0);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkBindBufferMemory failed: ");
|
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), memory, nullptr);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_gpu_buffer = buffer;
|
m_gpu_buffer = buffer;
|
||||||
m_gpu_memory = memory;
|
m_gpu_allocation = alloc;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ private:
|
||||||
bool CreateReadbackBuffer();
|
bool CreateReadbackBuffer();
|
||||||
|
|
||||||
VkBuffer m_gpu_buffer = VK_NULL_HANDLE;
|
VkBuffer m_gpu_buffer = VK_NULL_HANDLE;
|
||||||
VkDeviceMemory m_gpu_memory = VK_NULL_HANDLE;
|
VmaAllocation m_gpu_allocation = VK_NULL_HANDLE;
|
||||||
|
|
||||||
static constexpr size_t BUFFER_SIZE = sizeof(BBoxType) * NUM_BBOX_VALUES;
|
static constexpr size_t BUFFER_SIZE = sizeof(BBoxType) * NUM_BBOX_VALUES;
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,9 @@ void VideoBackend::InitBackendInfo()
|
||||||
|
|
||||||
if (LoadVulkanLibrary())
|
if (LoadVulkanLibrary())
|
||||||
{
|
{
|
||||||
VkInstance temp_instance =
|
u32 vk_api_version = 0;
|
||||||
VulkanContext::CreateVulkanInstance(WindowSystemType::Headless, false, false);
|
VkInstance temp_instance = VulkanContext::CreateVulkanInstance(WindowSystemType::Headless,
|
||||||
|
false, false, &vk_api_version);
|
||||||
if (temp_instance)
|
if (temp_instance)
|
||||||
{
|
{
|
||||||
if (LoadVulkanInstanceFunctions(temp_instance))
|
if (LoadVulkanInstanceFunctions(temp_instance))
|
||||||
|
@ -114,8 +115,9 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
||||||
// We use this instance to fill in backend info, then re-use it for the actual device.
|
// We use this instance to fill in backend info, then re-use it for the actual device.
|
||||||
bool enable_surface = wsi.type != WindowSystemType::Headless;
|
bool enable_surface = wsi.type != WindowSystemType::Headless;
|
||||||
bool enable_debug_reports = ShouldEnableDebugReports(enable_validation_layer);
|
bool enable_debug_reports = ShouldEnableDebugReports(enable_validation_layer);
|
||||||
VkInstance instance =
|
u32 vk_api_version = 0;
|
||||||
VulkanContext::CreateVulkanInstance(wsi.type, enable_debug_reports, enable_validation_layer);
|
VkInstance instance = VulkanContext::CreateVulkanInstance(
|
||||||
|
wsi.type, enable_debug_reports, enable_validation_layer, &vk_api_version);
|
||||||
if (instance == VK_NULL_HANDLE)
|
if (instance == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
PanicAlertFmt("Failed to create Vulkan instance.");
|
PanicAlertFmt("Failed to create Vulkan instance.");
|
||||||
|
@ -171,8 +173,9 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we can create the Vulkan device. VulkanContext takes ownership of the instance and surface.
|
// Now we can create the Vulkan device. VulkanContext takes ownership of the instance and surface.
|
||||||
g_vulkan_context = VulkanContext::Create(instance, gpu_list[selected_adapter_index], surface,
|
g_vulkan_context =
|
||||||
enable_debug_reports, enable_validation_layer);
|
VulkanContext::Create(instance, gpu_list[selected_adapter_index], surface,
|
||||||
|
enable_debug_reports, enable_validation_layer, vk_api_version);
|
||||||
if (!g_vulkan_context)
|
if (!g_vulkan_context)
|
||||||
{
|
{
|
||||||
PanicAlertFmt("Failed to create Vulkan device");
|
PanicAlertFmt("Failed to create Vulkan device");
|
||||||
|
|
|
@ -22,13 +22,9 @@ StreamBuffer::StreamBuffer(VkBufferUsageFlags usage, u32 size) : m_usage(usage),
|
||||||
|
|
||||||
StreamBuffer::~StreamBuffer()
|
StreamBuffer::~StreamBuffer()
|
||||||
{
|
{
|
||||||
if (m_host_pointer)
|
// VMA_ALLOCATION_CREATE_MAPPED_BIT automatically handles unmapping for us
|
||||||
vkUnmapMemory(g_vulkan_context->GetDevice(), m_memory);
|
|
||||||
|
|
||||||
if (m_buffer != VK_NULL_HANDLE)
|
if (m_buffer != VK_NULL_HANDLE)
|
||||||
g_command_buffer_mgr->DeferBufferDestruction(m_buffer);
|
g_command_buffer_mgr->DeferBufferDestruction(m_buffer, m_alloc);
|
||||||
if (m_memory != VK_NULL_HANDLE)
|
|
||||||
g_command_buffer_mgr->DeferDeviceMemoryDestruction(m_memory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<StreamBuffer> StreamBuffer::Create(VkBufferUsageFlags usage, u32 size)
|
std::unique_ptr<StreamBuffer> StreamBuffer::Create(VkBufferUsageFlags usage, u32 size)
|
||||||
|
@ -54,74 +50,38 @@ bool StreamBuffer::AllocateBuffer()
|
||||||
nullptr // const uint32_t* pQueueFamilyIndices
|
nullptr // const uint32_t* pQueueFamilyIndices
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VmaAllocationCreateInfo alloc_create_info = {};
|
||||||
|
alloc_create_info.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
||||||
|
VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT |
|
||||||
|
VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
||||||
|
alloc_create_info.usage =
|
||||||
|
VMA_MEMORY_USAGE_AUTO_PREFER_HOST; // Host visible VRAM is slower in practice
|
||||||
|
alloc_create_info.pool = VK_NULL_HANDLE;
|
||||||
|
alloc_create_info.pUserData = nullptr;
|
||||||
|
alloc_create_info.priority = 0.0;
|
||||||
|
alloc_create_info.requiredFlags = 0;
|
||||||
|
alloc_create_info.preferredFlags = 0;
|
||||||
|
|
||||||
VkBuffer buffer = VK_NULL_HANDLE;
|
VkBuffer buffer = VK_NULL_HANDLE;
|
||||||
VkResult res =
|
VmaAllocation alloc = VK_NULL_HANDLE;
|
||||||
vkCreateBuffer(g_vulkan_context->GetDevice(), &buffer_create_info, nullptr, &buffer);
|
VmaAllocationInfo alloc_info;
|
||||||
|
VkResult res = vmaCreateBuffer(g_vulkan_context->GetMemoryAllocator(), &buffer_create_info,
|
||||||
|
&alloc_create_info, &buffer, &alloc, &alloc_info);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: ");
|
LOG_VULKAN_ERROR(res, "vmaCreateBuffer failed: ");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get memory requirements (types etc) for this buffer
|
|
||||||
VkMemoryRequirements memory_requirements;
|
|
||||||
vkGetBufferMemoryRequirements(g_vulkan_context->GetDevice(), buffer, &memory_requirements);
|
|
||||||
|
|
||||||
// Aim for a coherent mapping if possible.
|
|
||||||
u32 memory_type_index = g_vulkan_context->GetUploadMemoryType(memory_requirements.memoryTypeBits,
|
|
||||||
&m_coherent_mapping);
|
|
||||||
|
|
||||||
// Allocate memory for backing this buffer
|
|
||||||
VkMemoryAllocateInfo memory_allocate_info = {
|
|
||||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType
|
|
||||||
nullptr, // const void* pNext
|
|
||||||
memory_requirements.size, // VkDeviceSize allocationSize
|
|
||||||
memory_type_index // uint32_t memoryTypeIndex
|
|
||||||
};
|
|
||||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
|
||||||
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_allocate_info, nullptr, &memory);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind memory to buffer
|
|
||||||
res = vkBindBufferMemory(g_vulkan_context->GetDevice(), buffer, memory, 0);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkBindBufferMemory failed: ");
|
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), memory, nullptr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map this buffer into user-space
|
|
||||||
void* mapped_ptr = nullptr;
|
|
||||||
res = vkMapMemory(g_vulkan_context->GetDevice(), memory, 0, m_size, 0, &mapped_ptr);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkMapMemory failed: ");
|
|
||||||
vkDestroyBuffer(g_vulkan_context->GetDevice(), buffer, nullptr);
|
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), memory, nullptr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmap current host pointer (if there was a previous buffer)
|
|
||||||
if (m_host_pointer)
|
|
||||||
vkUnmapMemory(g_vulkan_context->GetDevice(), m_memory);
|
|
||||||
|
|
||||||
// Destroy the backings for the buffer after the command buffer executes
|
// Destroy the backings for the buffer after the command buffer executes
|
||||||
|
// VMA_ALLOCATION_CREATE_MAPPED_BIT automatically handles unmapping for us
|
||||||
if (m_buffer != VK_NULL_HANDLE)
|
if (m_buffer != VK_NULL_HANDLE)
|
||||||
g_command_buffer_mgr->DeferBufferDestruction(m_buffer);
|
g_command_buffer_mgr->DeferBufferDestruction(m_buffer, m_alloc);
|
||||||
if (m_memory != VK_NULL_HANDLE)
|
|
||||||
g_command_buffer_mgr->DeferDeviceMemoryDestruction(m_memory);
|
|
||||||
|
|
||||||
// Replace with the new buffer
|
// Replace with the new buffer
|
||||||
m_buffer = buffer;
|
m_buffer = buffer;
|
||||||
m_memory = memory;
|
m_alloc = alloc;
|
||||||
m_host_pointer = reinterpret_cast<u8*>(mapped_ptr);
|
m_host_pointer = reinterpret_cast<u8*>(alloc_info.pMappedData);
|
||||||
m_current_offset = 0;
|
m_current_offset = 0;
|
||||||
m_current_gpu_position = 0;
|
m_current_gpu_position = 0;
|
||||||
m_tracked_fences.clear();
|
m_tracked_fences.clear();
|
||||||
|
@ -201,12 +161,9 @@ void StreamBuffer::CommitMemory(u32 final_num_bytes)
|
||||||
ASSERT(final_num_bytes <= m_last_allocation_size);
|
ASSERT(final_num_bytes <= m_last_allocation_size);
|
||||||
|
|
||||||
// For non-coherent mappings, flush the memory range
|
// For non-coherent mappings, flush the memory range
|
||||||
if (!m_coherent_mapping)
|
// vmaFlushAllocation checks whether the allocation uses a coherent memory type internally
|
||||||
{
|
vmaFlushAllocation(g_vulkan_context->GetMemoryAllocator(), m_alloc, m_current_offset,
|
||||||
VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, nullptr, m_memory,
|
final_num_bytes);
|
||||||
m_current_offset, final_num_bytes};
|
|
||||||
vkFlushMappedMemoryRanges(g_vulkan_context->GetDevice(), 1, &range);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_current_offset += final_num_bytes;
|
m_current_offset += final_num_bytes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ public:
|
||||||
~StreamBuffer();
|
~StreamBuffer();
|
||||||
|
|
||||||
VkBuffer GetBuffer() const { return m_buffer; }
|
VkBuffer GetBuffer() const { return m_buffer; }
|
||||||
VkDeviceMemory GetDeviceMemory() const { return m_memory; }
|
|
||||||
u8* GetHostPointer() const { return m_host_pointer; }
|
u8* GetHostPointer() const { return m_host_pointer; }
|
||||||
u8* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; }
|
u8* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; }
|
||||||
u32 GetCurrentSize() const { return m_size; }
|
u32 GetCurrentSize() const { return m_size; }
|
||||||
|
@ -45,13 +44,11 @@ private:
|
||||||
u32 m_last_allocation_size = 0;
|
u32 m_last_allocation_size = 0;
|
||||||
|
|
||||||
VkBuffer m_buffer = VK_NULL_HANDLE;
|
VkBuffer m_buffer = VK_NULL_HANDLE;
|
||||||
VkDeviceMemory m_memory = VK_NULL_HANDLE;
|
VmaAllocation m_alloc = VK_NULL_HANDLE;
|
||||||
u8* m_host_pointer = nullptr;
|
u8* m_host_pointer = nullptr;
|
||||||
|
|
||||||
// List of fences and the corresponding positions in the buffer
|
// List of fences and the corresponding positions in the buffer
|
||||||
std::deque<std::pair<u64, u32>> m_tracked_fences;
|
std::deque<std::pair<u64, u32>> m_tracked_fences;
|
||||||
|
|
||||||
bool m_coherent_mapping = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -26,10 +26,10 @@
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
{
|
{
|
||||||
VKTexture::VKTexture(const TextureConfig& tex_config, VkDeviceMemory device_memory, VkImage image,
|
VKTexture::VKTexture(const TextureConfig& tex_config, VmaAllocation alloc, VkImage image,
|
||||||
std::string_view name, VkImageLayout layout /* = VK_IMAGE_LAYOUT_UNDEFINED */,
|
std::string_view name, VkImageLayout layout /* = VK_IMAGE_LAYOUT_UNDEFINED */,
|
||||||
ComputeImageLayout compute_layout /* = ComputeImageLayout::Undefined */)
|
ComputeImageLayout compute_layout /* = ComputeImageLayout::Undefined */)
|
||||||
: AbstractTexture(tex_config), m_device_memory(device_memory), m_image(image), m_layout(layout),
|
: AbstractTexture(tex_config), m_alloc(alloc), m_image(image), m_layout(layout),
|
||||||
m_compute_layout(compute_layout), m_name(name)
|
m_compute_layout(compute_layout), m_name(name)
|
||||||
{
|
{
|
||||||
if (!m_name.empty() && g_ActiveConfig.backend_info.bSupportsSettingObjectNames)
|
if (!m_name.empty() && g_ActiveConfig.backend_info.bSupportsSettingObjectNames)
|
||||||
|
@ -49,10 +49,9 @@ VKTexture::~VKTexture()
|
||||||
g_command_buffer_mgr->DeferImageViewDestruction(m_view);
|
g_command_buffer_mgr->DeferImageViewDestruction(m_view);
|
||||||
|
|
||||||
// If we don't have device memory allocated, the image is not owned by us (e.g. swapchain)
|
// If we don't have device memory allocated, the image is not owned by us (e.g. swapchain)
|
||||||
if (m_device_memory != VK_NULL_HANDLE)
|
if (m_alloc != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
g_command_buffer_mgr->DeferImageDestruction(m_image);
|
g_command_buffer_mgr->DeferImageDestruction(m_image, m_alloc);
|
||||||
g_command_buffer_mgr->DeferDeviceMemoryDestruction(m_device_memory);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,46 +84,28 @@ std::unique_ptr<VKTexture> VKTexture::Create(const TextureConfig& tex_config, st
|
||||||
nullptr,
|
nullptr,
|
||||||
VK_IMAGE_LAYOUT_UNDEFINED};
|
VK_IMAGE_LAYOUT_UNDEFINED};
|
||||||
|
|
||||||
|
VmaAllocationCreateInfo alloc_create_info = {};
|
||||||
|
alloc_create_info.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||||
|
alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||||
|
alloc_create_info.pool = VK_NULL_HANDLE;
|
||||||
|
alloc_create_info.pUserData = nullptr;
|
||||||
|
alloc_create_info.priority =
|
||||||
|
tex_config.IsComputeImage() || tex_config.IsRenderTarget() ? 1.0 : 0.0;
|
||||||
|
alloc_create_info.requiredFlags = 0;
|
||||||
|
alloc_create_info.preferredFlags = 0;
|
||||||
|
|
||||||
VkImage image = VK_NULL_HANDLE;
|
VkImage image = VK_NULL_HANDLE;
|
||||||
VkResult res = vkCreateImage(g_vulkan_context->GetDevice(), &image_info, nullptr, &image);
|
VmaAllocation alloc = VK_NULL_HANDLE;
|
||||||
|
VkResult res = vmaCreateImage(g_vulkan_context->GetMemoryAllocator(), &image_info,
|
||||||
|
&alloc_create_info, &image, &alloc, nullptr);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateImage failed: ");
|
LOG_VULKAN_ERROR(res, "vmaCreateImage failed: ");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory to back this texture, we want device local memory in this case
|
std::unique_ptr<VKTexture> texture = std::make_unique<VKTexture>(
|
||||||
VkMemoryRequirements memory_requirements;
|
tex_config, alloc, image, name, VK_IMAGE_LAYOUT_UNDEFINED, ComputeImageLayout::Undefined);
|
||||||
vkGetImageMemoryRequirements(g_vulkan_context->GetDevice(), image, &memory_requirements);
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo memory_info = {
|
|
||||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, nullptr, memory_requirements.size,
|
|
||||||
g_vulkan_context
|
|
||||||
->GetMemoryType(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
||||||
false)
|
|
||||||
.value_or(0)};
|
|
||||||
|
|
||||||
VkDeviceMemory device_memory;
|
|
||||||
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_info, nullptr, &device_memory);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
|
||||||
vkDestroyImage(g_vulkan_context->GetDevice(), image, nullptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = vkBindImageMemory(g_vulkan_context->GetDevice(), image, device_memory, 0);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkBindImageMemory failed: ");
|
|
||||||
vkDestroyImage(g_vulkan_context->GetDevice(), image, nullptr);
|
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), device_memory, nullptr);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<VKTexture> texture =
|
|
||||||
std::make_unique<VKTexture>(tex_config, device_memory, image, name, VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
ComputeImageLayout::Undefined);
|
|
||||||
if (!texture->CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY))
|
if (!texture->CreateView(VK_IMAGE_VIEW_TYPE_2D_ARRAY))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -135,7 +116,7 @@ std::unique_ptr<VKTexture> VKTexture::CreateAdopted(const TextureConfig& tex_con
|
||||||
VkImageViewType view_type, VkImageLayout layout)
|
VkImageViewType view_type, VkImageLayout layout)
|
||||||
{
|
{
|
||||||
std::unique_ptr<VKTexture> texture = std::make_unique<VKTexture>(
|
std::unique_ptr<VKTexture> texture = std::make_unique<VKTexture>(
|
||||||
tex_config, VkDeviceMemory(VK_NULL_HANDLE), image, "", layout, ComputeImageLayout::Undefined);
|
tex_config, VmaAllocation(VK_NULL_HANDLE), image, "", layout, ComputeImageLayout::Undefined);
|
||||||
if (!texture->CreateView(view_type))
|
if (!texture->CreateView(view_type))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
@ -701,9 +682,9 @@ void VKTexture::TransitionToLayout(VkCommandBuffer command_buffer,
|
||||||
|
|
||||||
VKStagingTexture::VKStagingTexture(PrivateTag, StagingTextureType type, const TextureConfig& config,
|
VKStagingTexture::VKStagingTexture(PrivateTag, StagingTextureType type, const TextureConfig& config,
|
||||||
std::unique_ptr<StagingBuffer> buffer, VkImage linear_image,
|
std::unique_ptr<StagingBuffer> buffer, VkImage linear_image,
|
||||||
VkDeviceMemory linear_image_memory)
|
VmaAllocation linear_image_alloc)
|
||||||
: AbstractStagingTexture(type, config), m_staging_buffer(std::move(buffer)),
|
: AbstractStagingTexture(type, config), m_staging_buffer(std::move(buffer)),
|
||||||
m_linear_image(linear_image), m_linear_image_memory(linear_image_memory)
|
m_linear_image(linear_image), m_linear_image_alloc(linear_image_alloc)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,8 +692,7 @@ VKStagingTexture::~VKStagingTexture()
|
||||||
{
|
{
|
||||||
if (m_linear_image != VK_NULL_HANDLE)
|
if (m_linear_image != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
g_command_buffer_mgr->DeferImageDestruction(m_linear_image);
|
g_command_buffer_mgr->DeferImageDestruction(m_linear_image, m_linear_image_alloc);
|
||||||
g_command_buffer_mgr->DeferDeviceMemoryDestruction(m_linear_image_memory);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,28 +721,27 @@ std::unique_ptr<VKStagingTexture> VKStagingTexture::Create(StagingTextureType ty
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBuffer buffer;
|
VkBuffer buffer;
|
||||||
VkDeviceMemory memory;
|
VmaAllocation alloc;
|
||||||
bool coherent;
|
char* map_ptr;
|
||||||
if (!StagingBuffer::AllocateBuffer(buffer_type, buffer_size, buffer_usage, &buffer, &memory,
|
if (!StagingBuffer::AllocateBuffer(buffer_type, buffer_size, buffer_usage, &buffer, &alloc,
|
||||||
&coherent))
|
&map_ptr))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linear image
|
// Linear image
|
||||||
VkImage linear_image = VK_NULL_HANDLE;
|
VkImage linear_image = VK_NULL_HANDLE;
|
||||||
VkDeviceMemory linear_image_device_memory = VK_NULL_HANDLE;
|
VmaAllocation linear_image_alloc = VK_NULL_HANDLE;
|
||||||
if (DriverDetails::HasBug(DriverDetails::BUG_SLOW_OPTIMAL_IMAGE_TO_BUFFER_COPY) &&
|
if (DriverDetails::HasBug(DriverDetails::BUG_SLOW_OPTIMAL_IMAGE_TO_BUFFER_COPY) &&
|
||||||
type == StagingTextureType::Readback && config.samples == 1)
|
type == StagingTextureType::Readback && config.samples == 1)
|
||||||
{
|
{
|
||||||
std::tie(linear_image, linear_image_device_memory) = CreateLinearImage(type, config);
|
std::tie(linear_image, linear_image_alloc) = CreateLinearImage(type, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<StagingBuffer> staging_buffer =
|
std::unique_ptr<StagingBuffer> staging_buffer =
|
||||||
std::make_unique<StagingBuffer>(buffer_type, buffer, memory, buffer_size, coherent);
|
std::make_unique<StagingBuffer>(buffer_type, buffer, alloc, buffer_size, map_ptr);
|
||||||
std::unique_ptr<VKStagingTexture> staging_tex =
|
std::unique_ptr<VKStagingTexture> staging_tex = std::make_unique<VKStagingTexture>(
|
||||||
std::make_unique<VKStagingTexture>(PrivateTag{}, type, config, std::move(staging_buffer),
|
PrivateTag{}, type, config, std::move(staging_buffer), linear_image, linear_image_alloc);
|
||||||
linear_image, linear_image_device_memory);
|
|
||||||
|
|
||||||
// Use persistent mapping.
|
// Use persistent mapping.
|
||||||
if (!staging_tex->m_staging_buffer->Map())
|
if (!staging_tex->m_staging_buffer->Map())
|
||||||
|
@ -772,7 +751,7 @@ std::unique_ptr<VKStagingTexture> VKStagingTexture::Create(StagingTextureType ty
|
||||||
return staging_tex;
|
return staging_tex;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<VkImage, VkDeviceMemory> VKStagingTexture::CreateLinearImage(StagingTextureType type,
|
std::pair<VkImage, VmaAllocation> VKStagingTexture::CreateLinearImage(StagingTextureType type,
|
||||||
const TextureConfig& config)
|
const TextureConfig& config)
|
||||||
{
|
{
|
||||||
// Create a intermediate texture with linear tiling
|
// Create a intermediate texture with linear tiling
|
||||||
|
@ -802,43 +781,25 @@ std::pair<VkImage, VkDeviceMemory> VKStagingTexture::CreateLinearImage(StagingTe
|
||||||
return std::make_pair(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
return std::make_pair(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VmaAllocationCreateInfo alloc_create_info = {};
|
||||||
|
alloc_create_info.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
|
||||||
|
alloc_create_info.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
|
||||||
|
alloc_create_info.pool = VK_NULL_HANDLE;
|
||||||
|
alloc_create_info.pUserData = nullptr;
|
||||||
|
alloc_create_info.priority = 0.0;
|
||||||
|
alloc_create_info.requiredFlags = 0;
|
||||||
|
alloc_create_info.preferredFlags = 0;
|
||||||
|
|
||||||
VkImage image;
|
VkImage image;
|
||||||
res = vkCreateImage(g_vulkan_context->GetDevice(), &image_info, nullptr, &image);
|
VmaAllocation alloc;
|
||||||
|
res = vmaCreateImage(g_vulkan_context->GetMemoryAllocator(), &image_info, &alloc_create_info,
|
||||||
|
&image, &alloc, nullptr);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkCreateImage failed: ");
|
LOG_VULKAN_ERROR(res, "vmaCreateImage failed: ");
|
||||||
return std::make_pair(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
return std::make_pair(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
||||||
}
|
}
|
||||||
|
return std::make_pair(image, alloc);
|
||||||
// Allocate memory to back this texture, we want device local memory in this case
|
|
||||||
VkMemoryRequirements memory_requirements;
|
|
||||||
vkGetImageMemoryRequirements(g_vulkan_context->GetDevice(), image, &memory_requirements);
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo memory_info = {
|
|
||||||
VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, nullptr, memory_requirements.size,
|
|
||||||
g_vulkan_context
|
|
||||||
->GetMemoryType(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
||||||
false)
|
|
||||||
.value_or(0)};
|
|
||||||
|
|
||||||
VkDeviceMemory device_memory;
|
|
||||||
res = vkAllocateMemory(g_vulkan_context->GetDevice(), &memory_info, nullptr, &device_memory);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkAllocateMemory failed: ");
|
|
||||||
vkDestroyImage(g_vulkan_context->GetDevice(), image, nullptr);
|
|
||||||
return std::make_pair(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = vkBindImageMemory(g_vulkan_context->GetDevice(), image, device_memory, 0);
|
|
||||||
if (res != VK_SUCCESS)
|
|
||||||
{
|
|
||||||
LOG_VULKAN_ERROR(res, "vkBindImageMemory failed: ");
|
|
||||||
vkDestroyImage(g_vulkan_context->GetDevice(), image, nullptr);
|
|
||||||
vkFreeMemory(g_vulkan_context->GetDevice(), device_memory, nullptr);
|
|
||||||
return std::make_pair(VK_NULL_HANDLE, VK_NULL_HANDLE);
|
|
||||||
}
|
|
||||||
return std::make_pair(image, device_memory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKStagingTexture::CopyFromTexture(const AbstractTexture* src,
|
void VKStagingTexture::CopyFromTexture(const AbstractTexture* src,
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
VKTexture() = delete;
|
VKTexture() = delete;
|
||||||
VKTexture(const TextureConfig& tex_config, VkDeviceMemory device_memory, VkImage image,
|
VKTexture(const TextureConfig& tex_config, VmaAllocation alloc, VkImage image,
|
||||||
std::string_view name, VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED,
|
std::string_view name, VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
ComputeImageLayout compute_layout = ComputeImageLayout::Undefined);
|
ComputeImageLayout compute_layout = ComputeImageLayout::Undefined);
|
||||||
~VKTexture();
|
~VKTexture();
|
||||||
|
@ -51,11 +51,10 @@ public:
|
||||||
void FinishedRendering() override;
|
void FinishedRendering() override;
|
||||||
|
|
||||||
VkImage GetImage() const { return m_image; }
|
VkImage GetImage() const { return m_image; }
|
||||||
VkDeviceMemory GetDeviceMemory() const { return m_device_memory; }
|
|
||||||
VkImageView GetView() const { return m_view; }
|
VkImageView GetView() const { return m_view; }
|
||||||
VkImageLayout GetLayout() const { return m_layout; }
|
VkImageLayout GetLayout() const { return m_layout; }
|
||||||
VkFormat GetVkFormat() const { return GetVkFormatForHostTextureFormat(m_config.format); }
|
VkFormat GetVkFormat() const { return GetVkFormatForHostTextureFormat(m_config.format); }
|
||||||
bool IsAdopted() const { return m_device_memory != VkDeviceMemory(VK_NULL_HANDLE); }
|
bool IsAdopted() const { return m_alloc != VmaAllocation(VK_NULL_HANDLE); }
|
||||||
|
|
||||||
static std::unique_ptr<VKTexture> Create(const TextureConfig& tex_config, std::string_view name);
|
static std::unique_ptr<VKTexture> Create(const TextureConfig& tex_config, std::string_view name);
|
||||||
static std::unique_ptr<VKTexture>
|
static std::unique_ptr<VKTexture>
|
||||||
|
@ -74,7 +73,7 @@ public:
|
||||||
private:
|
private:
|
||||||
bool CreateView(VkImageViewType type);
|
bool CreateView(VkImageViewType type);
|
||||||
|
|
||||||
VkDeviceMemory m_device_memory;
|
VmaAllocation m_alloc;
|
||||||
VkImage m_image;
|
VkImage m_image;
|
||||||
VkImageView m_view = VK_NULL_HANDLE;
|
VkImageView m_view = VK_NULL_HANDLE;
|
||||||
mutable VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
mutable VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
@ -92,7 +91,7 @@ public:
|
||||||
VKStagingTexture() = delete;
|
VKStagingTexture() = delete;
|
||||||
VKStagingTexture(PrivateTag, StagingTextureType type, const TextureConfig& config,
|
VKStagingTexture(PrivateTag, StagingTextureType type, const TextureConfig& config,
|
||||||
std::unique_ptr<StagingBuffer> buffer, VkImage linear_image,
|
std::unique_ptr<StagingBuffer> buffer, VkImage linear_image,
|
||||||
VkDeviceMemory linear_image_memory);
|
VmaAllocation linear_image_alloc);
|
||||||
|
|
||||||
~VKStagingTexture();
|
~VKStagingTexture();
|
||||||
|
|
||||||
|
@ -110,7 +109,7 @@ public:
|
||||||
static std::unique_ptr<VKStagingTexture> Create(StagingTextureType type,
|
static std::unique_ptr<VKStagingTexture> Create(StagingTextureType type,
|
||||||
const TextureConfig& config);
|
const TextureConfig& config);
|
||||||
|
|
||||||
static std::pair<VkImage, VkDeviceMemory> CreateLinearImage(StagingTextureType type,
|
static std::pair<VkImage, VmaAllocation> CreateLinearImage(StagingTextureType type,
|
||||||
const TextureConfig& config);
|
const TextureConfig& config);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -120,7 +119,7 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<StagingBuffer> m_staging_buffer;
|
std::unique_ptr<StagingBuffer> m_staging_buffer;
|
||||||
VkImage m_linear_image = VK_NULL_HANDLE;
|
VkImage m_linear_image = VK_NULL_HANDLE;
|
||||||
VkDeviceMemory m_linear_image_memory = VK_NULL_HANDLE;
|
VmaAllocation m_linear_image_alloc = VK_NULL_HANDLE;
|
||||||
u64 m_flush_fence_counter = 0;
|
u64 m_flush_fence_counter = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ VulkanContext::VulkanContext(VkInstance instance, VkPhysicalDevice physical_devi
|
||||||
|
|
||||||
VulkanContext::~VulkanContext()
|
VulkanContext::~VulkanContext()
|
||||||
{
|
{
|
||||||
|
if (m_allocator != VK_NULL_HANDLE)
|
||||||
|
vmaDestroyAllocator(m_allocator);
|
||||||
if (m_device != VK_NULL_HANDLE)
|
if (m_device != VK_NULL_HANDLE)
|
||||||
vkDestroyDevice(m_device, nullptr);
|
vkDestroyDevice(m_device, nullptr);
|
||||||
|
|
||||||
|
@ -86,7 +88,8 @@ bool VulkanContext::CheckValidationLayerAvailablility()
|
||||||
}
|
}
|
||||||
|
|
||||||
VkInstance VulkanContext::CreateVulkanInstance(WindowSystemType wstype, bool enable_debug_report,
|
VkInstance VulkanContext::CreateVulkanInstance(WindowSystemType wstype, bool enable_debug_report,
|
||||||
bool enable_validation_layer)
|
bool enable_validation_layer,
|
||||||
|
u32* out_vk_api_version)
|
||||||
{
|
{
|
||||||
std::vector<const char*> enabled_extensions;
|
std::vector<const char*> enabled_extensions;
|
||||||
if (!SelectInstanceExtensions(&enabled_extensions, wstype, enable_debug_report))
|
if (!SelectInstanceExtensions(&enabled_extensions, wstype, enable_debug_report))
|
||||||
|
@ -114,6 +117,8 @@ VkInstance VulkanContext::CreateVulkanInstance(WindowSystemType wstype, bool ena
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*out_vk_api_version = app_info.apiVersion;
|
||||||
|
|
||||||
VkInstanceCreateInfo instance_create_info = {};
|
VkInstanceCreateInfo instance_create_info = {};
|
||||||
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||||
instance_create_info.pNext = nullptr;
|
instance_create_info.pNext = nullptr;
|
||||||
|
@ -429,10 +434,9 @@ void VulkanContext::PopulateBackendInfoMultisampleModes(
|
||||||
config->backend_info.AAModes.emplace_back(64);
|
config->backend_info.AAModes.emplace_back(64);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VulkanContext> VulkanContext::Create(VkInstance instance, VkPhysicalDevice gpu,
|
std::unique_ptr<VulkanContext>
|
||||||
VkSurfaceKHR surface,
|
VulkanContext::Create(VkInstance instance, VkPhysicalDevice gpu, VkSurfaceKHR surface,
|
||||||
bool enable_debug_reports,
|
bool enable_debug_reports, bool enable_validation_layer, u32 vk_api_version)
|
||||||
bool enable_validation_layer)
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<VulkanContext> context = std::make_unique<VulkanContext>(instance, gpu);
|
std::unique_ptr<VulkanContext> context = std::make_unique<VulkanContext>(instance, gpu);
|
||||||
|
|
||||||
|
@ -445,7 +449,8 @@ std::unique_ptr<VulkanContext> VulkanContext::Create(VkInstance instance, VkPhys
|
||||||
context->EnableDebugReports();
|
context->EnableDebugReports();
|
||||||
|
|
||||||
// Attempt to create the device.
|
// Attempt to create the device.
|
||||||
if (!context->CreateDevice(surface, enable_validation_layer))
|
if (!context->CreateDevice(surface, enable_validation_layer) ||
|
||||||
|
!context->CreateAllocator(vk_api_version))
|
||||||
{
|
{
|
||||||
// Since we are destroying the instance, we're also responsible for destroying the surface.
|
// Since we are destroying the instance, we're also responsible for destroying the surface.
|
||||||
if (surface != VK_NULL_HANDLE)
|
if (surface != VK_NULL_HANDLE)
|
||||||
|
@ -508,6 +513,9 @@ bool VulkanContext::SelectDeviceExtensions(bool enable_surface)
|
||||||
INFO_LOG_FMT(VIDEO, "Using VK_EXT_full_screen_exclusive for exclusive fullscreen.");
|
INFO_LOG_FMT(VIDEO, "Using VK_EXT_full_screen_exclusive for exclusive fullscreen.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
AddExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false);
|
||||||
|
AddExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,6 +703,34 @@ bool VulkanContext::CreateDevice(VkSurfaceKHR surface, bool enable_validation_la
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VulkanContext::CreateAllocator(u32 vk_api_version)
|
||||||
|
{
|
||||||
|
VmaAllocatorCreateInfo allocator_info = {};
|
||||||
|
allocator_info.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
|
||||||
|
allocator_info.physicalDevice = m_physical_device;
|
||||||
|
allocator_info.device = m_device;
|
||||||
|
allocator_info.preferredLargeHeapBlockSize = 64 << 20;
|
||||||
|
allocator_info.pAllocationCallbacks = nullptr;
|
||||||
|
allocator_info.pDeviceMemoryCallbacks = nullptr;
|
||||||
|
allocator_info.pHeapSizeLimit = nullptr;
|
||||||
|
allocator_info.pVulkanFunctions = nullptr;
|
||||||
|
allocator_info.instance = m_instance;
|
||||||
|
allocator_info.vulkanApiVersion = vk_api_version;
|
||||||
|
allocator_info.pTypeExternalMemoryHandleTypes = nullptr;
|
||||||
|
|
||||||
|
if (SupportsDeviceExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME))
|
||||||
|
allocator_info.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
|
||||||
|
|
||||||
|
VkResult res = vmaCreateAllocator(&allocator_info, &m_allocator);
|
||||||
|
if (res != VK_SUCCESS)
|
||||||
|
{
|
||||||
|
LOG_VULKAN_ERROR(res, "vmaCreateAllocator failed: ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags,
|
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugReportCallback(VkDebugReportFlagsEXT flags,
|
||||||
VkDebugReportObjectTypeEXT objectType,
|
VkDebugReportObjectTypeEXT objectType,
|
||||||
uint64_t object, size_t location,
|
uint64_t object, size_t location,
|
||||||
|
@ -756,109 +792,6 @@ void VulkanContext::DisableDebugReports()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u32> VulkanContext::GetMemoryType(u32 bits, VkMemoryPropertyFlags properties,
|
|
||||||
bool strict, bool* is_coherent)
|
|
||||||
{
|
|
||||||
static constexpr u32 ALL_MEMORY_PROPERTY_FLAGS = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
||||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
|
||||||
VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
|
|
||||||
|
|
||||||
const u32 mask = strict ? ALL_MEMORY_PROPERTY_FLAGS : properties;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < VK_MAX_MEMORY_TYPES; i++)
|
|
||||||
{
|
|
||||||
if ((bits & (1 << i)) != 0)
|
|
||||||
{
|
|
||||||
const VkMemoryPropertyFlags type_flags =
|
|
||||||
m_device_memory_properties.memoryTypes[i].propertyFlags;
|
|
||||||
const VkMemoryPropertyFlags supported = type_flags & mask;
|
|
||||||
if (supported == properties)
|
|
||||||
{
|
|
||||||
if (is_coherent)
|
|
||||||
*is_coherent = (type_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 VulkanContext::GetUploadMemoryType(u32 bits, bool* is_coherent)
|
|
||||||
{
|
|
||||||
static constexpr VkMemoryPropertyFlags COHERENT_FLAGS =
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
|
||||||
|
|
||||||
// Try for coherent memory. Some drivers (looking at you, Adreno) have the cached type before the
|
|
||||||
// uncached type, so use a strict check first.
|
|
||||||
std::optional<u32> type_index = GetMemoryType(bits, COHERENT_FLAGS, true, is_coherent);
|
|
||||||
if (type_index)
|
|
||||||
return type_index.value();
|
|
||||||
|
|
||||||
// Try for coherent memory, with any other bits set.
|
|
||||||
type_index = GetMemoryType(bits, COHERENT_FLAGS, false, is_coherent);
|
|
||||||
if (type_index)
|
|
||||||
{
|
|
||||||
WARN_LOG_FMT(VIDEO,
|
|
||||||
"Strict check for upload memory properties failed, this may affect performance");
|
|
||||||
return type_index.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall back to non-coherent memory.
|
|
||||||
WARN_LOG_FMT(
|
|
||||||
VIDEO,
|
|
||||||
"Vulkan: Failed to find a coherent memory type for uploads, this will affect performance.");
|
|
||||||
type_index = GetMemoryType(bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, false, is_coherent);
|
|
||||||
if (type_index)
|
|
||||||
return type_index.value();
|
|
||||||
|
|
||||||
// Shouldn't happen, there should be at least one host-visible heap.
|
|
||||||
PanicAlertFmt("Unable to get memory type for upload.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 VulkanContext::GetReadbackMemoryType(u32 bits, bool* is_coherent)
|
|
||||||
{
|
|
||||||
std::optional<u32> type_index;
|
|
||||||
|
|
||||||
// Mali driver appears to be significantly slower for readbacks when using cached memory.
|
|
||||||
if (DriverDetails::HasBug(DriverDetails::BUG_SLOW_CACHED_READBACK_MEMORY))
|
|
||||||
{
|
|
||||||
type_index = GetMemoryType(
|
|
||||||
bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, true,
|
|
||||||
is_coherent);
|
|
||||||
if (type_index)
|
|
||||||
return type_index.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimal config uses cached+coherent.
|
|
||||||
type_index =
|
|
||||||
GetMemoryType(bits,
|
|
||||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT |
|
|
||||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
|
||||||
true, is_coherent);
|
|
||||||
if (type_index)
|
|
||||||
return type_index.value();
|
|
||||||
|
|
||||||
// Otherwise, prefer cached over coherent if we must choose one.
|
|
||||||
type_index =
|
|
||||||
GetMemoryType(bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
|
||||||
false, is_coherent);
|
|
||||||
if (type_index)
|
|
||||||
return type_index.value();
|
|
||||||
|
|
||||||
WARN_LOG_FMT(VIDEO, "Vulkan: Failed to find a cached memory type for readbacks, this will affect "
|
|
||||||
"performance.");
|
|
||||||
type_index = GetMemoryType(bits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, false, is_coherent);
|
|
||||||
*is_coherent = false;
|
|
||||||
if (type_index)
|
|
||||||
return type_index.value();
|
|
||||||
|
|
||||||
// We should have at least one host visible memory type...
|
|
||||||
PanicAlertFmt("Unable to get memory type for upload.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool VulkanContext::SupportsDeviceExtension(const char* name) const
|
bool VulkanContext::SupportsDeviceExtension(const char* name) const
|
||||||
{
|
{
|
||||||
return std::any_of(m_device_extensions.begin(), m_device_extensions.end(),
|
return std::any_of(m_device_extensions.begin(), m_device_extensions.end(),
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
|
|
||||||
// Helper method to create a Vulkan instance.
|
// Helper method to create a Vulkan instance.
|
||||||
static VkInstance CreateVulkanInstance(WindowSystemType wstype, bool enable_debug_report,
|
static VkInstance CreateVulkanInstance(WindowSystemType wstype, bool enable_debug_report,
|
||||||
bool enable_validation_layer);
|
bool enable_validation_layer, u32* out_vk_api_version);
|
||||||
|
|
||||||
// Returns a list of Vulkan-compatible GPUs.
|
// Returns a list of Vulkan-compatible GPUs.
|
||||||
using GPUList = std::vector<VkPhysicalDevice>;
|
using GPUList = std::vector<VkPhysicalDevice>;
|
||||||
|
@ -47,7 +47,7 @@ public:
|
||||||
// been called for the specified VideoConfig.
|
// been called for the specified VideoConfig.
|
||||||
static std::unique_ptr<VulkanContext> Create(VkInstance instance, VkPhysicalDevice gpu,
|
static std::unique_ptr<VulkanContext> Create(VkInstance instance, VkPhysicalDevice gpu,
|
||||||
VkSurfaceKHR surface, bool enable_debug_reports,
|
VkSurfaceKHR surface, bool enable_debug_reports,
|
||||||
bool enable_validation_layer);
|
bool enable_validation_layer, u32 api_version);
|
||||||
|
|
||||||
// Enable/disable debug message runtime.
|
// Enable/disable debug message runtime.
|
||||||
bool EnableDebugReports();
|
bool EnableDebugReports();
|
||||||
|
@ -98,14 +98,6 @@ public:
|
||||||
return m_device_properties.limits.bufferImageGranularity;
|
return m_device_properties.limits.bufferImageGranularity;
|
||||||
}
|
}
|
||||||
float GetMaxSamplerAnisotropy() const { return m_device_properties.limits.maxSamplerAnisotropy; }
|
float GetMaxSamplerAnisotropy() const { return m_device_properties.limits.maxSamplerAnisotropy; }
|
||||||
// Finds a memory type index for the specified memory properties and the bits returned by
|
|
||||||
// vkGetImageMemoryRequirements
|
|
||||||
std::optional<u32> GetMemoryType(u32 bits, VkMemoryPropertyFlags properties, bool strict,
|
|
||||||
bool* is_coherent = nullptr);
|
|
||||||
|
|
||||||
// Finds a memory type for upload or readback buffers.
|
|
||||||
u32 GetUploadMemoryType(u32 bits, bool* is_coherent = nullptr);
|
|
||||||
u32 GetReadbackMemoryType(u32 bits, bool* is_coherent = nullptr);
|
|
||||||
|
|
||||||
// Returns true if the specified extension is supported and enabled.
|
// Returns true if the specified extension is supported and enabled.
|
||||||
bool SupportsDeviceExtension(const char* name) const;
|
bool SupportsDeviceExtension(const char* name) const;
|
||||||
|
@ -113,6 +105,8 @@ public:
|
||||||
// Returns true if exclusive fullscreen is supported for the given surface.
|
// Returns true if exclusive fullscreen is supported for the given surface.
|
||||||
bool SupportsExclusiveFullscreen(const WindowSystemInfo& wsi, VkSurfaceKHR surface);
|
bool SupportsExclusiveFullscreen(const WindowSystemInfo& wsi, VkSurfaceKHR surface);
|
||||||
|
|
||||||
|
VmaAllocator GetMemoryAllocator() const { return m_allocator; }
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
// Returns the platform-specific exclusive fullscreen structure.
|
// Returns the platform-specific exclusive fullscreen structure.
|
||||||
VkSurfaceFullScreenExclusiveWin32InfoEXT
|
VkSurfaceFullScreenExclusiveWin32InfoEXT
|
||||||
|
@ -127,10 +121,12 @@ private:
|
||||||
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer);
|
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer);
|
||||||
void InitDriverDetails();
|
void InitDriverDetails();
|
||||||
void PopulateShaderSubgroupSupport();
|
void PopulateShaderSubgroupSupport();
|
||||||
|
bool CreateAllocator(u32 vk_api_version);
|
||||||
|
|
||||||
VkInstance m_instance = VK_NULL_HANDLE;
|
VkInstance m_instance = VK_NULL_HANDLE;
|
||||||
VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;
|
VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;
|
||||||
VkDevice m_device = VK_NULL_HANDLE;
|
VkDevice m_device = VK_NULL_HANDLE;
|
||||||
|
VmaAllocator m_allocator = VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkQueue m_graphics_queue = VK_NULL_HANDLE;
|
VkQueue m_graphics_queue = VK_NULL_HANDLE;
|
||||||
u32 m_graphics_queue_family_index = 0;
|
u32 m_graphics_queue_family_index = 0;
|
||||||
|
|
|
@ -37,6 +37,7 @@ VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceSupportKHR, false)
|
||||||
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, false)
|
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, false)
|
||||||
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceFormatsKHR, false)
|
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfaceFormatsKHR, false)
|
||||||
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfacePresentModesKHR, false)
|
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceSurfacePresentModesKHR, false)
|
||||||
|
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceMemoryProperties2, false)
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
VULKAN_INSTANCE_ENTRY_POINT(vkCreateWin32SurfaceKHR, false)
|
VULKAN_INSTANCE_ENTRY_POINT(vkCreateWin32SurfaceKHR, false)
|
||||||
|
@ -192,6 +193,10 @@ VULKAN_DEVICE_ENTRY_POINT(vkDestroySwapchainKHR, false)
|
||||||
VULKAN_DEVICE_ENTRY_POINT(vkGetSwapchainImagesKHR, false)
|
VULKAN_DEVICE_ENTRY_POINT(vkGetSwapchainImagesKHR, false)
|
||||||
VULKAN_DEVICE_ENTRY_POINT(vkAcquireNextImageKHR, false)
|
VULKAN_DEVICE_ENTRY_POINT(vkAcquireNextImageKHR, false)
|
||||||
VULKAN_DEVICE_ENTRY_POINT(vkQueuePresentKHR, false)
|
VULKAN_DEVICE_ENTRY_POINT(vkQueuePresentKHR, false)
|
||||||
|
VULKAN_DEVICE_ENTRY_POINT(vkGetBufferMemoryRequirements2, false)
|
||||||
|
VULKAN_DEVICE_ENTRY_POINT(vkGetImageMemoryRequirements2, false)
|
||||||
|
VULKAN_DEVICE_ENTRY_POINT(vkBindBufferMemory2, false)
|
||||||
|
VULKAN_DEVICE_ENTRY_POINT(vkBindImageMemory2, false)
|
||||||
|
|
||||||
#ifdef SUPPORTS_VULKAN_EXCLUSIVE_FULLSCREEN
|
#ifdef SUPPORTS_VULKAN_EXCLUSIVE_FULLSCREEN
|
||||||
VULKAN_DEVICE_ENTRY_POINT(vkAcquireFullScreenExclusiveModeEXT, false)
|
VULKAN_DEVICE_ENTRY_POINT(vkAcquireFullScreenExclusiveModeEXT, false)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2016 Dolphin Emulator Project
|
// Copyright 2016 Dolphin Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#define VMA_IMPLEMENTATION
|
||||||
#include "VideoBackends/Vulkan/VulkanLoader.h"
|
#include "VideoBackends/Vulkan/VulkanLoader.h"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
|
@ -37,6 +37,42 @@
|
||||||
#undef VULKAN_INSTANCE_ENTRY_POINT
|
#undef VULKAN_INSTANCE_ENTRY_POINT
|
||||||
#undef VULKAN_MODULE_ENTRY_POINT
|
#undef VULKAN_MODULE_ENTRY_POINT
|
||||||
|
|
||||||
|
// Include vma allocator globally since including it before the vulkan headers causes
|
||||||
|
// errors
|
||||||
|
#ifdef _MSVC_LANG
|
||||||
|
#pragma warning(push, 4)
|
||||||
|
#pragma warning(disable : 4189) // local variable is initialized but not referenced
|
||||||
|
|
||||||
|
#endif // #ifdef _MSVC_LANG
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-variable"
|
||||||
|
#endif // #ifdef __clang__
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||||
|
#endif // #ifdef __GNUC__
|
||||||
|
|
||||||
|
#define VMA_VULKAN_VERSION 1001000
|
||||||
|
#define VMA_STATIC_VULKAN_FUNCTIONS 1
|
||||||
|
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
|
||||||
|
#undef VK_NO_PROTOTYPES
|
||||||
|
#include "vk_mem_alloc.h"
|
||||||
|
|
||||||
|
#ifdef _MSVC_LANG
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif // #ifdef _MSVC_LANG
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif // #ifdef __clang__
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif // #ifdef __GNUC__
|
||||||
|
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
|
||||||
namespace Vulkan
|
namespace Vulkan
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)OpenAL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)OpenAL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)rangeset\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)rangeset\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)Vulkan\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)Vulkan\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<AdditionalIncludeDirectories>$(ExternalsDir)VulkanMemoryAllocator\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<AdditionalIncludeDirectories>$(ExternalsDir)WIL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ExternalsDir)WIL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<!--WIL doesn't have it's own vcxproj/exports, and no externals reference WIL, so this is fine to define only for Dolphin-->
|
<!--WIL doesn't have it's own vcxproj/exports, and no externals reference WIL, so this is fine to define only for Dolphin-->
|
||||||
<PreprocessorDefinitions>WIL_SUPPRESS_EXCEPTIONS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIL_SUPPRESS_EXCEPTIONS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
|
Loading…
Reference in New Issue