Compare commits
3 commits
bc02b924e2
...
5cee471f1f
Author | SHA1 | Date | |
---|---|---|---|
5cee471f1f | |||
7cca2bfbff | |||
a7dc666082 |
1 changed files with 282 additions and 13 deletions
|
@ -64,15 +64,107 @@ QueueFamilyIndices find_queue_families(VkPhysicalDevice device) {
|
||||||
return indices;
|
return indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<uint32_t> vulkan_find_memory_type(VkPhysicalDevice phys_dev,
|
||||||
|
uint32_t t_filter,
|
||||||
|
VkMemoryPropertyFlags props) {
|
||||||
|
VkPhysicalDeviceMemoryProperties mem_props;
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(phys_dev, &mem_props);
|
||||||
|
|
||||||
|
for (uint32_t idx = 0; idx < mem_props.memoryTypeCount; ++idx) {
|
||||||
|
if ((t_filter & (1 << idx)) &&
|
||||||
|
(mem_props.memoryTypes[idx].propertyFlags & props) == props) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool vulkan_create_buffer(VkDevice device, VkPhysicalDevice phys_dev,
|
||||||
|
VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
|
VkMemoryPropertyFlags props, VkBuffer &buf,
|
||||||
|
VkDeviceMemory &buf_mem) {
|
||||||
|
VkBufferCreateInfo buf_info{};
|
||||||
|
buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
buf_info.size = size;
|
||||||
|
buf_info.usage = usage;
|
||||||
|
buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
|
||||||
|
if (vkCreateBuffer(device, &buf_info, nullptr, &buf) != VK_SUCCESS) {
|
||||||
|
std::clog << "WARNING: Failed to create buffer!\n";
|
||||||
|
buf = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkMemoryRequirements mem_reqs;
|
||||||
|
vkGetBufferMemoryRequirements(device, buf, &mem_reqs);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo alloc_info{};
|
||||||
|
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
alloc_info.allocationSize = mem_reqs.size;
|
||||||
|
|
||||||
|
auto mem_type =
|
||||||
|
vulkan_find_memory_type(phys_dev, mem_reqs.memoryTypeBits, props);
|
||||||
|
if (!mem_type.has_value()) {
|
||||||
|
vkDestroyBuffer(device, buf, nullptr);
|
||||||
|
buf = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
alloc_info.memoryTypeIndex = mem_type.value();
|
||||||
|
|
||||||
|
if (vkAllocateMemory(device, &alloc_info, nullptr, &buf_mem) != VK_SUCCESS) {
|
||||||
|
std::clog << "WARNING: Failed to allocate buffer memory!\n";
|
||||||
|
vkDestroyBuffer(device, buf, nullptr);
|
||||||
|
buf = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
vkBindBufferMemory(device, buf, buf_mem, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vulkan_copy_buffer(VkDevice device, VkCommandPool command_pool,
|
||||||
|
VkQueue queue, VkBuffer src_buf, VkBuffer dst_buf,
|
||||||
|
VkDeviceSize size) {
|
||||||
|
VkCommandBufferAllocateInfo alloc_info{};
|
||||||
|
alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
alloc_info.commandPool = command_pool;
|
||||||
|
alloc_info.commandBufferCount = 1;
|
||||||
|
|
||||||
|
VkCommandBuffer command_buf;
|
||||||
|
vkAllocateCommandBuffers(device, &alloc_info, &command_buf);
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo begin_info{};
|
||||||
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
|
||||||
|
vkBeginCommandBuffer(command_buf, &begin_info);
|
||||||
|
|
||||||
|
VkBufferCopy copy_region{};
|
||||||
|
copy_region.size = size;
|
||||||
|
vkCmdCopyBuffer(command_buf, src_buf, dst_buf, 1, ©_region);
|
||||||
|
|
||||||
|
vkEndCommandBuffer(command_buf);
|
||||||
|
|
||||||
|
VkSubmitInfo submit_info{};
|
||||||
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submit_info.commandBufferCount = 1;
|
||||||
|
submit_info.pCommandBuffers = &command_buf;
|
||||||
|
|
||||||
|
vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||||
|
vkQueueWaitIdle(queue);
|
||||||
|
|
||||||
|
vkFreeCommandBuffers(device, command_pool, 1, &command_buf);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // DITHERING_VULKAN_ENABLED == 1
|
#endif // DITHERING_VULKAN_ENABLED == 1
|
||||||
|
|
||||||
#include "image.hpp"
|
#include "image.hpp"
|
||||||
|
|
||||||
image::Bl dither::blue_noise(int width, int height, int threads,
|
image::Bl dither::blue_noise(int width, int height, int threads,
|
||||||
bool use_opencl, bool use_vulkan) {
|
bool use_opencl, bool use_vulkan) {
|
||||||
bool using_opencl = false;
|
|
||||||
bool using_vulkan = false;
|
|
||||||
|
|
||||||
#if DITHERING_VULKAN_ENABLED == 1
|
#if DITHERING_VULKAN_ENABLED == 1
|
||||||
if (use_vulkan) {
|
if (use_vulkan) {
|
||||||
// Try to use Vulkan.
|
// Try to use Vulkan.
|
||||||
|
@ -428,6 +520,188 @@ image::Bl dither::blue_noise(int width, int height, int threads,
|
||||||
},
|
},
|
||||||
&compute_pipeline);
|
&compute_pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkCommandPool command_pool;
|
||||||
|
{
|
||||||
|
VkCommandPoolCreateInfo pool_info{};
|
||||||
|
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
|
pool_info.queueFamilyIndex = indices.computeFamily.value();
|
||||||
|
|
||||||
|
if (vkCreateCommandPool(device, &pool_info, nullptr, &command_pool) !=
|
||||||
|
VK_SUCCESS) {
|
||||||
|
std::clog << "WARNING: Failed to create vulkan command pool!\n";
|
||||||
|
goto ENDOF_VULKAN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
utility::Cleanup cleanup_command_pool(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkDestroyCommandPool(device, *((VkCommandPool *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&command_pool);
|
||||||
|
|
||||||
|
int filter_size = (width + height) / 2;
|
||||||
|
std::vector<float> precomputed = internal::precompute_gaussian(filter_size);
|
||||||
|
VkDeviceSize precomputed_size = sizeof(float) * precomputed.size();
|
||||||
|
VkDeviceSize filter_out_size = sizeof(float) * width * height;
|
||||||
|
VkDeviceSize pbp_size = sizeof(int) * width * height;
|
||||||
|
VkDeviceSize other_size = sizeof(int) * 3;
|
||||||
|
|
||||||
|
VkBuffer precomputed_buf;
|
||||||
|
VkDeviceMemory precomputed_buf_mem;
|
||||||
|
utility::Cleanup cleanup_precomputed_buf(utility::Cleanup::Nop{});
|
||||||
|
utility::Cleanup cleanup_precomputed_buf_mem(utility::Cleanup::Nop{});
|
||||||
|
{
|
||||||
|
VkBuffer staging_buffer;
|
||||||
|
VkDeviceMemory staging_buffer_mem;
|
||||||
|
|
||||||
|
if (!vulkan_create_buffer(device, phys_device, precomputed_size,
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
staging_buffer, staging_buffer_mem)) {
|
||||||
|
std::clog << "WARNING: Failed to create staging buffer!\n";
|
||||||
|
goto ENDOF_VULKAN;
|
||||||
|
}
|
||||||
|
utility::Cleanup cleanup_staging_buf(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkDestroyBuffer(device, *((VkBuffer *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&staging_buffer);
|
||||||
|
utility::Cleanup cleanup_staging_buf_mem(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkFreeMemory(device, *((VkDeviceMemory *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&staging_buffer_mem);
|
||||||
|
|
||||||
|
void *data_ptr;
|
||||||
|
vkMapMemory(device, staging_buffer_mem, 0, precomputed_size, 0,
|
||||||
|
&data_ptr);
|
||||||
|
std::memcpy(data_ptr, precomputed.data(), precomputed_size);
|
||||||
|
vkUnmapMemory(device, staging_buffer_mem);
|
||||||
|
|
||||||
|
if (!vulkan_create_buffer(device, phys_device, precomputed_size,
|
||||||
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
|
precomputed_buf, precomputed_buf_mem)) {
|
||||||
|
std::clog << "WARNING: Failed to create precomputed buffer!\n";
|
||||||
|
goto ENDOF_VULKAN;
|
||||||
|
}
|
||||||
|
cleanup_precomputed_buf = utility::Cleanup(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkDestroyBuffer(device, *((VkBuffer *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&precomputed_buf);
|
||||||
|
cleanup_precomputed_buf_mem = utility::Cleanup(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkFreeMemory(device, *((VkDeviceMemory *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&precomputed_buf_mem);
|
||||||
|
|
||||||
|
vulkan_copy_buffer(device, command_pool, compute_queue, staging_buffer,
|
||||||
|
precomputed_buf, precomputed_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBuffer filter_out_buf;
|
||||||
|
VkDeviceMemory filter_out_buf_mem;
|
||||||
|
if (!vulkan_create_buffer(device, phys_device, filter_out_size,
|
||||||
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
|
filter_out_buf, filter_out_buf_mem)) {
|
||||||
|
std::clog << "WARNING: Failed to create filter_out buffer!\n";
|
||||||
|
goto ENDOF_VULKAN;
|
||||||
|
}
|
||||||
|
utility::Cleanup cleanup_filter_out_buf(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkDestroyBuffer(device, *((VkBuffer *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&filter_out_buf);
|
||||||
|
utility::Cleanup cleanup_filter_out_buf_mem(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkFreeMemory(device, *((VkDeviceMemory *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&filter_out_buf_mem);
|
||||||
|
|
||||||
|
VkBuffer pbp_buf;
|
||||||
|
VkDeviceMemory pbp_buf_mem;
|
||||||
|
if (!vulkan_create_buffer(device, phys_device, pbp_size,
|
||||||
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, pbp_buf,
|
||||||
|
pbp_buf_mem)) {
|
||||||
|
std::clog << "WARNING: Failed to create pbp buffer!\n";
|
||||||
|
goto ENDOF_VULKAN;
|
||||||
|
}
|
||||||
|
utility::Cleanup cleanup_pbp_buf(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkDestroyBuffer(device, *((VkBuffer *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&pbp_buf);
|
||||||
|
utility::Cleanup cleanup_pbp_buf_mem(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkFreeMemory(device, *((VkDeviceMemory *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&pbp_buf_mem);
|
||||||
|
|
||||||
|
VkBuffer other_buf;
|
||||||
|
VkDeviceMemory other_buf_mem;
|
||||||
|
utility::Cleanup cleanup_other_buf(utility::Cleanup::Nop{});
|
||||||
|
utility::Cleanup cleanup_other_buf_mem(utility::Cleanup::Nop{});
|
||||||
|
{
|
||||||
|
VkBuffer staging_buffer;
|
||||||
|
VkDeviceMemory staging_buffer_mem;
|
||||||
|
|
||||||
|
if (!vulkan_create_buffer(device, phys_device, other_size,
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||||
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
staging_buffer, staging_buffer_mem)) {
|
||||||
|
std::clog << "WARNING: Failed to create staging buffer!\n";
|
||||||
|
goto ENDOF_VULKAN;
|
||||||
|
}
|
||||||
|
utility::Cleanup cleanup_staging_buf(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkDestroyBuffer(device, *((VkBuffer *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&staging_buffer);
|
||||||
|
utility::Cleanup cleanup_staging_buf_mem(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkFreeMemory(device, *((VkDeviceMemory *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&staging_buffer_mem);
|
||||||
|
|
||||||
|
void *data_ptr;
|
||||||
|
vkMapMemory(device, staging_buffer_mem, 0, other_size, 0, &data_ptr);
|
||||||
|
std::memcpy(data_ptr, &width, sizeof(int));
|
||||||
|
std::memcpy(((char *)data_ptr) + sizeof(int), &height, sizeof(int));
|
||||||
|
std::memcpy(((char *)data_ptr) + sizeof(int) * 2, &filter_size,
|
||||||
|
sizeof(int));
|
||||||
|
vkUnmapMemory(device, staging_buffer_mem);
|
||||||
|
|
||||||
|
if (!vulkan_create_buffer(device, phys_device, other_size,
|
||||||
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, other_buf,
|
||||||
|
other_buf_mem)) {
|
||||||
|
std::clog << "WARNING: Failed to create other buffer!\n";
|
||||||
|
goto ENDOF_VULKAN;
|
||||||
|
}
|
||||||
|
cleanup_other_buf = utility::Cleanup(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkDestroyBuffer(device, *((VkBuffer *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&other_buf);
|
||||||
|
cleanup_other_buf_mem = utility::Cleanup(
|
||||||
|
[device](void *ptr) {
|
||||||
|
vkFreeMemory(device, *((VkDeviceMemory *)ptr), nullptr);
|
||||||
|
},
|
||||||
|
&other_buf_mem);
|
||||||
|
|
||||||
|
vulkan_copy_buffer(device, command_pool, compute_queue, staging_buffer,
|
||||||
|
other_buf, other_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ENDOF_VULKAN:
|
ENDOF_VULKAN:
|
||||||
std::clog << "TODO: Remove this once Vulkan support is implemented.\n";
|
std::clog << "TODO: Remove this once Vulkan support is implemented.\n";
|
||||||
|
@ -525,16 +799,11 @@ ENDOF_VULKAN:
|
||||||
std::clog << "WARNING: Not compiled with OpenCL support!\n";
|
std::clog << "WARNING: Not compiled with OpenCL support!\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!using_opencl) {
|
std::cout << "Vulkan/OpenCL: Failed to setup/use or is not enabled, using "
|
||||||
std::cout << "OpenCL: Failed to setup/use or is not enabled, using "
|
|
||||||
"regular impl..."
|
"regular impl..."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return internal::rangeToBl(
|
return internal::rangeToBl(internal::blue_noise_impl(width, height, threads),
|
||||||
internal::blue_noise_impl(width, height, threads), width);
|
width);
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "ERROR: Invalid state (end of blue_noise fn)\n";
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned int> dither::internal::blue_noise_impl(int width,
|
std::vector<unsigned int> dither::internal::blue_noise_impl(int width,
|
||||||
|
|
Loading…
Reference in a new issue