fix for AMD gpu (#21)

This commit is contained in:
InoriRus 2022-07-04 17:24:03 +03:00
parent 1aa7cf72ce
commit 498eac6a32
8 changed files with 345 additions and 186 deletions

View File

@ -1,4 +1,4 @@
version: 0.1.7.build-{build} version: 0.1.8.build-{build}
image: Visual Studio 2019 image: Visual Studio 2019
environment: environment:
matrix: matrix:

View File

@ -82,7 +82,7 @@ if (KYTY_LINKER STREQUAL LD)
set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000") set(KYTY_LD_OPTIONS "-Wl,--image-base=0x100000000000")
endif() endif()
project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.1.7) project(Kyty${KYTY_PROJECT_NAME}${CMAKE_BUILD_TYPE}${KYTY_COMPILER} VERSION 0.1.8)
include(src_script.cmake) include(src_script.cmake)

View File

@ -38,23 +38,33 @@ struct VulkanCommandPool
uint32_t buffers_count = 0; uint32_t buffers_count = 0;
}; };
struct VulkanQueueInfo
{
Core::Mutex* mutex = nullptr;
uint32_t family = static_cast<uint32_t>(-1);
uint32_t index = static_cast<uint32_t>(-1);
VkQueue vk_queue = nullptr;
};
struct GraphicContext struct GraphicContext
{ {
static constexpr int QUEUES_NUM = 11; static constexpr int QUEUES_NUM = 11;
static constexpr int QUEUE_GFX = 8; static constexpr int QUEUE_GFX = 8;
static constexpr int QUEUE_GFX_NUM = 1;
static constexpr int QUEUE_UTIL = 9; static constexpr int QUEUE_UTIL = 9;
static constexpr int QUEUE_UTIL_NUM = 1;
static constexpr int QUEUE_PRESENT = 10; static constexpr int QUEUE_PRESENT = 10;
static constexpr int QUEUE_PRESENT_NUM = 1;
static constexpr int QUEUE_COMPUTE_START = 0; static constexpr int QUEUE_COMPUTE_START = 0;
static constexpr int QUEUE_COMPUTE_NUM = 8; static constexpr int QUEUE_COMPUTE_NUM = 8;
uint32_t screen_width = 0; uint32_t screen_width = 0;
uint32_t screen_height = 0; uint32_t screen_height = 0;
VkInstance instance = nullptr; VkInstance instance = nullptr;
VkDebugUtilsMessengerEXT debug_messenger = nullptr; VkDebugUtilsMessengerEXT debug_messenger = nullptr;
VkPhysicalDevice physical_device = nullptr; VkPhysicalDevice physical_device = nullptr;
VkDevice device = nullptr; VkDevice device = nullptr;
uint32_t queue_family_index = static_cast<uint32_t>(-1); VulkanQueueInfo queues[QUEUES_NUM];
VkQueue queue[QUEUES_NUM] = {};
}; };
struct VulkanMemory struct VulkanMemory

View File

