diff --git a/README.md b/README.md
index e87cc530b892428e7b66c2d2604fa6db5a6e69e2..cfb0ae4b55a8579f371c676373f81fbd57ebc85a 100644
--- a/README.md
+++ b/README.md
@@ -163,7 +163,7 @@ auto build_cmd_bufs = [&]() {
         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
         .queueFamilyIndex = device->get_graphics_queue().family_index,
     };
-    if (!device->vkCreateCommandPool(&create_info, memory::alloc(), &cmd_pool))
+    if (!device->vkCreateCommandPool(&create_info, &cmd_pool))
         return false;
 
     VkCommandBufferAllocateInfo alloc_info
@@ -224,7 +224,7 @@ auto build_cmd_bufs = [&]() {
 auto clean_cmd_bufs = [&]() {
 
     device->vkFreeCommandBuffers(cmd_pool, frame_count, cmd_bufs.data());
-    device->vkDestroyCommandPool(cmd_pool, memory::alloc());
+    device->vkDestroyCommandPool(cmd_pool);
 };
 
 build_cmd_bufs();
diff --git a/liblava/base/device.cpp b/liblava/base/device.cpp
index 439e85c0af1c9685fe17e696d1647899d79b9d7b..81b4c21ca19078aba4d3783be10b9a19b4c55746 100644
--- a/liblava/base/device.cpp
+++ b/liblava/base/device.cpp
@@ -208,7 +208,7 @@ VkShaderModule lava::create_shader_module(device* device, data const& data) {
     };
 
     VkShaderModule result;
-    if (!device->vkCreateShaderModule(&shader_module_create_info, memory::alloc(), &result))
+    if (!device->vkCreateShaderModule(&shader_module_create_info, &result))
         return nullptr;
 
     return result;
diff --git a/liblava/base/device.hpp b/liblava/base/device.hpp
index 502202fd5c55529cfbc0e6e16053b89bbc0b9de7..2077af611e80878ed7355de5ad63958478f3364f 100644
--- a/liblava/base/device.hpp
+++ b/liblava/base/device.hpp
@@ -12,85 +12,7 @@ namespace lava {
 // fwd
 struct physical_device;
 
-struct device : no_copy_no_move {
-
-    using ptr = std::shared_ptr<device>;
-    using list = std::vector<device::ptr>;
-
-    struct create_param {
-
-        const physical_device* _physical_device = nullptr;
-
-        struct queue_info {
-
-            using list = std::vector<queue_info>;
-
-            VkQueueFlags flags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
-
-            using priority_list = std::vector<float>;
-            priority_list priorities;
-
-            ui32 count() const { return to_ui32(priorities.size()); }
-
-            explicit queue_info(ui32 count = 1) {
-
-                for (auto i = 0u; i < count; ++i)
-                    priorities.push_back(1.f);
-            }
-        };
-
-        queue_info::list queue_info_list;
-
-        names extensions;
-
-        void set_default_queues() {
-
-            extensions.push_back("VK_KHR_swapchain");
-            queue_info_list.resize(1);
-        }
-    };
-
-    ~device();
-
-    bool create(create_param const& param);
-    void destroy();
-
-    struct queue {
-
-        using list = std::vector<queue>;
-        using ref = queue const&;
-
-        VkQueue vk_queue = nullptr;
-        ui32 family_index = 0;
-    };
-
-    queue::ref get_graphics_queue(ui32 index = 0) const { return get_graphics_queues().at(index); }
-    queue::ref get_compute_queue(ui32 index = 0) const { return get_compute_queues().at(index); }
-    queue::ref get_transfer_queue(ui32 index = 0) const { return get_transfer_queues().at(index); }
-
-    queue::list const& get_graphics_queues() const { return graphics_queues; }
-    queue::list const& get_compute_queues() const { return compute_queues; }
-    queue::list const& get_transfer_queues() const { return transfer_queues; }
-
-    VkDevice get() const { return vk_device; }
-    VolkDeviceTable const& call() const { return table; }
-
-    bool wait_for_idle() const { return check(call().vkDeviceWaitIdle(vk_device)); }
-
-    VkDescriptorPool get_descriptor_pool() const { return descriptor_pool; }
-
-    physical_device const* get_physical_device() const { return _physical_device; }
-    VkPhysicalDevice get_vk_physical_device() const;
-
-    VkPhysicalDeviceFeatures const& get_features() const;
-    VkPhysicalDeviceProperties const& get_properties() const;
-
-    bool is_surface_supported(VkSurfaceKHR surface) const;
-
-    void set_allocator(allocator::ptr value) { _allocator = value; }
-    allocator::ptr get_allocator() { return _allocator; }
-
-    VmaAllocator alloc() const { return _allocator != nullptr ? _allocator->get() : nullptr; }
+struct device_table {
 
     vk_result vkCreateImageView(const VkImageViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkImageView* pView) {
 
@@ -98,30 +20,55 @@ struct device : no_copy_no_move {
         return { check(result), result };
     }
 
+    vk_result vkCreateImageView(const VkImageViewCreateInfo* pCreateInfo, VkImageView* pView) {
+
+        return vkCreateImageView(pCreateInfo, memory::alloc(), pView);
+    }
+
     vk_result vkCreateSampler(const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler) {
 
         auto result = table.vkCreateSampler(vk_device, pCreateInfo, pAllocator, pSampler);
         return { check(result), result };
     }
 
+    vk_result vkCreateSampler(const VkSamplerCreateInfo* pCreateInfo, VkSampler* pSampler) {
+
+        return vkCreateSampler(pCreateInfo, memory::alloc(), pSampler);
+    }
+
     vk_result vkCreateShaderModule(const VkShaderModuleCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkShaderModule* pShaderModule) {
 
         auto result = table.vkCreateShaderModule(vk_device, pCreateInfo, pAllocator, pShaderModule);
         return { check(result), result };
     }
 
+    vk_result vkCreateShaderModule(const VkShaderModuleCreateInfo* pCreateInfo, VkShaderModule* pShaderModule) {
+
+        return vkCreateShaderModule(pCreateInfo, memory::alloc(), pShaderModule);
+    }
+
     vk_result vkCreateFence(const VkFenceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence) {
 
         auto result = table.vkCreateFence(vk_device, pCreateInfo, pAllocator, pFence);
         return { check(result), result };
     }
 
+    vk_result vkCreateFence(const VkFenceCreateInfo* pCreateInfo, VkFence* pFence) {
+
+        return vkCreateFence(pCreateInfo, memory::alloc(), pFence);
+    }
+
     vk_result vkCreateSemaphore(const VkSemaphoreCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSemaphore* pSemaphore) {
 
         auto result = table.vkCreateSemaphore(vk_device, pCreateInfo, pAllocator, pSemaphore);
         return { check(result), result };
     }
 
+    vk_result vkCreateSemaphore(const VkSemaphoreCreateInfo* pCreateInfo, VkSemaphore* pSemaphore) {
+
+        return vkCreateSemaphore(pCreateInfo, memory::alloc(), pSemaphore);
+    }
+
     vk_result vkWaitForFences(uint32_t fenceCount, const VkFence* pFences, VkBool32 waitAll, uint64_t timeout) {
 
         auto result = table.vkWaitForFences(vk_device, fenceCount, pFences, waitAll, timeout);
@@ -158,6 +105,11 @@ struct device : no_copy_no_move {
         return { check(result), result };
     }
 
+    vk_result vkCreateSwapchainKHR(const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain) {
+
+        return vkCreateSwapchainKHR(pCreateInfo, memory::alloc(), pSwapchain);
+    }
+
     vk_result vkGetSwapchainImagesKHR(VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) {
 
         auto result = table.vkGetSwapchainImagesKHR(vk_device, swapchain, pSwapchainImageCount, pSwapchainImages);
@@ -170,28 +122,33 @@ struct device : no_copy_no_move {
         return { check(result), result };
     }
 
+    vk_result vkCreateCommandPool(const VkCommandPoolCreateInfo* pCreateInfo, VkCommandPool* pCommandPool) {
+
+        return vkCreateCommandPool(pCreateInfo, memory::alloc(), pCommandPool);
+    }
+
     vk_result vkAllocateCommandBuffers(const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers) {
 
         auto result = table.vkAllocateCommandBuffers(vk_device, pAllocateInfo, pCommandBuffers);
         return { check(result), result };
     }
 
-    void vkDestroyImageView(VkImageView imageView, const VkAllocationCallbacks* pAllocator) {
+    void vkDestroyImageView(VkImageView imageView, const VkAllocationCallbacks* pAllocator = memory::alloc()) {
 
         table.vkDestroyImageView(vk_device, imageView, pAllocator);
     }
 
-    void vkDestroyFence(VkFence fence, const VkAllocationCallbacks* pAllocator) {
+    void vkDestroyFence(VkFence fence, const VkAllocationCallbacks* pAllocator = memory::alloc()) {
 
         table.vkDestroyFence(vk_device, fence, pAllocator);
     }
 
-    void vkDestroySemaphore(VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator) {
+    void vkDestroySemaphore(VkSemaphore semaphore, const VkAllocationCallbacks* pAllocator = memory::alloc()) {
 
         table.vkDestroySemaphore(vk_device, semaphore, pAllocator);
     }
 
-    void vkDestroySwapchainKHR(VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) {
+    void vkDestroySwapchainKHR(VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator = memory::alloc()) {
 
         table.vkDestroySwapchainKHR(vk_device, swapchain, pAllocator);
     }
@@ -201,19 +158,105 @@ struct device : no_copy_no_move {
         table.vkFreeCommandBuffers(vk_device, commandPool, commandBufferCount, pCommandBuffers);
     }
 
-    void vkDestroyCommandPool(VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator) {
+    void vkDestroyCommandPool(VkCommandPool commandPool, const VkAllocationCallbacks* pAllocator = memory::alloc()) {
 
         table.vkDestroyCommandPool(vk_device, commandPool, pAllocator);
     }
 
+    void vkDestroySampler(VkSampler sampler, const VkAllocationCallbacks* pAllocator = memory::alloc()) {
+
+        table.vkDestroySampler(vk_device, sampler, pAllocator);
+    }
+
+    VkDevice vk_device = nullptr;
+    VolkDeviceTable table = {};
+};
+
+struct device : device_table, no_copy_no_move {
+
+    using ptr = std::shared_ptr<device>;
+    using list = std::vector<device::ptr>;
+
+    struct create_param {
+
+        const physical_device* _physical_device = nullptr;
+
+        struct queue_info {
+
+            using list = std::vector<queue_info>;
+
+            VkQueueFlags flags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
+
+            using priority_list = std::vector<float>;
+            priority_list priorities;
+
+            ui32 count() const { return to_ui32(priorities.size()); }
+
+            explicit queue_info(ui32 count = 1) {
+
+                for (auto i = 0u; i < count; ++i)
+                    priorities.push_back(1.f);
+            }
+        };
+
+        queue_info::list queue_info_list;
+
+        names extensions;
+
+        void set_default_queues() {
+
+            extensions.push_back("VK_KHR_swapchain");
+            queue_info_list.resize(1);
+        }
+    };
+
+    ~device();
+
+    bool create(create_param const& param);
+    void destroy();
+
+    struct queue {
+
+        using list = std::vector<queue>;
+        using ref = queue const&;
+
+        VkQueue vk_queue = nullptr;
+        ui32 family_index = 0;
+    };
+
+    queue::ref get_graphics_queue(ui32 index = 0) const { return get_graphics_queues().at(index); }
+    queue::ref get_compute_queue(ui32 index = 0) const { return get_compute_queues().at(index); }
+    queue::ref get_transfer_queue(ui32 index = 0) const { return get_transfer_queues().at(index); }
+
+    queue::list const& get_graphics_queues() const { return graphics_queues; }
+    queue::list const& get_compute_queues() const { return compute_queues; }
+    queue::list const& get_transfer_queues() const { return transfer_queues; }
+
+    VkDevice get() const { return vk_device; }
+    VolkDeviceTable const& call() const { return table; }
+
+    bool wait_for_idle() const { return check(call().vkDeviceWaitIdle(vk_device)); }
+
+    VkDescriptorPool get_descriptor_pool() const { return descriptor_pool; }
+
+    physical_device const* get_physical_device() const { return _physical_device; }
+    VkPhysicalDevice get_vk_physical_device() const;
+
+    VkPhysicalDeviceFeatures const& get_features() const;
+    VkPhysicalDeviceProperties const& get_properties() const;
+
+    bool is_surface_supported(VkSurfaceKHR surface) const;
+
+    void set_allocator(allocator::ptr value) { _allocator = value; }
+    allocator::ptr get_allocator() { return _allocator; }
+
+    VmaAllocator alloc() const { return _allocator != nullptr ? _allocator->get() : nullptr; }
+
 private:
     bool create_descriptor_pool();
 
-    VkDevice vk_device = nullptr;
     physical_device const* _physical_device = nullptr;
 
-    VolkDeviceTable table = {};
-
     VkDescriptorPool descriptor_pool = nullptr;
 
     queue::list graphics_queues;
diff --git a/liblava/frame/renderer.cpp b/liblava/frame/renderer.cpp
index a24566bf2df776dcc581c19964612be4a77c12dd..1287455423889f3443979437fe378b7606cbbc7f 100644
--- a/liblava/frame/renderer.cpp
+++ b/liblava/frame/renderer.cpp
@@ -29,7 +29,7 @@ bool renderer::create(swapchain* target_) {
                 .flags = VK_FENCE_CREATE_SIGNALED_BIT,
             };
 
-            if (!dev->vkCreateFence(&create_info, memory::alloc(), &fences[i]))
+            if (!dev->vkCreateFence(&create_info, &fences[i]))
                 return false;
         }
 
@@ -39,10 +39,10 @@ bool renderer::create(swapchain* target_) {
                 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
             };
 
-            if (!dev->vkCreateSemaphore(&create_info, memory::alloc(), &image_acquired_semaphores[i]))
+            if (!dev->vkCreateSemaphore(&create_info, &image_acquired_semaphores[i]))
                 return false;
 
-            if (!dev->vkCreateSemaphore(&create_info, memory::alloc(), &render_complete_semaphores[i]))
+            if (!dev->vkCreateSemaphore(&create_info, &render_complete_semaphores[i]))
                 return false;
         }
     }
@@ -57,9 +57,9 @@ void renderer::destroy() {
 
     for (auto i = 0u; i < queued_frames; ++i) {
 
-        dev->vkDestroyFence(fences[i], memory::alloc());
-        dev->vkDestroySemaphore(image_acquired_semaphores[i], memory::alloc());
-        dev->vkDestroySemaphore(render_complete_semaphores[i], memory::alloc());
+        dev->vkDestroyFence(fences[i]);
+        dev->vkDestroySemaphore(image_acquired_semaphores[i]);
+        dev->vkDestroySemaphore(render_complete_semaphores[i]);
     }
 
     fences.clear();
@@ -110,7 +110,7 @@ std::optional<index> renderer::begin_frame() {
     if (!dev->vkResetFences(to_ui32(wait_fences.size()), wait_fences.data()))
         return {};
 
-    return get_current_frame();
+    return get_frame();
 }
 
 bool renderer::end_frame(VkCommandBuffers const& cmd_buffers) {
diff --git a/liblava/frame/renderer.hpp b/liblava/frame/renderer.hpp
index 69d21bbcf39e48ec7bdb8880e784e57b826fd2d9..4393e9235ee3ee51013ef4d9540c9ebbf81f7436 100644
--- a/liblava/frame/renderer.hpp
+++ b/liblava/frame/renderer.hpp
@@ -26,7 +26,7 @@ struct renderer {
         return end_frame(cmd_buffers);
     }
 
-    index get_current_frame() const { return frame_index; }
+    index get_frame() const { return frame_index; }
 
     using destroy_func = std::function<void()>;
     destroy_func on_destroy;
diff --git a/liblava/frame/swapchain.cpp b/liblava/frame/swapchain.cpp
index e168a721a22630fc9741bf052376729fe89b23ce..ee45b63f910768a9e3bb263189c9b3e862a999ce 100644
--- a/liblava/frame/swapchain.cpp
+++ b/liblava/frame/swapchain.cpp
@@ -181,7 +181,7 @@ bool swapchain::create_internal() {
 
     info.preTransform = cap.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : cap.currentTransform;
 
-    if (!dev->vkCreateSwapchainKHR(&info, memory::alloc(), &vk_swapchain))
+    if (!dev->vkCreateSwapchainKHR(&info,  &vk_swapchain))
         return false;
 
     auto backbuffer_count = 0u;
@@ -211,7 +211,7 @@ bool swapchain::create_internal() {
     }
 
     if (old_swapchain)
-        dev->vkDestroySwapchainKHR(old_swapchain, memory::alloc());
+        dev->vkDestroySwapchainKHR(old_swapchain);
 
     return true;
 }
@@ -221,7 +221,7 @@ void swapchain::destroy_internal() {
     if (!vk_swapchain)
         return;
 
-    dev->vkDestroySwapchainKHR(vk_swapchain, memory::alloc());
+    dev->vkDestroySwapchainKHR(vk_swapchain);
     vk_swapchain = nullptr;
 }
 
diff --git a/liblava/resource/image.cpp b/liblava/resource/image.cpp
index 6c12cd39cc97997ff8a4dfd648869549248e57b9..c15672d58b924445d5136cbd67350a4204f5c99b 100644
--- a/liblava/resource/image.cpp
+++ b/liblava/resource/image.cpp
@@ -86,14 +86,14 @@ bool image::create(device* device, uv2 size, VmaMemoryUsage memory_usage, bool m
     view_info.image = vk_image;
     view_info.subresourceRange = subresource_range;
 
-    return device->vkCreateImageView(&view_info, memory::alloc(), &view);
+    return device->vkCreateImageView(&view_info, &view);
 }
 
 void image::destroy(bool only_view) {
 
     if (view) {
 
-        dev->vkDestroyImageView(view, memory::alloc());
+        dev->vkDestroyImageView(view);
         view = nullptr;
     }
 
diff --git a/liblava/resource/texture.cpp b/liblava/resource/texture.cpp
index c6a33faf8a26a44eb31d7e4b3e24a1eeafc84791..035bd5a435ee4bfa5f67310d4f80d29d4bf7a9bb 100644
--- a/liblava/resource/texture.cpp
+++ b/liblava/resource/texture.cpp
@@ -87,7 +87,7 @@ bool texture::create(device* device, uv2 size, VkFormat format, layer::list cons
     };
 
 
-    if (!device->vkCreateSampler(&sampler_info, memory::alloc(), &sampler)) {
+    if (!device->vkCreateSampler(&sampler_info, &sampler)) {
 
         log()->error("texture create vkCreateSampler failed");
         return false;
@@ -137,7 +137,7 @@ void texture::destroy() {
     if (sampler) {
 
         if (device)
-            device->call().vkDestroySampler(device->get(), sampler, memory::alloc());
+            device->vkDestroySampler(sampler);
 
         sampler = nullptr;
     }
@@ -156,9 +156,9 @@ void texture::destroy_upload_buffer() {
 
 bool texture::upload(void const* data, size_t data_size) {
 
-    auto device = _image->get_device();
     upload_buffer = buffer::make();
-    return upload_buffer->create(device, data, data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, false, VMA_MEMORY_USAGE_CPU_TO_GPU);
+
+    return upload_buffer->create(_image->get_device(), data, data_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, false, VMA_MEMORY_USAGE_CPU_TO_GPU);
 }
 
 bool texture::stage(VkCommandBuffer cmd_buffer) {
diff --git a/tests/tests.cpp b/tests/tests.cpp
index 2101c5afdc868ec70627f262c95fd3164e1e73d3..ac1194fe90e27220682b4e600ee966352bb2881a 100644
--- a/tests/tests.cpp
+++ b/tests/tests.cpp
@@ -112,7 +112,7 @@ LAVA_TEST(4, "clear color")
             .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
             .queueFamilyIndex = device->get_graphics_queue().family_index,
         };
-        if (!device->vkCreateCommandPool(&create_info, memory::alloc(), &cmd_pool))
+        if (!device->vkCreateCommandPool(&create_info, &cmd_pool))
             return false;
 
         VkCommandBufferAllocateInfo alloc_info
@@ -170,7 +170,7 @@ LAVA_TEST(4, "clear color")
     auto clean_cmd_bufs = [&]() {
 
         device->vkFreeCommandBuffers(cmd_pool, frame_count, cmd_bufs.data());
-        device->vkDestroyCommandPool(cmd_pool, memory::alloc());
+        device->vkDestroyCommandPool(cmd_pool);
     };
 
     if (!build_cmd_bufs())