diff --git a/CMakeLists.txt b/CMakeLists.txt
index c50b40ea0a97251527caaa721a1053f8e32d7288..09a842443f7417d181f3b72a831c3531fe026b7d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -164,6 +164,8 @@ add_library(lava.base STATIC
         ${LIBLAVA_DIR}/base/memory.hpp
         ${LIBLAVA_DIR}/base/physical_device.cpp
         ${LIBLAVA_DIR}/base/physical_device.hpp
+        ${LIBLAVA_DIR}/base/queue.cpp
+        ${LIBLAVA_DIR}/base/queue.hpp
         ${LIBLAVA_EXT_DIR}/volk/volk.c
         )
 
@@ -357,14 +359,10 @@ if(LIBLAVA_TESTS)
                 RUNTIME DESTINATION bin
                 )
 
-        message(">> lava-unit")
-
-        message(">>> Catch2")
+        message(">> lava-unit (Catch2)")
 
         add_subdirectory(${LIBLAVA_EXT_DIR}/Catch2 Catch2 EXCLUDE_FROM_ALL)
 
-        message("<<< Catch2")
-
         add_executable(lava-unit 
                 ${LIBLAVA_TESTS_DIR}/unit.cpp
                 )
diff --git a/DOCS.md b/DOCS.md
index a297d31d66a7a51c06cb70508a0d17033cac2262..946003921177cb7b704c921016f0a67cd45c5377 100644
--- a/DOCS.md
+++ b/DOCS.md
@@ -398,7 +398,7 @@ int main(int argc, char* argv[]) {
 
 #### lava [base](https://github.com/liblava/liblava/tree/master/liblava/base)
 
-[![base](https://img.shields.io/badge/lava-base-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/base.hpp) [![device](https://img.shields.io/badge/lava-device-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/device.hpp) [![instance](https://img.shields.io/badge/lava-instance-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/instance.hpp) [![memory](https://img.shields.io/badge/lava-memory-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/memory.hpp) [![physical_device](https://img.shields.io/badge/lava-physical_device-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/physical_device.hpp)
+[![base](https://img.shields.io/badge/lava-base-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/base.hpp) [![device](https://img.shields.io/badge/lava-device-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/device.hpp) [![instance](https://img.shields.io/badge/lava-instance-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/instance.hpp) [![memory](https://img.shields.io/badge/lava-memory-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/memory.hpp) [![physical_device](https://img.shields.io/badge/lava-physical_device-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/physical_device.hpp) [![queue](https://img.shields.io/badge/lava-queue-orange.svg)](https://github.com/liblava/liblava/tree/master/liblava/base/queue.hpp)
 
 #### lava [file](https://github.com/liblava/liblava/tree/master/liblava/file)
 
diff --git a/liblava/base.hpp b/liblava/base.hpp
index 32eb8d6187f3408ba71b571ecbb5e1d5eaef1446..659e8261c5cc839a66b2bd691052a43cb4457ad4 100644
--- a/liblava/base.hpp
+++ b/liblava/base.hpp
@@ -11,3 +11,4 @@
 #include <liblava/base/instance.hpp>
 #include <liblava/base/memory.hpp>
 #include <liblava/base/physical_device.hpp>
+#include <liblava/base/queue.hpp>
diff --git a/liblava/base/device.cpp b/liblava/base/device.cpp
index 8b39724a5c9ff84578a83ba9e8f83821f004b384..1e37a26e2bb283b60c7db2711b0228ce0aae7de7 100644
--- a/liblava/base/device.cpp
+++ b/liblava/base/device.cpp
@@ -8,25 +8,79 @@
 
 namespace lava {
 
+    void device::create_param::set_all_queues() {
+        lava::set_all_queues(queue_family_infos, physical_device->get_queue_family_properties());
+    }
+
+    bool device::create_param::add_queues(VkQueueFlags flags, ui32 count, r32 priority) {
+        return lava::add_queues(queue_family_infos, physical_device->get_queue_family_properties(), flags, count, priority);
+    }
+
+    bool device::create_param::add_dedicated_queues(r32 priority) {
+        return lava::add_dedicated_queues(queue_family_infos, physical_device->get_queue_family_properties(), priority);
+    }
+
+    queue_verify_result device::create_param::verify_queues() const {
+        return lava::verify_queues(queue_family_infos, physical_device->get_queue_family_properties());
+    }
+
     bool device::create(create_param::ref param) {
         physical_device = param.physical_device;
         if (!physical_device)
             return false;
 
-        std::vector<VkDeviceQueueCreateInfo> queue_create_info_list(param.queue_info_list.size());
+        auto verify_result = param.verify_queues();
+        if (verify_result != queue_verify_result::ok) {
+            switch (verify_result) {
+            case queue_verify_result::empty_list: {
+                log()->error("create device - verify queues - param with empty list");
+                break;
+            }
+            case queue_verify_result::no_properties: {
+                log()->error("create device - verify queues - no device family properties");
+                break;
+            }
+            case queue_verify_result::duplicate_family_index: {
+                log()->error("create device - verify queues - duplicate family index");
+                break;
+            }
+            case queue_verify_result::no_family_index: {
+                log()->error("create device - verify queues - family index is not available");
+                break;
+            }
+            case queue_verify_result::no_queues: {
+                log()->error("create device - verify queues - undefined queues in family");
+                break;
+            }
+            case queue_verify_result::too_many_queues: {
+                log()->error("create device - verify queues - number of queues is incorrect");
+                break;
+            }
+            case queue_verify_result::no_compatible_flags: {
+                log()->error("create device - verify queues - no compatible flags in queue");
+                break;
+            }
+            default:
+                log()->error("create device - verify queues");
+            }
+
+            return false;
+        }
+
+        std::vector<VkDeviceQueueCreateInfo> queue_create_info_list(param.queue_family_infos.size());
 
-        for (size_t i = 0, e = param.queue_info_list.size(); i != e; ++i) {
+        std::vector<std::vector<r32>> priorities;
+        priorities.resize(param.queue_family_infos.size());
+
+        for (auto i = 0u; i < param.queue_family_infos.size(); ++i) {
             queue_create_info_list[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+            queue_create_info_list[i].queueFamilyIndex = param.queue_family_infos[i].family_index;
+            queue_create_info_list[i].queueCount = param.queue_family_infos[i].queues.size();
 
-            auto index = 0u;
-            if (!physical_device->get_queue_family(index, param.queue_info_list[i].flags)) {
-                log()->error("create device queue family");
-                return false;
-            }
+            for (auto j = 0u; j < param.queue_family_infos[i].queues.size(); ++j)
+                priorities.at(i).push_back(param.queue_family_infos[i].queues.at(j).priority);
 
-            queue_create_info_list[i].queueFamilyIndex = index;
-            queue_create_info_list[i].queueCount = param.queue_info_list[i].count();
-            queue_create_info_list[i].pQueuePriorities = param.queue_info_list[i].priorities.data();
+            queue_create_info_list[i].pQueuePriorities = priorities.at(i).data();
         }
 
         VkDeviceCreateInfo create_info{
@@ -55,27 +109,29 @@ namespace lava {
         transfer_queue_list.clear();
         queue_list.clear();
 
-        index_map queue_family_map;
+        for (auto i = 0u; i != queue_create_info_list.size(); ++i) {
+            auto queue_family_index = queue_create_info_list[i].queueFamilyIndex;
+            auto queue_family_flags = physical_device->get_queue_family_properties().at(queue_family_index).queueFlags;
 
-        for (size_t i = 0, ei = queue_create_info_list.size(); i != ei; ++i) {
-            if (!queue_family_map.count(queue_create_info_list[i].queueFamilyIndex))
-                queue_family_map.emplace(queue_create_info_list[i].queueFamilyIndex, 0);
+            for (auto queue_index = 0u; queue_index != queue_create_info_list[i].queueCount; ++queue_index) {
+                VkQueue vk_queue = nullptr;
+                call().vkGetDeviceQueue(vk_device, queue_family_index, queue_index, &vk_queue);
 
-            for (size_t j = 0, ej = queue_create_info_list[i].queueCount; j != ej; ++j) {
-                auto counter = queue_family_map[queue_create_info_list[i].queueFamilyIndex];
-                queue_family_map[queue_create_info_list[i].queueFamilyIndex]++;
+                auto flags = param.queue_family_infos[i].queues.at(queue_index).flags;
+                auto priority = queue_create_info_list[i].pQueuePriorities[queue_index];
 
-                VkQueue queue = nullptr;
-                call().vkGetDeviceQueue(vk_device, queue_create_info_list[i].queueFamilyIndex, counter, &queue);
+                queue queue{
+                    vk_queue, queue_family_flags, queue_family_index, priority
+                };
 
-                if (param.queue_info_list[i].flags & VK_QUEUE_GRAPHICS_BIT)
-                    graphics_queue_list.push_back({ queue, queue_create_info_list[i].queueFamilyIndex });
-                if (param.queue_info_list[i].flags & VK_QUEUE_COMPUTE_BIT)
-                    compute_queue_list.push_back({ queue, queue_create_info_list[i].queueFamilyIndex });
-                if (param.queue_info_list[i].flags & VK_QUEUE_TRANSFER_BIT)
-                    transfer_queue_list.push_back({ queue, queue_create_info_list[i].queueFamilyIndex });
+                if (flags & VK_QUEUE_GRAPHICS_BIT)
+                    graphics_queue_list.push_front(queue);
+                if (flags & VK_QUEUE_COMPUTE_BIT)
+                    compute_queue_list.push_front(queue);
+                if (flags & VK_QUEUE_TRANSFER_BIT)
+                    transfer_queue_list.push_front(queue);
 
-                queue_list.push_back({ queue, queue_create_info_list[i].queueFamilyIndex });
+                queue_list.push_back(queue);
             }
         }
 
diff --git a/liblava/base/device.hpp b/liblava/base/device.hpp
index 9da9193d68b963a87d4d15dccbfe79d5362788cb..abc96daee5f5886b76bbdc44f24579ebcfa78b78 100644
--- a/liblava/base/device.hpp
+++ b/liblava/base/device.hpp
@@ -5,6 +5,7 @@
 #pragma once
 
 #include <liblava/base/device_table.hpp>
+#include <liblava/base/queue.hpp>
 #include <liblava/core/data.hpp>
 
 namespace lava {
@@ -22,34 +23,30 @@ namespace lava {
 
             physical_device_cptr physical_device = nullptr;
 
-            struct queue_info {
-                using list = std::vector<queue_info>;
+            names extensions;
+            VkPhysicalDeviceFeatures features{};
+            void const* next = nullptr; // pNext
 
-                VkQueueFlags flags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
+            queue_family_info::list queue_family_infos;
 
-                using priority_list = std::vector<float>;
-                priority_list priorities;
+            void add_swapchain_extension() {
+                extensions.push_back("VK_KHR_swapchain");
+            }
 
-                ui32 count() const {
-                    return to_ui32(priorities.size());
-                }
+            void set_default_queues() {
+                lava::set_default_queues(queue_family_infos);
+            }
 
-                explicit queue_info(ui32 count = 1) {
-                    for (auto i = 0u; i < count; ++i)
-                        priorities.push_back(1.f);
-                }
-            };
+            void set_all_queues();
 
-            queue_info::list queue_info_list;
+            bool add_queue(VkQueueFlags flags, r32 priority = 1.f) {
+                return add_queues(flags, 1, priority);
+            }
+            bool add_queues(VkQueueFlags flags, ui32 count, r32 priority = 1.f);
 
-            names extensions;
-            VkPhysicalDeviceFeatures features{};
-            void const* next = nullptr; // pNext
+            bool add_dedicated_queues(r32 priority = 1.f);
 
-            void set_default_queues() {
-                extensions.push_back("VK_KHR_swapchain");
-                queue_info_list.resize(1);
-            }
+            queue_verify_result verify_queues() const;
         };
 
         ~device() {
@@ -59,14 +56,6 @@ namespace lava {
         bool create(create_param::ref param);
         void destroy();
 
-        struct queue {
-            using list = std::vector<queue>;
-            using ref = queue const&;
-
-            VkQueue vk_queue = nullptr;
-            index family = 0;
-        };
-
         queue::ref get_graphics_queue(index index = 0) const {
             return get_graphics_queues().at(index);
         }
@@ -160,10 +149,10 @@ namespace lava {
 
         VkDescriptorPool descriptor_pool = 0;
 
-        device::queue::list graphics_queue_list;
-        device::queue::list compute_queue_list;
-        device::queue::list transfer_queue_list;
-        device::queue::list queue_list;
+        queue::list graphics_queue_list;
+        queue::list compute_queue_list;
+        queue::list transfer_queue_list;
+        queue::list queue_list;
 
         VkPhysicalDeviceFeatures features;
 
diff --git a/liblava/base/physical_device.cpp b/liblava/base/physical_device.cpp
index 1b42f9f1c358e04f74b53f612eadd184fd597e20..e6f4a22b3044eab7c778281a6e4fcd3316753d5b 100644
--- a/liblava/base/physical_device.cpp
+++ b/liblava/base/physical_device.cpp
@@ -51,6 +51,7 @@ namespace lava {
     device::create_param physical_device::create_default_device_param() const {
         device::create_param create_param;
         create_param.physical_device = this;
+        create_param.add_swapchain_extension();
         create_param.set_default_queues();
 
         return create_param;
diff --git a/liblava/base/queue.cpp b/liblava/base/queue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7fc13314f512cce59ded73ec01de95fcd4c4dd58
--- /dev/null
+++ b/liblava/base/queue.cpp
@@ -0,0 +1,129 @@
+// file      : liblava/base/queue.cpp
+// copyright : Copyright (c) 2018-present, Lava Block OÜ and contributors
+// license   : MIT; see accompanying LICENSE file
+
+#include <liblava/base/queue.hpp>
+
+namespace lava {
+
+    void set_default_queues(queue_family_info::list& list) {
+        list.clear();
+
+        list.resize(1);
+        list.at(0).queues.resize(1);
+    }
+
+    void set_all_queues(queue_family_info::list& list, VkQueueFamilyPropertiesList const& properties) {
+        list.clear();
+
+        for (auto& queue_family : properties) {
+            queue_family_info info;
+            info.family_index = list.size();
+            for (auto queue_count = 0; queue_count < queue_family.queueCount; ++queue_count)
+                info.queues.emplace_back(queue_family.queueFlags, 1.f);
+            list.push_back(info);
+        }
+    }
+
+    void add_queues(queue_family_info::list& list, index family_index, VkQueueFlags flags, ui32 count, r32 priority) {
+        for (auto& family_info : list) {
+            if (family_info.family_index == family_index) {
+                family_info.add(flags, count, priority);
+                return;
+            }
+        }
+
+        queue_family_info family_info;
+        family_info.family_index = family_index;
+        family_info.add(flags, count, priority);
+        list.emplace_back(family_info);
+    }
+
+    bool add_queues(queue_family_info::list& list, VkQueueFamilyPropertiesList const& properties, VkQueueFlags flags, ui32 count, r32 priority) {
+        VkQueueFamilyPropertiesList free_properties;
+        for (auto family_index = 0u; family_index < properties.size(); ++family_index) {
+            auto family_properties = properties.at(family_index);
+            for (auto& family_info : list) {
+                if (family_info.family_index == family_index) {
+                    family_properties.queueCount = properties.at(family_index).queueCount - family_info.count();
+                    break;
+                }
+            }
+
+            free_properties.push_back(family_properties);
+        }
+
+        // first look for a free family with the same flags (in reverse order)
+        i32 family_index_count = free_properties.size();
+        for (auto family_index = family_index_count - 1; family_index >= 0; --family_index) {
+            auto const& queue_family = free_properties.at(family_index);
+
+            auto queue_family_flags = queue_family.queueFlags & ~VK_QUEUE_SPARSE_BINDING_BIT; // ignore
+            if ((queue_family_flags == flags) && (queue_family.queueCount >= count)) {
+                add_queues(list, family_index, flags, count, priority);
+                return true;
+            }
+        }
+
+        // fallback: search again if the flags exists within a free family
+        for (auto family_index = 0u; family_index < free_properties.size(); ++family_index) {
+            auto const& queue_family = free_properties.at(family_index);
+
+            auto queue_family_flags = queue_family.queueFlags & ~VK_QUEUE_SPARSE_BINDING_BIT; // ignore
+            if (((queue_family_flags & flags) == flags) && (queue_family.queueCount >= count)) {
+                add_queues(list, family_index, flags, count, priority);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    bool add_dedicated_queues(queue_family_info::list& list, VkQueueFamilyPropertiesList const& properties, r32 priority) {
+        if (properties.size() < 2)
+            return false;
+
+        for (auto family_index = 1u; family_index < properties.size(); ++family_index) {
+            queue_family_info info;
+            info.family_index = family_index;
+            for (auto queue_count = 0; queue_count < properties.at(family_index).queueCount; ++queue_count)
+                info.queues.emplace_back(properties.at(family_index).queueFlags, priority);
+            list.push_back(info);
+        }
+
+        return true;
+    }
+
+    queue_verify_result verify_queues(queue_family_info::list const& list, VkQueueFamilyPropertiesList const& properties) {
+        if (list.empty())
+            return queue_verify_result::empty_list;
+
+        if (properties.empty())
+            return queue_verify_result::no_properties;
+
+        index_list families;
+        for (auto& info : list) {
+            if (contains(families, info.family_index))
+                return queue_verify_result::duplicate_family_index;
+
+            families.push_back(info.family_index);
+
+            if (info.family_index > properties.size() - 1)
+                return queue_verify_result::no_family_index;
+
+            if (info.queues.empty())
+                return queue_verify_result::no_queues;
+
+            if (info.count() > properties[info.family_index].queueCount)
+                return queue_verify_result::too_many_queues;
+
+            for (auto& queue : info.queues) {
+                if ((properties[info.family_index].queueFlags & queue.flags) != queue.flags)
+                    return queue_verify_result::no_compatible_flags;
+            }
+        }
+
+        return queue_verify_result::ok;
+    }
+
+} // namespace lava
diff --git a/liblava/base/queue.hpp b/liblava/base/queue.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..385304d619f80f2c061729e0665817ae17460500
--- /dev/null
+++ b/liblava/base/queue.hpp
@@ -0,0 +1,78 @@
+// file      : liblava/base/queue.hpp
+// copyright : Copyright (c) 2018-present, Lava Block OÜ and contributors
+// license   : MIT; see accompanying LICENSE file
+
+#pragma once
+
+#include <liblava/base/base.hpp>
+
+namespace lava {
+
+    struct queue {
+        using list = std::deque<queue>;
+        using ref = queue const&;
+
+        VkQueue vk_queue = nullptr;
+        VkQueueFlags flags = 0;
+
+        index family = 0;
+        r32 priority = 1.f;
+
+        bool operator<(queue const& other) const {
+            return priority < other.priority;
+        }
+    };
+
+    constexpr VkQueueFlags const default_queue_flags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
+
+    struct queue_info {
+        using list = std::deque<queue_info>;
+
+        VkQueueFlags flags = default_queue_flags;
+        r32 priority = 1.f;
+    };
+
+    struct queue_family_info {
+        using list = std::deque<queue_family_info>;
+
+        index family_index = 0;
+        queue_info::list queues;
+
+        void add(VkQueueFlags flags, ui32 count = 1, r32 priority = 1.f) {
+            for (auto i = 0u; i < count; ++i)
+                queues.emplace_back(flags, priority);
+        }
+
+        ui32 count() const {
+            return to_ui32(queues.size());
+        }
+
+        void clear() {
+            queues.clear();
+        }
+    };
+
+    void set_default_queues(queue_family_info::list& list);
+    void set_all_queues(queue_family_info::list& list, VkQueueFamilyPropertiesList const& properties);
+
+    bool add_queues(queue_family_info::list& list,
+                    VkQueueFamilyPropertiesList const& properties,
+                    VkQueueFlags flags, ui32 count, r32 priority = 1.f);
+
+    bool add_dedicated_queues(queue_family_info::list& list,
+                              VkQueueFamilyPropertiesList const& properties,
+                              r32 priority = 1.f);
+
+    enum class queue_verify_result : type {
+        ok = 0,
+        empty_list,
+        no_properties,
+        duplicate_family_index,
+        no_family_index,
+        no_queues,
+        too_many_queues,
+        no_compatible_flags
+    };
+    queue_verify_result verify_queues(queue_family_info::list const& list, VkQueueFamilyPropertiesList const& properties);
+
+} // namespace lava
diff --git a/liblava/frame/renderer.cpp b/liblava/frame/renderer.cpp
index 823aaf815ddb6bc5716468eb56b1d845a5acc8d9..5277313b37a66be0d7c29ff3202d226b3bcec3fc 100644
--- a/liblava/frame/renderer.cpp
+++ b/liblava/frame/renderer.cpp
@@ -11,7 +11,7 @@ namespace lava {
         target = t;
         device = target->get_device();
 
-        queue = device->get_graphics_queue();
+        graphics_queue = device->get_graphics_queue();
         queued_frames = target->get_backbuffer_count();
 
         fences.resize(queued_frames);
@@ -141,7 +141,7 @@ namespace lava {
         std::array<VkSubmitInfo, 1> const submit_infos = { submit_info };
         VkFence current_fence = fences[current_sync];
 
-        if (!device->vkQueueSubmit(queue.vk_queue, to_ui32(submit_infos.size()), submit_infos.data(), current_fence))
+        if (!device->vkQueueSubmit(graphics_queue.vk_queue, to_ui32(submit_infos.size()), submit_infos.data(), current_fence))
             return false;
 
         std::array<VkSwapchainKHR, 1> const swapchains = { target->get() };
@@ -156,7 +156,7 @@ namespace lava {
             .pImageIndices = indices.data(),
         };
 
-        auto result = device->vkQueuePresentKHR(queue.vk_queue, &present_info);
+        auto result = device->vkQueuePresentKHR(graphics_queue.vk_queue, &present_info);
         if (result.value == VK_ERROR_OUT_OF_DATE_KHR) {
             target->request_reload();
             return true;
diff --git a/liblava/frame/renderer.hpp b/liblava/frame/renderer.hpp
index b09f15dc2ac15569cb645854332a6adbfc172f3f..621d3ff7f3971525c38ff48b84ba83e2915cfe1c 100644
--- a/liblava/frame/renderer.hpp
+++ b/liblava/frame/renderer.hpp
@@ -34,7 +34,7 @@ namespace lava {
 
     private:
         device_ptr device = nullptr;
-        device::queue queue;
+        queue graphics_queue;
 
         swapchain* target = nullptr;
 
diff --git a/tests/unit.cpp b/tests/unit.cpp
index 4dfc7ee50141861f1b8b15f56e298c8fbcedf79f..dbae9908505f20409c30c45888709b9c9f920952 100644
--- a/tests/unit.cpp
+++ b/tests/unit.cpp
@@ -1,5 +1,5 @@
 // file      : tests/unit.cpp
-// copyright : Copyright (c) 2018-present, Lava Block O� and contributors
+// copyright : Copyright (c) 2018-present, Lava Block OÜ and contributors
 // license   : MIT; see accompanying LICENSE file
 
 #include <catch2/catch_test_macros.hpp>
@@ -7,13 +7,108 @@
 
 using namespace lava;
 
-unsigned int Factorial(unsigned int number) {
-    return number <= 1 ? number : Factorial(number - 1) * number;
+TEST_CASE("queue setup - GeForce GTX 1060", "[queue]") {
+    // http://vulkan.gpuinfo.org/listreports.php?devicename=GeForce+GTX+1060
+
+    VkQueueFamilyPropertiesList properties{
+        { VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 16 },
+        { VK_QUEUE_TRANSFER_BIT, 2 },
+        { VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 8 }
+    };
+
+    queue_family_info::list list;
+
+    SECTION("set default queues") {
+        set_default_queues(list);
+
+        REQUIRE(list.at(0).count() == 1);
+        REQUIRE(list.at(0).queues.at(0).flags == (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT));
+    }
+
+    SECTION("set all queues") {
+        set_all_queues(list, properties);
+
+        REQUIRE(list.at(0).count() == 16);
+        for (auto& queue : list.at(0).queues)
+            REQUIRE(queue.flags == (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT));
+
+        REQUIRE(list.at(1).count() == 2);
+        for (auto& queue : list.at(1).queues)
+            REQUIRE(queue.flags == (VK_QUEUE_TRANSFER_BIT));
+
+        REQUIRE(list.at(2).count() == 8);
+        for (auto& queue : list.at(2).queues)
+            REQUIRE(queue.flags == (VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT));
+    }
+
+    SECTION("add default + each dedicated queues") {
+        set_default_queues(list);
+
+        REQUIRE(add_queues(list, properties, VK_QUEUE_COMPUTE_BIT, 1));
+        REQUIRE(add_queues(list, properties, VK_QUEUE_TRANSFER_BIT, 1));
+    }
+
+    REQUIRE(verify_queues(list, properties) == queue_verify_result::ok);
+}
+
+TEST_CASE("queue setup - Radeon RX 580 Series", "[queue]") {
+    // http://vulkan.gpuinfo.org/listreports.php?devicename=Radeon+RX+580+Series
+
+    VkQueueFamilyPropertiesList properties{
+        { VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 },
+        { VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 2 },
+        { VK_QUEUE_TRANSFER_BIT, 2 }
+    };
+
+    queue_family_info::list list;
+
+    SECTION("add all dedicated queues") {
+        SECTION("with default queues") {
+            set_default_queues(list);
+            REQUIRE(list.size() == 1);
+            REQUIRE(add_dedicated_queues(list, properties));
+            REQUIRE(list.size() == 3);
+        }
+
+        SECTION("without default queues") {
+            REQUIRE(list.empty());
+            REQUIRE(add_dedicated_queues(list, properties));
+            REQUIRE(list.size() == 2);
+        }
+    }
+
+    SECTION("add more queues + fallback") {
+        REQUIRE(add_queues(list, properties, VK_QUEUE_TRANSFER_BIT, 2));
+        REQUIRE(add_queues(list, properties, VK_QUEUE_TRANSFER_BIT | VK_QUEUE_COMPUTE_BIT, 1));
+        REQUIRE(add_queues(list, properties, VK_QUEUE_TRANSFER_BIT | VK_QUEUE_COMPUTE_BIT, 1));
+
+        // fallback
+        REQUIRE(add_queues(list, properties, VK_QUEUE_TRANSFER_BIT, 1));
+        REQUIRE_FALSE(add_queues(list, properties, VK_QUEUE_COMPUTE_BIT, 1));
+    }
+
+    REQUIRE(verify_queues(list, properties) == queue_verify_result::ok);
 }
 
-TEST_CASE("Factorials are computed", "[factorial]") {
-    REQUIRE(Factorial(1) == 1);
-    REQUIRE(Factorial(2) == 2);
-    REQUIRE(Factorial(3) == 6);
-    REQUIRE(Factorial(10) == 3628800);
+TEST_CASE("queue setup - Intel(R) HD Graphics 620", "[queue]") {
+    // http://vulkan.gpuinfo.org/listreports.php?devicename=Intel%28R%29+HD+Graphics+620
+
+    VkQueueFamilyPropertiesList properties{
+        { VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, 1 }
+    };
+
+    queue_family_info::list list;
+
+    SECTION("no dedicated queues available") {
+        REQUIRE_FALSE(add_dedicated_queues(list, properties));
+
+        REQUIRE(verify_queues(list, properties) == queue_verify_result::empty_list);
+    }
+
+    SECTION("no more queues available") {
+        REQUIRE(add_queues(list, properties, VK_QUEUE_GRAPHICS_BIT, 1));
+        REQUIRE_FALSE(add_queues(list, properties, VK_QUEUE_COMPUTE_BIT, 1));
+
+        REQUIRE(verify_queues(list, properties) == queue_verify_result::ok);
+    }
 }