@ -30,7 +30,7 @@ struct RenderColorInfo;
class CommandBuffer class CommandBuffer
{ {
public: public:
CommandBuffer() { Allocate(); } explicit CommandBuffer(int queue): m_queue(queue) { Allocate(); }
virtual ~CommandBuffer() { Free(); } virtual ~CommandBuffer() { Free(); }
void SetParent(CommandProcessor* parent) { m_parent = parent; } void SetParent(CommandProcessor* parent) { m_parent = parent; }
@ -55,9 +55,6 @@ public:
VulkanCommandPool* GetPool() { return m_pool; } VulkanCommandPool* GetPool() { return m_pool; }
[[nodiscard]] bool IsExecute() const { return m_execute; } [[nodiscard]] bool IsExecute() const { return m_execute; }
void SetQueue(int queue) { m_queue = queue; }
// void CommandProcessorWait();
private: private:
VulkanCommandPool* m_pool = nullptr; VulkanCommandPool* m_pool = nullptr;

View File

@ -434,31 +434,28 @@ class CommandPool
{ {
public: public:
CommandPool() = default; CommandPool() = default;
~CommandPool() ~CommandPool() // NOLINT
{ {
if (m_pool != nullptr) // TODO(): check if destructor is called from std::_Exit()
{ // DeleteAll();
// TODO(): check if destructor is called from std::_Exit()
// Delete();
}
} }
KYTY_CLASS_NO_COPY(CommandPool); KYTY_CLASS_NO_COPY(CommandPool);
VulkanCommandPool* GetPool() VulkanCommandPool* GetPool(int id)
{ {
if (m_pool == nullptr) if (m_pool[id] == nullptr)
{ {
Create(); Create(id);
} }
return m_pool; return m_pool[id];
} }
private: private:
void Create(); void Create(int id);
void Delete(); void DeleteAll();
VulkanCommandPool* m_pool = nullptr; VulkanCommandPool* m_pool[GraphicContext::QUEUES_NUM] = {};
}; };
static RenderContext* g_render_ctx = nullptr; static RenderContext* g_render_ctx = nullptr;
@ -1190,60 +1187,61 @@ VulkanBuffer* GdsBuffer::GetBuffer(GraphicContext* ctx)
return m_buffer; return m_buffer;
} }
void CommandPool::Create() void CommandPool::Create(int id)
{ {
auto* ctx = g_render_ctx->GetGraphicCtx(); auto* ctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(m_pool != nullptr); EXIT_IF(id < 0 || id >= GraphicContext::QUEUES_NUM);
EXIT_IF(m_pool[id] != nullptr);
m_pool = new VulkanCommandPool; m_pool[id] = new VulkanCommandPool;
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr); EXIT_IF(ctx->device == nullptr);
EXIT_IF(ctx->queue_family_index == static_cast<uint32_t>(-1)); EXIT_IF(ctx->queues[id].family == static_cast<uint32_t>(-1));
EXIT_IF(m_pool->pool != nullptr); EXIT_IF(m_pool[id]->pool != nullptr);
EXIT_IF(m_pool->buffers != nullptr); EXIT_IF(m_pool[id]->buffers != nullptr);
EXIT_IF(m_pool->fences != nullptr); EXIT_IF(m_pool[id]->fences != nullptr);
EXIT_IF(m_pool->semaphores != nullptr); EXIT_IF(m_pool[id]->semaphores != nullptr);
EXIT_IF(m_pool->buffers_count != 0); EXIT_IF(m_pool[id]->buffers_count != 0);
VkCommandPoolCreateInfo pool_info {}; VkCommandPoolCreateInfo pool_info {};
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
pool_info.pNext = nullptr; pool_info.pNext = nullptr;
pool_info.queueFamilyIndex = ctx->queue_family_index; pool_info.queueFamilyIndex = ctx->queues[id].family;
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
vkCreateCommandPool(ctx->device, &pool_info, nullptr, &m_pool->pool); vkCreateCommandPool(ctx->device, &pool_info, nullptr, &m_pool[id]->pool);
EXIT_NOT_IMPLEMENTED(m_pool->pool == nullptr); EXIT_NOT_IMPLEMENTED(m_pool[id]->pool == nullptr);
m_pool->buffers_count = 4; m_pool[id]->buffers_count = 4;
m_pool->buffers = new VkCommandBuffer[m_pool->buffers_count]; m_pool[id]->buffers = new VkCommandBuffer[m_pool[id]->buffers_count];
m_pool->fences = new VkFence[m_pool->buffers_count]; m_pool[id]->fences = new VkFence[m_pool[id]->buffers_count];
m_pool->semaphores = new VkSemaphore[m_pool->buffers_count]; m_pool[id]->semaphores = new VkSemaphore[m_pool[id]->buffers_count];
m_pool->busy = new bool[m_pool->buffers_count]; m_pool[id]->busy = new bool[m_pool[id]->buffers_count];
VkCommandBufferAllocateInfo alloc_info {}; VkCommandBufferAllocateInfo alloc_info {};
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
alloc_info.commandPool = m_pool->pool; alloc_info.commandPool = m_pool[id]->pool;
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
alloc_info.commandBufferCount = m_pool->buffers_count; alloc_info.commandBufferCount = m_pool[id]->buffers_count;
if (vkAllocateCommandBuffers(ctx->device, &alloc_info, m_pool->buffers) != VK_SUCCESS) if (vkAllocateCommandBuffers(ctx->device, &alloc_info, m_pool[id]->buffers) != VK_SUCCESS)
{ {
EXIT("Can't allocate command buffers"); EXIT("Can't allocate command buffers");
} }
for (uint32_t i = 0; i < m_pool->buffers_count; i++) for (uint32_t i = 0; i < m_pool[id]->buffers_count; i++)
{ {
m_pool->busy[i] = false; m_pool[id]->busy[i] = false;
VkFenceCreateInfo fence_info {}; VkFenceCreateInfo fence_info {};
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_info.pNext = nullptr; fence_info.pNext = nullptr;
fence_info.flags = 0; fence_info.flags = 0;
if (vkCreateFence(ctx->device, &fence_info, nullptr, &m_pool->fences[i]) != VK_SUCCESS) if (vkCreateFence(ctx->device, &fence_info, nullptr, &m_pool[id]->fences[i]) != VK_SUCCESS)
{ {
EXIT("Can't create fence"); EXIT("Can't create fence");
} }
@ -1253,42 +1251,47 @@ void CommandPool::Create()
semaphore_info.pNext = nullptr; semaphore_info.pNext = nullptr;
semaphore_info.flags = 0; semaphore_info.flags = 0;
if (vkCreateSemaphore(ctx->device, &semaphore_info, nullptr, &m_pool->semaphores[i]) != VK_SUCCESS) if (vkCreateSemaphore(ctx->device, &semaphore_info, nullptr, &m_pool[id]->semaphores[i]) != VK_SUCCESS)
{ {
EXIT("Can't create semaphore"); EXIT("Can't create semaphore");
} }
EXIT_IF(m_pool->buffers[i] == nullptr); EXIT_IF(m_pool[id]->buffers[i] == nullptr);
EXIT_IF(m_pool->fences[i] == nullptr); EXIT_IF(m_pool[id]->fences[i] == nullptr);
EXIT_IF(m_pool->semaphores[i] == nullptr); EXIT_IF(m_pool[id]->semaphores[i] == nullptr);
} }
} }
void CommandPool::Delete() void CommandPool::DeleteAll()
{ {
auto* ctx = g_render_ctx->GetGraphicCtx(); auto* ctx = g_render_ctx->GetGraphicCtx();
EXIT_IF(m_pool == nullptr); for (auto& pool: m_pool)
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
for (uint32_t i = 0; i < m_pool->buffers_count; i++)
{ {
vkDestroySemaphore(ctx->device, m_pool->semaphores[i], nullptr); if (pool != nullptr)
vkDestroyFence(ctx->device, m_pool->fences[i], nullptr); {
EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr);
for (uint32_t i = 0; i < pool->buffers_count; i++)
{
vkDestroySemaphore(ctx->device, pool->semaphores[i], nullptr);
vkDestroyFence(ctx->device, pool->fences[i], nullptr);
}
vkFreeCommandBuffers(ctx->device, pool->pool, pool->buffers_count, pool->buffers);
vkDestroyCommandPool(ctx->device, pool->pool, nullptr);
delete[] pool->semaphores;
delete[] pool->fences;
delete[] pool->buffers;
delete[] pool->busy;
delete pool;
pool = nullptr;
}
} }
vkFreeCommandBuffers(ctx->device, m_pool->pool, m_pool->buffers_count, m_pool->buffers);
vkDestroyCommandPool(ctx->device, m_pool->pool, nullptr);
delete[] m_pool->semaphores;
delete[] m_pool->fences;
delete[] m_pool->buffers;
delete[] m_pool->busy;
delete m_pool;
m_pool = nullptr;
} }
VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* color, RenderDepthInfo* depth) VulkanFramebuffer* FramebufferCache::CreateFramebuffer(RenderColorInfo* color, RenderDepthInfo* depth)
@ -5049,7 +5052,7 @@ void CommandBuffer::Allocate()
{ {
EXIT_IF(!IsInvalid()); EXIT_IF(!IsInvalid());
m_pool = g_command_pool.GetPool(); m_pool = g_command_pool.GetPool(m_queue);
Core::LockGuard lock(m_pool->mutex); Core::LockGuard lock(m_pool->mutex);
@ -5130,9 +5133,19 @@ void CommandBuffer::Execute()
EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM); EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM);
auto* queue = g_render_ctx->GetGraphicCtx()->queue[m_queue]; const auto& queue = g_render_ctx->GetGraphicCtx()->queues[m_queue];
auto result = vkQueueSubmit(queue, 1, &submit_info, fence); if (queue.mutex != nullptr)
{
queue.mutex->Lock();
}
auto result = vkQueueSubmit(queue.vk_queue, 1, &submit_info, fence);
if (queue.mutex != nullptr)
{
queue.mutex->Unlock();
}
m_execute = true; m_execute = true;
@ -5159,9 +5172,19 @@ void CommandBuffer::ExecuteWithSemaphore()
EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM); EXIT_IF(m_queue < 0 || m_queue >= GraphicContext::QUEUES_NUM);
auto* queue = g_render_ctx->GetGraphicCtx()->queue[m_queue]; const auto& queue = g_render_ctx->GetGraphicCtx()->queues[m_queue];
auto result = vkQueueSubmit(queue, 1, &submit_info, fence); if (queue.mutex != nullptr)
{
queue.mutex->Lock();
}
auto result = vkQueueSubmit(queue.vk_queue, 1, &submit_info, fence);
if (queue.mutex != nullptr)
{
queue.mutex->Lock();
}
m_execute = true; m_execute = true;

