#include "api_objects.h"
#include "util/optional.h"
#include <iostream>
+#include <type_traits>
+#include <vector>
+#include <algorithm>
namespace kazan
{
return std::make_unique<Vulkan_semaphore>();
}
-std::unique_ptr<Vulkan_image> Vulkan_image::create(Vulkan_device &device, const VkImageCreateInfo &create_info)
+VkResult Vulkan_fence::wait_multiple(std::uint32_t fence_count,
+ const VkFence *fences,
+ bool wait_for_all,
+ std::uint64_t timeout)
+{
+ if(fence_count == 0)
+ return VK_SUCCESS;
+ assert(fences);
+
+ typedef std::chrono::steady_clock::duration Duration;
+ typedef std::chrono::steady_clock::time_point Time_point;
+
+ // assume anything over 1000000 hours is
+ // infinite; 1000000 hours is about 114
+ // years, however, it's still way less than
+ // 2^63 nanoseconds, so we won't overflow
+ constexpr std::chrono::hours max_wait_time(1000000);
+ util::optional<Duration> wait_duration; // nullopt means infinite timeout
+ if(timeout <= static_cast<std::uint64_t>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(max_wait_time).count()))
+ {
+ wait_duration = std::chrono::duration_cast<Duration>(std::chrono::nanoseconds(timeout));
+ if(wait_duration->count() == 0 && timeout != 0)
+ wait_duration = Duration(1); // round up so we will sleep some
+ }
+ if(wait_duration && wait_duration->count() == 0)
+ {
+ bool found = false;
+ bool search_for = !wait_for_all;
+ for(std::uint32_t i = 0; i < fence_count; i++)
+ {
+ assert(fences[i]);
+ if(from_handle(fences[i])->is_signaled() == search_for)
+ {
+ found = true;
+ break;
+ }
+ }
+ if(found && wait_for_all)
+ return VK_TIMEOUT;
+ if(!found && !wait_for_all)
+ return VK_TIMEOUT;
+ return VK_SUCCESS;
+ }
+ auto start_time = std::chrono::steady_clock::now();
+ util::optional<Time_point> end_time; // nullopt means infinite timeout
+ if(wait_duration && (start_time.time_since_epoch().count() <= 0
+ || Duration::max() - start_time.time_since_epoch() >= *wait_duration))
+ end_time = start_time + *wait_duration;
+ Waiter waiter(wait_for_all ? fence_count : 1);
+ std::vector<std::list<Waiter *>::iterator> iters;
+ iters.reserve(fence_count);
+ struct Fence_cleanup
+ {
+ std::vector<std::list<Waiter *>::iterator> &iters;
+ const VkFence *fences;
+ ~Fence_cleanup()
+ {
+ for(std::uint32_t i = 0; i < iters.size(); i++)
+ {
+ auto *fence = from_handle(fences[i]);
+ assert(fence);
+ std::unique_lock<std::mutex> lock_it(fence->lock);
+ fence->waiters.erase(iters[i]);
+ }
+ }
+ } cleanup = {
+ .iters = iters, .fences = fences,
+ };
+ for(std::uint32_t i = 0; i < fence_count; i++)
+ {
+ auto *fence = from_handle(fences[i]);
+ assert(fence);
+ std::unique_lock<std::mutex> lock_it(fence->lock);
+ iters.push_back(fence->waiters.insert(fence->waiters.end(), &waiter));
+ if(fence->signaled)
+ waiter.notify(false);
+ }
+ assert(iters.size() == fence_count);
+ return waiter.wait(end_time) ? VK_SUCCESS : VK_TIMEOUT;
+}
+
+std::unique_ptr<Vulkan_fence> Vulkan_fence::create(Vulkan_device &device,
+ const VkFenceCreateInfo &create_info)
+{
+ assert(create_info.sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
+ assert((create_info.flags & ~VK_FENCE_CREATE_SIGNALED_BIT) == 0);
+ return std::make_unique<Vulkan_fence>(create_info.flags);
+}
+
+std::unique_ptr<Vulkan_image> Vulkan_image::create(Vulkan_device &device,
+ const VkImageCreateInfo &create_info)
{
#warning finish implementing Vulkan_image::create
return std::make_unique<Vulkan_image>();
}
+
+Vulkan_command_buffer::Vulkan_command_buffer(
+ std::list<std::unique_ptr<Vulkan_command_buffer>>::iterator iter,
+ Vulkan_command_pool &command_pool,
+ Vulkan_device &device) noexcept : iter(iter),
+ command_pool(command_pool),
+ device(device)
+{
+}
+
+void Vulkan_command_buffer::reset(VkCommandPoolResetFlags flags)
+{
+#warning finish implementing Vulkan_command_buffer::reset
+}
+
+void Vulkan_command_pool::allocate_multiple(Vulkan_device &device,
+ const VkCommandBufferAllocateInfo &allocate_info,
+ VkCommandBuffer *allocated_command_buffers)
+{
+ std::uint32_t command_buffer_count = allocate_info.commandBufferCount;
+ try
+ {
+ std::list<std::unique_ptr<Vulkan_command_buffer>> current_command_buffers;
+ for(std::uint32_t i = 0; i < command_buffer_count; i++)
+ {
+ auto iter = current_command_buffers.emplace(current_command_buffers.end());
+ auto command_buffer = std::make_unique<Vulkan_command_buffer>(iter, *this, device);
+ allocated_command_buffers[i] = to_handle(command_buffer.get());
+ *iter = std::move(command_buffer);
+ }
+ command_buffers.splice(command_buffers.end(), current_command_buffers);
+ }
+ catch(...)
+ {
+ for(std::uint32_t i = 0; i < command_buffer_count; i++)
+ allocated_command_buffers[i] = VK_NULL_HANDLE;
+ throw;
+ }
+}
+
+std::unique_ptr<Vulkan_command_pool> Vulkan_command_pool::create(
+ Vulkan_device &device, const VkCommandPoolCreateInfo &create_info)
+{
+ assert(create_info.sType == VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO);
+ assert(create_info.queueFamilyIndex < Vulkan_physical_device::queue_family_property_count);
+ assert((create_info.flags
+ & ~(VK_COMMAND_POOL_CREATE_TRANSIENT_BIT
+ | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT))
+ == 0);
+ return std::make_unique<Vulkan_command_pool>();
+}
}
}
#include "util/variant.h"
#include "util/system_memory_info.h"
#include "util/constexpr_array.h"
+#include "util/optional.h"
#include <memory>
#include <cassert>
#include <chrono>
#include <limits>
+#include <vector>
+#include <list>
+#include <mutex>
+#include <condition_variable>
+#include <chrono>
namespace kazan
{
const VkSemaphoreCreateInfo &create_info);
};
+class Vulkan_fence : public Vulkan_nondispatchable_object<Vulkan_fence, VkFence>
+{
+private:
+ struct Waiter
+ {
+ std::mutex lock;
+ std::condition_variable cond;
+ std::uint32_t wait_count;
+ explicit Waiter(std::uint32_t wait_count) : lock(), cond(), wait_count(wait_count)
+ {
+ }
+ void notify(bool notify_condition_variable)
+ {
+ std::unique_lock<std::mutex> lock_it(lock);
+ if(wait_count != 0)
+ {
+ wait_count--;
+ if(notify_condition_variable && wait_count == 0)
+ cond.notify_all();
+ }
+ }
+ bool wait(util::optional<std::chrono::steady_clock::time_point> end_time)
+ {
+ std::unique_lock<std::mutex> lock_it(lock);
+ while(wait_count != 0)
+ {
+ if(end_time)
+ cond.wait_until(lock_it, *end_time);
+ else
+ cond.wait(lock_it);
+ }
+ return wait_count == 0;
+ }
+ };
+
+private:
+ std::mutex lock;
+ bool signaled;
+ std::list<Waiter *> waiters;
+
+public:
+ explicit Vulkan_fence(VkFenceCreateFlags flags)
+ : lock(), signaled(flags & VK_FENCE_CREATE_SIGNALED_BIT), waiters()
+ {
+ }
+ bool is_signaled()
+ {
+ std::unique_lock<std::mutex> lock_it(lock);
+ return signaled;
+ }
+ void set_signaled(bool new_signaled)
+ {
+ std::unique_lock<std::mutex> lock_it(lock);
+ if(signaled == new_signaled)
+ return;
+ signaled = new_signaled;
+ if(new_signaled)
+ {
+ for(auto *waiter : waiters)
+ waiter->notify(true);
+ }
+ }
+ void signal()
+ {
+ set_signaled(true);
+ }
+ void reset()
+ {
+ set_signaled(false);
+ }
+ static VkResult wait_multiple(std::uint32_t fence_count,
+ const VkFence *fences,
+ bool wait_for_all,
+ std::uint64_t timeout);
+ static std::unique_ptr<Vulkan_fence> create(Vulkan_device &device,
+ const VkFenceCreateInfo &create_info);
+};
+
struct Vulkan_image : public Vulkan_nondispatchable_object<Vulkan_image, VkImage>
{
virtual ~Vulkan_image() = default;
static std::unique_ptr<Vulkan_image> create(Vulkan_device &device,
const VkImageCreateInfo &create_info);
};
+
+struct Vulkan_command_pool;
+
+struct Vulkan_command_buffer
+ : public Vulkan_dispatchable_object<Vulkan_command_buffer, VkCommandBuffer>
+{
+ std::list<std::unique_ptr<Vulkan_command_buffer>>::iterator iter;
+ Vulkan_command_pool &command_pool;
+ Vulkan_device &device;
+ Vulkan_command_buffer(std::list<std::unique_ptr<Vulkan_command_buffer>>::iterator iter,
+ Vulkan_command_pool &command_pool,
+ Vulkan_device &device) noexcept;
+ void reset(VkCommandPoolResetFlags flags);
+#warning finish implementing Vulkan_command_buffer
+};
+
+struct Vulkan_command_pool
+ : public Vulkan_nondispatchable_object<Vulkan_command_pool, VkCommandPool>
+{
+ std::list<std::unique_ptr<Vulkan_command_buffer>> command_buffers;
+ void reset(VkCommandPoolResetFlags flags)
+ {
+ for(auto &command_buffer : command_buffers)
+ command_buffer->reset(flags);
+ }
+ void allocate_multiple(Vulkan_device &device,
+ const VkCommandBufferAllocateInfo &allocate_info,
+ VkCommandBuffer *allocated_command_buffers);
+ void free_command_buffer(VkCommandBuffer command_buffer_handle) noexcept
+ {
+ if(!command_buffer_handle)
+ return;
+ auto *command_buffer = Vulkan_command_buffer::from_handle(command_buffer_handle);
+ assert(&command_buffer->command_pool == this);
+ command_buffers.erase(command_buffer->iter);
+ }
+ void free_multiple(const VkCommandBuffer *allocated_command_buffers,
+ std::uint32_t command_buffer_count) noexcept
+ {
+ for(std::uint32_t i = 0; i < command_buffer_count; i++)
+ free_command_buffer(allocated_command_buffers[i]);
+ }
+ static std::unique_ptr<Vulkan_command_pool> create(Vulkan_device &device,
+ const VkCommandPoolCreateInfo &create_info);
+};
}
}
}
extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence(VkDevice device,
- const VkFenceCreateInfo *pCreateInfo,
+ const VkFenceCreateInfo *create_info,
const VkAllocationCallbacks *allocator,
- VkFence *pFence)
+ VkFence *fence)
{
validate_allocator(allocator);
-#warning finish implementing vkCreateFence
- assert(!"vkCreateFence is not implemented");
+ assert(device);
+ assert(create_info);
+ assert(fence);
+ return vulkan_icd::catch_exceptions_and_return_result(
+ [&]()
+ {
+ auto create_result = vulkan::Vulkan_fence::create(
+ *vulkan::Vulkan_device::from_handle(device), *create_info);
+ *fence = move_to_handle(std::move(create_result));
+ return VK_SUCCESS;
+ });
}
extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroyFence(VkDevice device,
const VkAllocationCallbacks *allocator)
{
validate_allocator(allocator);
-#warning finish implementing vkDestroyFence
- assert(!"vkDestroyFence is not implemented");
+ assert(device);
+ vulkan::Vulkan_fence::move_from_handle(fence).reset();
}
extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(VkDevice device,
- uint32_t fenceCount,
- const VkFence *pFences)
+ uint32_t fence_count,
+ const VkFence *fences)
{
-#warning finish implementing vkResetFences
- assert(!"vkResetFences is not implemented");
+ assert(device);
+ assert(fences);
+ return vulkan_icd::catch_exceptions_and_return_result(
+ [&]()
+ {
+ for(std::uint32_t i = 0; i < fence_count; i++)
+ vulkan::Vulkan_fence::from_handle(fences[i])->reset();
+ return VK_SUCCESS;
+ });
}
extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence)
{
-#warning finish implementing vkGetFenceStatus
- assert(!"vkGetFenceStatus is not implemented");
+ assert(device);
+ assert(fence);
+ return vulkan_icd::catch_exceptions_and_return_result(
+ [&]()
+ {
+ return vulkan::Vulkan_fence::from_handle(fence)->is_signaled() ? VK_SUCCESS :
+ VK_NOT_READY;
+ });
}
extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences(VkDevice device,
- uint32_t fenceCount,
- const VkFence *pFences,
- VkBool32 waitAll,
+ uint32_t fence_count,
+ const VkFence *fences,
+ VkBool32 wait_all,
uint64_t timeout)
{
-#warning finish implementing vkWaitForFences
- assert(!"vkWaitForFences is not implemented");
+ assert(device);
+ assert(fences);
+ return vulkan_icd::catch_exceptions_and_return_result(
+ [&]()
+ {
+ return vulkan::Vulkan_fence::wait_multiple(fence_count, fences, wait_all, timeout);
+ });
}
extern "C" VKAPI_ATTR VkResult VKAPI_CALL
extern "C" VKAPI_ATTR VkResult VKAPI_CALL
vkCreateCommandPool(VkDevice device,
- const VkCommandPoolCreateInfo *pCreateInfo,
+ const VkCommandPoolCreateInfo *create_info,
const VkAllocationCallbacks *allocator,
- VkCommandPool *pCommandPool)
+ VkCommandPool *command_pool)
{
validate_allocator(allocator);
-#warning finish implementing vkCreateCommandPool
- assert(!"vkCreateCommandPool is not implemented");
+ assert(device);
+ assert(create_info);
+ assert(command_pool);
+ return vulkan_icd::catch_exceptions_and_return_result(
+ [&]()
+ {
+ auto create_result = vulkan::Vulkan_command_pool::create(
+ *vulkan::Vulkan_device::from_handle(device), *create_info);
+ *command_pool = move_to_handle(std::move(create_result));
+ return VK_SUCCESS;
+ });
}
extern "C" VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool(VkDevice device,
- VkCommandPool commandPool,
+ VkCommandPool command_pool,
const VkAllocationCallbacks *allocator)
{
validate_allocator(allocator);
-#warning finish implementing vkDestroyCommandPool
- assert(!"vkDestroyCommandPool is not implemented");
+ assert(device);
+ assert(command_pool);
+ vulkan::Vulkan_command_pool::move_from_handle(command_pool).reset();
}
extern "C" VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool(VkDevice device,
- VkCommandPool commandPool,
+ VkCommandPool command_pool,
VkCommandPoolResetFlags flags)
{
-#warning finish implementing vkResetCommandPool
- assert(!"vkResetCommandPool is not implemented");
+ assert(device);
+ assert(command_pool);
+ return vulkan_icd::catch_exceptions_and_return_result(
+ [&]()
+ {
+ vulkan::Vulkan_command_pool::from_handle(command_pool)->reset(flags);
+ return VK_SUCCESS;
+ });
}
extern "C" VKAPI_ATTR VkResult VKAPI_CALL
vkAllocateCommandBuffers(VkDevice device,
- const VkCommandBufferAllocateInfo *pAllocateInfo,
- VkCommandBuffer *pCommandBuffers)
+ const VkCommandBufferAllocateInfo *allocate_info,
+ VkCommandBuffer *command_buffers)
{
-#warning finish implementing vkAllocateCommandBuffers
- assert(!"vkAllocateCommandBuffers is not implemented");
+ assert(device);
+ assert(allocate_info);
+ assert(command_buffers);
+ return vulkan_icd::catch_exceptions_and_return_result(
+ [&]()
+ {
+ vulkan::Vulkan_command_pool::from_handle(allocate_info->commandPool)
+ ->allocate_multiple(
+ *vulkan::Vulkan_device::from_handle(device), *allocate_info, command_buffers);
+ return VK_SUCCESS;
+ });
}
extern "C" VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device,
- VkCommandPool commandPool,
- uint32_t commandBufferCount,
- const VkCommandBuffer *pCommandBuffers)
+ VkCommandPool command_pool,
+ uint32_t command_buffer_count,
+ const VkCommandBuffer *command_buffers)
{
-#warning finish implementing vkFreeCommandBuffers
- assert(!"vkFreeCommandBuffers is not implemented");
+ assert(device);
+ assert(command_pool);
+ assert(command_buffers);
+ vulkan::Vulkan_command_pool::from_handle(command_pool)
+ ->free_multiple(command_buffers, command_buffer_count);
}
extern "C" VKAPI_ATTR VkResult VKAPI_CALL
VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR,
};
VkSurfaceCapabilitiesKHR capabilities = {
- .minImageCount = 1,
+ .minImageCount = 2,
.maxImageCount = 0,
.currentExtent =
{
window(window),
shm_is_supported(start_setup_results.shm_is_supported)
{
+ assert(create_info.sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
+#warning formats other than VK_FORMAT_B8G8R8A8_UNORM are unimplemented
+ assert(create_info.imageFormat == VK_FORMAT_B8G8R8A8_UNORM);
+ assert(create_info.imageColorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR);
+ assert(create_info.imageExtent.width == start_setup_results.image_width);
+ assert(create_info.imageExtent.height == start_setup_results.image_height);
+ assert(create_info.imageArrayLayers
+ <= start_setup_results.capabilities.maxImageArrayLayers);
+ assert(create_info.imageArrayLayers != 0);
+ assert((create_info.imageUsage & ~start_setup_results.capabilities.supportedUsageFlags)
+ == 0);
+ assert(create_info.preTransform == start_setup_results.capabilities.currentTransform);
+ assert((create_info.compositeAlpha
+ & ~start_setup_results.capabilities.supportedCompositeAlpha)
+ == 0);
+ const char *warning_message_present_mode_name = nullptr;
+ switch(create_info.presentMode)
+ {
+ case VK_PRESENT_MODE_IMMEDIATE_KHR:
+ break;
+ case VK_PRESENT_MODE_FIFO_KHR:
+ warning_message_present_mode_name = "FIFO";
+ break;
+ case VK_PRESENT_MODE_MAILBOX_KHR:
+ warning_message_present_mode_name = "MAILBOX";
+ break;
+ case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
+ warning_message_present_mode_name = "FIFO_RELAXED";
+ break;
+ case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR:
+ case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR:
+ case VK_PRESENT_MODE_RANGE_SIZE_KHR:
+ case VK_PRESENT_MODE_MAX_ENUM_KHR:
+ assert(!"bad present mode");
+ break;
+ }
+ if(warning_message_present_mode_name)
+ std::cerr << warning_message_present_mode_name
+ << " present mode is not implemented; falling back to IMMEDIATE"
+ << std::endl;
std::size_t unpadded_scanline_size =
start_setup_results.image_pixel_size * start_setup_results.image_width;
std::size_t padded_scanline_size =
switch(start_setup_result.surface_format_group)
{
case Implementation::Surface_format_group::B8G8R8A8:
- surface_formats = {
+ surface_formats =
+ {
+#if 1
+#warning implement VK_FORMAT_B8G8R8A8_SRGB
+#else
{
.format = VK_FORMAT_B8G8R8A8_SRGB,
.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
},
+#endif
{
.format = VK_FORMAT_B8G8R8A8_UNORM,
.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,