View File

@ -514,9 +514,9 @@ void CommandProcessor::BufferInit()
{ {
EXIT_IF(buf != nullptr); EXIT_IF(buf != nullptr);
buf = new CommandBuffer; buf = new CommandBuffer(m_queue);
buf->SetParent(this); buf->SetParent(this);
buf->SetQueue(m_queue); // buf->SetQueue(m_queue);
} }
m_current_buffer = 0; m_current_buffer = 0;

View File

@ -333,8 +333,8 @@ void UtilFillImage(GraphicContext* ctx, VulkanImage* dst_image, const void* src_
std::memcpy(data, src_data, size); std::memcpy(data, src_data, size);
VulkanUnmapMemory(ctx, &staging_buffer.memory); VulkanUnmapMemory(ctx, &staging_buffer.memory);
CommandBuffer buffer; CommandBuffer buffer(GraphicContext::QUEUE_UTIL);
buffer.SetQueue(GraphicContext::QUEUE_UTIL); // buffer.SetQueue(GraphicContext::QUEUE_UTIL);
EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); EXIT_NOT_IMPLEMENTED(buffer.IsInvalid());
@ -360,8 +360,8 @@ void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t
staging_buffer.memory.property = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; staging_buffer.memory.property = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
VulkanCreateBuffer(ctx, size, &staging_buffer); VulkanCreateBuffer(ctx, size, &staging_buffer);
CommandBuffer buffer; CommandBuffer buffer(GraphicContext::QUEUE_UTIL);
buffer.SetQueue(GraphicContext::QUEUE_UTIL); // buffer.SetQueue(GraphicContext::QUEUE_UTIL);
EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); EXIT_NOT_IMPLEMENTED(buffer.IsInvalid());
@ -381,8 +381,8 @@ void UtilFillBuffer(GraphicContext* ctx, void* dst_data, uint64_t size, uint32_t
void UtilSetDepthLayoutOptimal(DepthStencilVulkanImage* image) void UtilSetDepthLayoutOptimal(DepthStencilVulkanImage* image)
{ {
CommandBuffer buffer; CommandBuffer buffer(GraphicContext::QUEUE_UTIL);
buffer.SetQueue(GraphicContext::QUEUE_UTIL); // buffer.SetQueue(GraphicContext::QUEUE_UTIL);
EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); EXIT_NOT_IMPLEMENTED(buffer.IsInvalid());
@ -406,8 +406,8 @@ void UtilSetDepthLayoutOptimal(DepthStencilVulkanImage* image)
void UtilSetImageLayoutOptimal(VulkanImage* image) void UtilSetImageLayoutOptimal(VulkanImage* image)
{ {
CommandBuffer buffer; CommandBuffer buffer(GraphicContext::QUEUE_UTIL);
buffer.SetQueue(GraphicContext::QUEUE_UTIL); // buffer.SetQueue(GraphicContext::QUEUE_UTIL);
EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); EXIT_NOT_IMPLEMENTED(buffer.IsInvalid());
@ -440,8 +440,8 @@ void UtilFillImage(GraphicContext* ctx, VulkanImage* image, const void* src_data
std::memcpy(data, src_data, size); std::memcpy(data, src_data, size);
VulkanUnmapMemory(ctx, &staging_buffer.memory); VulkanUnmapMemory(ctx, &staging_buffer.memory);
CommandBuffer buffer; CommandBuffer buffer(GraphicContext::QUEUE_UTIL);
buffer.SetQueue(GraphicContext::QUEUE_UTIL); // buffer.SetQueue(GraphicContext::QUEUE_UTIL);
EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); EXIT_NOT_IMPLEMENTED(buffer.IsInvalid());
@ -459,8 +459,8 @@ void UtilFillImage(GraphicContext* ctx, const Vector<ImageImageCopy>& regions, V
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(dst_image == nullptr); EXIT_IF(dst_image == nullptr);
CommandBuffer buffer; CommandBuffer buffer(GraphicContext::QUEUE_UTIL);
buffer.SetQueue(GraphicContext::QUEUE_UTIL); // buffer.SetQueue(GraphicContext::QUEUE_UTIL);
EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); EXIT_NOT_IMPLEMENTED(buffer.IsInvalid());
@ -478,8 +478,8 @@ void UtilCopyBuffer(VulkanBuffer* src_buffer, VulkanBuffer* dst_buffer, uint64_t
EXIT_IF(dst_buffer == nullptr); EXIT_IF(dst_buffer == nullptr);
EXIT_IF(dst_buffer->buffer == nullptr); EXIT_IF(dst_buffer->buffer == nullptr);
CommandBuffer buffer; CommandBuffer buffer(GraphicContext::QUEUE_UTIL);
buffer.SetQueue(GraphicContext::QUEUE_UTIL); // buffer.SetQueue(GraphicContext::QUEUE_UTIL);
EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); EXIT_NOT_IMPLEMENTED(buffer.IsInvalid());

View File

@ -1302,13 +1302,153 @@ static bool CheckFormat(VkPhysicalDevice device, VkFormat format, bool tile, VkF
return false; return false;
} }
struct QueueInfo
{
uint32_t family = 0;
uint32_t index = 0;
bool graphics = false;
bool compute = false;
bool transfer = false;
bool present = false;
};
struct VulkanQueues
{
uint32_t family_count = 0;
Vector<uint32_t> family_used;
Vector<QueueInfo> available;
Vector<QueueInfo> graphics;
Vector<QueueInfo> compute;
Vector<QueueInfo> transfer;
Vector<QueueInfo> present;
};
static void VulkanDumpQueues(const VulkanQueues& qs)
{
printf("Queues selected:\n");
printf("\t family_count = %u\n", qs.family_count);
Core::StringList nums;
for (auto u: qs.family_used)
{
nums.Add(String::FromPrintf("%u", u));
}
printf("\t family_used = [%s]\n", nums.Concat(U", ").C_Str());
printf("\t graphics:\n");
for (const auto& q: qs.graphics)
{
printf("\t\t family = %u, index = %u\n", q.family, q.index);
}
printf("\t compute:\n");
for (const auto& q: qs.compute)
{
printf("\t\t family = %u, index = %u\n", q.family, q.index);
}
printf("\t transfer:\n");
for (const auto& q: qs.transfer)
{
printf("\t\t family = %u, index = %u\n", q.family, q.index);
}
printf("\t present:\n");
for (const auto& q: qs.present)
{
printf("\t\t family = %u, index = %u\n", q.family, q.index);
}
}
static VulkanQueues VulkanFindQueues(VkPhysicalDevice device, VkSurfaceKHR surface, uint32_t graphics_num, uint32_t compute_num,
uint32_t transfer_num, uint32_t present_num)
{
EXIT_IF(device == nullptr);
EXIT_IF(surface == nullptr);
VulkanQueues qs;
uint32_t queue_family_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr);
Vector<VkQueueFamilyProperties> queue_families(queue_family_count);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families.GetData());
qs.family_count = queue_family_count;
uint32_t family = 0;
for (auto& f: queue_families)
{
VkBool32 presentation_supported = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(device, family, surface, &presentation_supported);
printf("\tqueue family: %s [count = %u], [present = %s]\n", string_VkQueueFlags(f.queueFlags).c_str(), f.queueCount,
(presentation_supported == VK_TRUE ? "true" : "false"));
for (uint32_t i = 0; i < f.queueCount; i++)
{
QueueInfo info;
info.family = family;
info.index = i;
info.graphics = (f.queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0;
info.compute = (f.queueFlags & VK_QUEUE_COMPUTE_BIT) != 0;
info.transfer = (f.queueFlags & VK_QUEUE_TRANSFER_BIT) != 0;
info.present = (presentation_supported == VK_TRUE);
qs.available.Add(info);
}
qs.family_used.Add(0);
family++;
}
for (uint32_t i = 0; i < graphics_num; i++)
{
if (auto index = qs.available.Find(true, [](auto& q, auto& b) { return q.graphics == b; }); qs.available.IndexValid(index))
{
qs.family_used[qs.available.At(index).family]++;
qs.graphics.Add(qs.available.At(index));
qs.available.RemoveAt(index);
}
}
for (uint32_t i = 0; i < compute_num; i++)
{
if (auto index = qs.available.Find(true, [](auto& q, auto& b) { return q.compute == b; }); qs.available.IndexValid(index))
{
qs.family_used[qs.available.At(index).family]++;
qs.compute.Add(qs.available.At(index));
qs.available.RemoveAt(index);
}
}
for (uint32_t i = 0; i < transfer_num; i++)
{
if (auto index = qs.available.Find(true, [](auto& q, auto& b) { return q.transfer == b; }); qs.available.IndexValid(index))
{
qs.family_used[qs.available.At(index).family]++;
qs.transfer.Add(qs.available.At(index));
qs.available.RemoveAt(index);
}
}
for (uint32_t i = 0; i < present_num; i++)
{
if (auto index = qs.available.Find(true, [](auto& q, auto& b) { return q.present == b; }); qs.available.IndexValid(index))
{
qs.family_used[qs.available.At(index).family]++;
qs.present.Add(qs.available.At(index));
qs.available.RemoveAt(index);
}
}
return qs;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity) // NOLINTNEXTLINE(readability-function-cognitive-complexity)
static VkPhysicalDevice VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceKHR surface, VkQueueFlags queue_family, uint32_t queue_count, static void VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceKHR surface, const Vector<const char*>& device_extensions,
const Vector<const char*>& device_extensions, SurfaceCapabilities* out_capabilities, VkPhysicalDevice* out_device, VulkanQueues* out_queues)
SurfaceCapabilities* r /*, uint32_t image_count*/)
{ {
EXIT_IF(instance == nullptr); EXIT_IF(instance == nullptr);
EXIT_IF(surface == nullptr); EXIT_IF(surface == nullptr);
EXIT_IF(out_capabilities == nullptr);
EXIT_IF(out_device == nullptr);
EXIT_IF(out_queues == nullptr);
uint32_t devices_count = 0; uint32_t devices_count = 0;
vkEnumeratePhysicalDevices(instance, &devices_count, nullptr); vkEnumeratePhysicalDevices(instance, &devices_count, nullptr);
@ -1319,10 +1459,11 @@ static VkPhysicalDevice VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceK
vkEnumeratePhysicalDevices(instance, &devices_count, devices.GetData()); vkEnumeratePhysicalDevices(instance, &devices_count, devices.GetData());
VkPhysicalDevice best_device = nullptr; VkPhysicalDevice best_device = nullptr;
VulkanQueues best_queues;
for (const auto& device: devices) for (const auto& device: devices)
{ {
bool skip_device = true; bool skip_device = false;
VkPhysicalDeviceProperties device_properties {}; VkPhysicalDeviceProperties device_properties {};
VkPhysicalDeviceFeatures2 device_features2 {}; VkPhysicalDeviceFeatures2 device_features2 {};
@ -1339,35 +1480,21 @@ static VkPhysicalDevice VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceK
printf("Vulkan device: %s\n", device_properties.deviceName); printf("Vulkan device: %s\n", device_properties.deviceName);
uint32_t queue_family_count = 0; auto qs = VulkanFindQueues(device, surface, GraphicContext::QUEUE_GFX_NUM, GraphicContext::QUEUE_COMPUTE_NUM,
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr); GraphicContext::QUEUE_UTIL_NUM, GraphicContext::QUEUE_PRESENT_NUM);
Vector<VkQueueFamilyProperties> queue_families(queue_family_count); VulkanDumpQueues(qs);
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families.GetData());
for (auto& f: queue_families) if (qs.graphics.Size() != GraphicContext::QUEUE_GFX_NUM ||
!(qs.compute.Size() >= 1 && qs.compute.Size() <= GraphicContext::QUEUE_COMPUTE_NUM) ||
qs.transfer.Size() != GraphicContext::QUEUE_UTIL_NUM || qs.present.Size() != GraphicContext::QUEUE_PRESENT_NUM)
{ {
printf("\tqueue family: %s [count = %u]\n", string_VkQueueFlags(f.queueFlags).c_str(), f.queueCount); printf("Not enough queues\n");
} skip_device = true;
Vector<uint32_t> indexes;
queue_families.FindAll(
queue_family, [queue_count](auto f, auto bit) { return (f.queueFlags & bit) != 0 && f.queueCount >= queue_count; }, &indexes);
for (auto index: indexes)
{
VkBool32 presentation_supported = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(device, index, surface, &presentation_supported);
if (presentation_supported == VK_TRUE)
{
skip_device = false;
break;
}
} }
if (color_write_ext.colorWriteEnable != VK_TRUE) if (color_write_ext.colorWriteEnable != VK_TRUE)
{ {
printf("colorWriteEnable is not supported\n"); printf("colorWriteEnable is not supported\n");
skip_device = true; skip_device = true;
} }
@ -1420,9 +1547,9 @@ static VkPhysicalDevice VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceK
if (!skip_device) if (!skip_device)
{ {
VulkanGetSurfaceCapabilities(device, surface, r); VulkanGetSurfaceCapabilities(device, surface, out_capabilities);
if ((r->capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) if ((out_capabilities->capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0)
{ {
printf("Surface cannot be destination of blit\n"); printf("Surface cannot be destination of blit\n");
skip_device = true; skip_device = true;
@ -1530,69 +1657,48 @@ static VkPhysicalDevice VulkanFindPhysicalDevice(VkInstance instance, VkSurfaceK
continue; continue;
} }
if (best_device == nullptr) if (best_device == nullptr || device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
{
best_device = device;
}
if (device_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
{ {
best_device = device; best_device = device;
best_queues = qs;
} }
} }
return best_device; *out_device = best_device;
*out_queues = best_queues;
} }
static VkDevice VulkanCreateDevice(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VulkanExtensions* r, static VkDevice VulkanCreateDevice(VkPhysicalDevice physical_device, VkSurfaceKHR surface, const VulkanExtensions* r,
VkQueueFlags queue_family, uint32_t queue_count, uint32_t* queue_family_index, const VulkanQueues& queues, const Vector<const char*>& device_extensions)
const Vector<const char*>& device_extensions)
{ {
EXIT_IF(physical_device == nullptr); EXIT_IF(physical_device == nullptr);
EXIT_IF(r == nullptr); EXIT_IF(r == nullptr);
EXIT_IF(queue_family_index == nullptr);
EXIT_IF(surface == nullptr); EXIT_IF(surface == nullptr);
Vector<float> queue_priority(queue_count); Vector<VkDeviceQueueCreateInfo> queue_create_info(queues.family_count);
for (auto& f: queue_priority) Vector<Vector<float>> queue_priority(queues.family_count);
uint32_t queue_create_info_num = 0;
for (uint32_t i = 0; i < queues.family_count; i++)
{ {
f = 1.0f; if (queues.family_used[i] != 0)
}
uint32_t queue_family_count = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr);
Vector<VkQueueFamilyProperties> queue_families(queue_family_count);
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families.GetData());
Vector<uint32_t> indexes;
queue_families.FindAll(
queue_family, [queue_count](auto f, auto bit) { return (f.queueFlags & bit) != 0 && f.queueCount >= queue_count; }, &indexes);
*queue_family_index = queue_families.Size() + 1;
for (auto index: indexes)
{
VkBool32 presentation_supported = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, index, surface, &presentation_supported);
if (presentation_supported == VK_TRUE)
{ {
*queue_family_index = index; for (uint32_t pi = 0; pi < queues.family_used[i]; pi++)
break; {
queue_priority[queue_create_info_num].Add(1.0f);
}
queue_create_info[queue_create_info_num].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_create_info[queue_create_info_num].pNext = nullptr;
queue_create_info[queue_create_info_num].flags = 0;
queue_create_info[queue_create_info_num].queueFamilyIndex = i;
queue_create_info[queue_create_info_num].queueCount = queues.family_used[i];
queue_create_info[queue_create_info_num].pQueuePriorities = queue_priority[queue_create_info_num].GetDataConst();
queue_create_info_num++;
} }
} }
EXIT_IF(!queue_families.IndexValid(*queue_family_index));
VkDeviceQueueCreateInfo queue_create_info {};
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_create_info.pNext = nullptr;
queue_create_info.flags = 0;
queue_create_info.queueFamilyIndex = *queue_family_index;
queue_create_info.queueCount = queue_count;
queue_create_info.pQueuePriorities = queue_priority.GetDataConst();
VkPhysicalDeviceFeatures device_features {}; VkPhysicalDeviceFeatures device_features {};
device_features.fragmentStoresAndAtomics = VK_TRUE; device_features.fragmentStoresAndAtomics = VK_TRUE;
device_features.samplerAnisotropy = VK_TRUE; device_features.samplerAnisotropy = VK_TRUE;
@ -1607,8 +1713,8 @@ static VkDevice VulkanCreateDevice(VkPhysicalDevice physical_device, VkSurfaceKH
create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
create_info.pNext = &color_write_ext; create_info.pNext = &color_write_ext;
create_info.flags = 0; create_info.flags = 0;
create_info.pQueueCreateInfos = &queue_create_info; create_info.pQueueCreateInfos = queue_create_info.GetDataConst();
create_info.queueCreateInfoCount = 1; create_info.queueCreateInfoCount = queue_create_info_num;
create_info.enabledLayerCount = (r->enable_validation_layers ? r->required_layers.Size() : 0); create_info.enabledLayerCount = (r->enable_validation_layers ? r->required_layers.Size() : 0);
create_info.ppEnabledLayerNames = (r->enable_validation_layers ? r->required_layers.GetDataConst() : nullptr); create_info.ppEnabledLayerNames = (r->enable_validation_layers ? r->required_layers.GetDataConst() : nullptr);
create_info.enabledExtensionCount = device_extensions.Size(); create_info.enabledExtensionCount = device_extensions.Size();
@ -1902,17 +2008,36 @@ static VKAPI_ATTR VkResult VKAPI_CALL VulkanCreateDebugUtilsMessengerEXT(VkInsta
return swapchain; return swapchain;
} }
static void VulkanCreateQueues(GraphicContext* ctx) static void VulkanCreateQueues(GraphicContext* ctx, const VulkanQueues& queues)
{ {
EXIT_IF(ctx == nullptr); EXIT_IF(ctx == nullptr);
EXIT_IF(ctx->device == nullptr); EXIT_IF(ctx->device == nullptr);
EXIT_IF(ctx->queue_family_index == static_cast<uint32_t>(-1)); EXIT_IF(queues.graphics.Size() != 1);
EXIT_IF(queues.transfer.Size() != 1);
EXIT_IF(queues.present.Size() != 1);
EXIT_IF(!(queues.compute.Size() >= 1 && queues.compute.Size() <= GraphicContext::QUEUE_COMPUTE_NUM));
for (int i = 0; i < GraphicContext::QUEUES_NUM; i++) auto get_queue = [ctx](int id, const QueueInfo& info, bool with_mutex = false)
{ {
EXIT_IF(ctx->queue[i] != nullptr); ctx->queues[id].family = info.family;
vkGetDeviceQueue(ctx->device, ctx->queue_family_index, i, &ctx->queue[i]); ctx->queues[id].index = info.index;
EXIT_NOT_IMPLEMENTED(ctx->queue[i] == nullptr); EXIT_IF(ctx->queues[id].vk_queue != nullptr);
vkGetDeviceQueue(ctx->device, ctx->queues[id].family, ctx->queues[id].index, &ctx->queues[id].vk_queue);
EXIT_NOT_IMPLEMENTED(ctx->queues[id].vk_queue == nullptr);
if (with_mutex)
{
ctx->queues[id].mutex = new Core::Mutex;
}
};
get_queue(GraphicContext::QUEUE_GFX, queues.graphics.At(0));
get_queue(GraphicContext::QUEUE_UTIL, queues.transfer.At(0));
get_queue(GraphicContext::QUEUE_PRESENT, queues.present.At(0));
for (int id = 0; id < GraphicContext::QUEUE_COMPUTE_NUM; id++)
{
bool with_mutex = (GraphicContext::QUEUE_COMPUTE_NUM == queues.compute.Size());
get_queue(GraphicContext::QUEUE_COMPUTE_START + id, queues.compute.At(id % queues.compute.Size()), with_mutex);
} }
} }
@ -2063,9 +2188,11 @@ static void VulkanCreate(WindowContext* ctx)
ctx->surface_capabilities = new SurfaceCapabilities {}; ctx->surface_capabilities = new SurfaceCapabilities {};
ctx->graphic_ctx.physical_device = VulkanQueues queues;
VulkanFindPhysicalDevice(ctx->graphic_ctx.instance, ctx->surface, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
GraphicContext::QUEUES_NUM, device_extensions, ctx->surface_capabilities); VulkanFindPhysicalDevice(ctx->graphic_ctx.instance, ctx->surface, device_extensions, ctx->surface_capabilities,
&ctx->graphic_ctx.physical_device, &queues);
if (ctx->graphic_ctx.physical_device == nullptr) if (ctx->graphic_ctx.physical_device == nullptr)
{ {
EXIT("Could not find suitable device"); EXIT("Could not find suitable device");
@ -2079,15 +2206,13 @@ static void VulkanCreate(WindowContext* ctx)
memcpy(ctx->device_name, device_properties.deviceName, sizeof(ctx->device_name)); memcpy(ctx->device_name, device_properties.deviceName, sizeof(ctx->device_name));
memcpy(ctx->processor_name, Loader::GetSystemInfo().ProcessorName.C_Str(), sizeof(ctx->processor_name)); memcpy(ctx->processor_name, Loader::GetSystemInfo().ProcessorName.C_Str(), sizeof(ctx->processor_name));
ctx->graphic_ctx.device = ctx->graphic_ctx.device = VulkanCreateDevice(ctx->graphic_ctx.physical_device, ctx->surface, &r, queues, device_extensions);
VulkanCreateDevice(ctx->graphic_ctx.physical_device, ctx->surface, &r, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
GraphicContext::QUEUES_NUM, &ctx->graphic_ctx.queue_family_index, device_extensions);
if (ctx->graphic_ctx.device == nullptr) if (ctx->graphic_ctx.device == nullptr)
{ {
EXIT("Could not create device"); EXIT("Could not create device");
} }
VulkanCreateQueues(&ctx->graphic_ctx); VulkanCreateQueues(&ctx->graphic_ctx, queues);
ctx->swapchain = VulkanCreateSwapchain(&ctx->graphic_ctx, 2); ctx->swapchain = VulkanCreateSwapchain(&ctx->graphic_ctx, 2);
} }
@ -2238,8 +2363,8 @@ void WindowDrawBuffer(VideoOutVulkanImage* image)
EXIT_IF(blt_src_image == nullptr); EXIT_IF(blt_src_image == nullptr);
EXIT_IF(blt_dst_image == nullptr); EXIT_IF(blt_dst_image == nullptr);
CommandBuffer buffer; CommandBuffer buffer(GraphicContext::QUEUE_PRESENT);
buffer.SetQueue(GraphicContext::QUEUE_PRESENT); // buffer.SetQueue(GraphicContext::QUEUE_PRESENT);
EXIT_NOT_IMPLEMENTED(buffer.IsInvalid()); EXIT_NOT_IMPLEMENTED(buffer.IsInvalid());
@ -2280,7 +2405,11 @@ void WindowDrawBuffer(VideoOutVulkanImage* image)
present.waitSemaphoreCount = 1; present.waitSemaphoreCount = 1;
present.pResults = nullptr; present.pResults = nullptr;
result = vkQueuePresentKHR(g_window_ctx->graphic_ctx.queue[GraphicContext::QUEUE_PRESENT], &present); const auto& queue = g_window_ctx->graphic_ctx.queues[GraphicContext::QUEUE_PRESENT];
EXIT_IF(queue.mutex != nullptr);
result = vkQueuePresentKHR(queue.vk_queue, &present);
EXIT_NOT_IMPLEMENTED(result != VK_SUCCESS); EXIT_NOT_IMPLEMENTED(result != VK_SUCCESS);
WindowUpdateTitle(); WindowUpdateTitle();