Begin work on Vulkan compute (WIP)

Some Vulkan initialization stuff WIP.
This commit is contained in:
Stephen Seo 2024-03-06 17:04:08 +09:00
parent 0da27b59be
commit 4e4ee7f558
8 changed files with 212 additions and 16 deletions

View file

@ -6,6 +6,7 @@ set(blueNoiseGen_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/image.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/arg_parse.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/utility.cpp
)
add_compile_options(
@ -29,29 +30,48 @@ if(NOT DEFINED DISABLE_OPENCL OR NOT DISABLE_OPENCL)
else()
message(STATUS "Not checking for OpenCL")
endif()
if(NOT DEFINED DISABLE_VULKAN OR NOT DISABLE_VULKAN)
find_package(Vulkan)
if(NOT DEFINED Vulkan_FOUND)
set(DISABLE_VULKAN True)
message(WARNING "Vulkan not found, Vulkan usage is disabled.")
endif()
else()
message(STATUS "Not checking for Vulkan")
endif()
find_package(PNG REQUIRED)
add_executable(blueNoiseGen ${blueNoiseGen_SOURCES})
target_compile_features(blueNoiseGen PUBLIC cxx_std_17)
target_compile_definitions(blueNoiseGen PRIVATE CL_TARGET_OPENCL_VERSION=300)
target_include_directories(blueNoiseGen PUBLIC Threads::Threads ${PNG_INCLUDE_DIRS})
target_link_libraries(blueNoiseGen PUBLIC Threads::Threads ${PNG_LIBRARIES})
if(DEFINED DISABLE_OPENCL AND DISABLE_OPENCL)
message(STATUS "OpenCL usage is disabled.")
target_include_directories(blueNoiseGen PUBLIC
Threads::Threads
${PNG_INCLUDE_DIRS})
target_link_libraries(blueNoiseGen PUBLIC
Threads::Threads
${PNG_LIBRARIES})
target_compile_definitions(blueNoiseGen PRIVATE DITHERING_OPENCL_ENABLED=0)
else()
message(STATUS "OpenCL usage is enabled.")
target_include_directories(blueNoiseGen PUBLIC
Threads::Threads
${OpenCL_INCLUDE_DIRS}
${PNG_INCLUDE_DIRS})
${OpenCL_INCLUDE_DIRS})
target_link_libraries(blueNoiseGen PUBLIC
Threads::Threads
${OpenCL_LIBRARIES}
${PNG_LIBRARIES})
${OpenCL_LIBRARIES})
target_compile_definitions(blueNoiseGen PRIVATE DITHERING_OPENCL_ENABLED=1)
endif()
if(DEFINED DISABLE_VULKAN AND DISABLE_VULKAN)
message(STATUS "Vulkan usage is disabled.")
target_compile_definitions(blueNoiseGen PRIVATE DITHERING_VULKAN_ENABLED=0)
else()
message(STATUS "Vulkan usage is enabled.")
target_include_directories(blueNoiseGen PUBLIC
${Vulkan_INCLUDE_DIRS})
target_link_libraries(blueNoiseGen PUBLIC
${Vulkan_LIBRARIES})
target_compile_definitions(blueNoiseGen PRIVATE DITHERING_VULKAN_ENABLED=1)
if(CMAKE_BUILD_TYPE MATCHES "Debug")
target_compile_definitions(blueNoiseGen PRIVATE VULKAN_VALIDATION=1)
else()
target_compile_definitions(blueNoiseGen PRIVATE VULKAN_VALIDATION=0)
endif()
endif()

View file

@ -7,6 +7,7 @@ Args::Args()
: generate_blue_noise_(false),
use_opencl_(true),
overwrite_file_(false),
use_vulkan_(true),
blue_noise_size_(32),
threads_(4),
output_filename_("output.png") {}
@ -26,7 +27,9 @@ void Args::DisplayHelp() {
" -o <filelname> | --output <filename>\tOutput filename to "
"use\n"
" --overwrite\t\t\t\tEnable overwriting of file (default "
"disabled)\n";
"disabled)\n"
" --usevulkan | --nousevulkan\t\t\tUse/Disable Vulkan (enabled "
"by default)\n";
}
bool Args::ParseArgs(int argc, char **argv) {
@ -69,6 +72,10 @@ bool Args::ParseArgs(int argc, char **argv) {
output_filename_ = std::string(argv[1]);
--argc;
++argv;
} else if (std::strcmp(argv[0], "--usevulkan") == 0) {
use_vulkan_ = true;
} else if (std::strcmp(argv[0], "--nousevulkan") == 0) {
use_vulkan_ = false;
} else {
std::cout << "WARNING: Ignoring invalid input \"" << argv[0] << "\""
<< std::endl;

View file

@ -14,6 +14,7 @@ struct Args {
bool generate_blue_noise_;
bool use_opencl_;
bool overwrite_file_;
bool use_vulkan_;
unsigned int blue_noise_size_;
unsigned int threads_;
std::string output_filename_;

View file

@ -2,6 +2,7 @@
#include <cassert>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
@ -13,11 +14,153 @@
#include <CL/opencl.h>
#endif
#if DITHERING_VULKAN_ENABLED == 1
#include <vulkan/vulkan.h>
static std::vector<const char *> VK_EXTENSIONS = {};
#if VULKAN_VALIDATION == 1
const std::vector<const char *> VALIDATION_LAYERS = {
"VK_LAYER_KHRONOS_validation"};
static VKAPI_ATTR VkBool32 VKAPI_CALL fn_VULKAN_DEBUG_CALLBACK(
VkDebugUtilsMessageSeverityFlagBitsEXT, VkDebugUtilsMessageTypeFlagsEXT,
const VkDebugUtilsMessengerCallbackDataEXT *p_callback_data, void *) {
std::cerr << "Validation layer: " << p_callback_data->pMessage << std::endl;
return VK_FALSE;
}
#endif // VULKAN_VALIDATION == 1
#endif // DITHERING_VULKAN_ENABLED == 1
#include "image.hpp"
image::Bl dither::blue_noise(int width, int height, int threads,
bool use_opencl) {
bool use_opencl, bool use_vulkan) {
bool using_opencl = false;
bool using_vulkan = false;
#if DITHERING_VULKAN_ENABLED == 1
if (use_vulkan) {
// Try to use Vulkan.
#if VULKAN_VALIDATION == 1
// Check for validation support.
uint32_t layer_count;
vkEnumerateInstanceLayerProperties(&layer_count, nullptr);
std::vector<VkLayerProperties> available_layers(layer_count);
vkEnumerateInstanceLayerProperties(&layer_count, available_layers.data());
bool validation_supported = true;
for (const char *layer_name : VALIDATION_LAYERS) {
bool layer_found = false;
for (const auto &layer_props : available_layers) {
if (std::strcmp(layer_name, layer_props.layerName) == 0) {
layer_found = true;
break;
}
}
if (!layer_found) {
validation_supported = false;
break;
}
}
if (!validation_supported) {
std::clog << "WARNING: Validation requested but not supported, cannot "
"use Vulkan!\n";
goto ENDOF_VULKAN;
}
VK_EXTENSIONS.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif // VULKAN_VALIDATION == 1
VkApplicationInfo app_info{};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pApplicationName = "Blue Noise Generation";
app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
app_info.pEngineName = "No Engine";
app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
app_info.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo create_info{};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.pApplicationInfo = &app_info;
create_info.enabledExtensionCount = VK_EXTENSIONS.size();
create_info.ppEnabledExtensionNames = VK_EXTENSIONS.data();
VkDebugUtilsMessengerCreateInfoEXT debug_create_info{};
#if VULKAN_VALIDATION == 1
create_info.enabledLayerCount = VALIDATION_LAYERS.size();
create_info.ppEnabledLayerNames = VALIDATION_LAYERS.data();
const auto populate_debug_info =
[](VkDebugUtilsMessengerCreateInfoEXT *info) {
info->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
info->messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
info->messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
info->pfnUserCallback = fn_VULKAN_DEBUG_CALLBACK;
};
populate_debug_info(&debug_create_info);
create_info.pNext = &debug_create_info;
create_info.enabledExtensionCount = 1;
#else
create_info.enabledLayerCount = 0;
create_info.pNext = nullptr;
#endif // VULKAN_VALIDATION == 1
VkInstance instance;
if (vkCreateInstance(&create_info, nullptr, &instance) != VK_SUCCESS) {
std::clog << "WARNING: Failed to create Vulkan instance!\n";
goto ENDOF_VULKAN;
}
utility::Cleanup cleanup_vk_instance(
[](void *ptr) { vkDestroyInstance(*((VkInstance *)ptr), nullptr); },
&instance);
#if VULKAN_VALIDATION == 1
populate_debug_info(&debug_create_info);
VkDebugUtilsMessengerEXT debug_messenger;
auto create_debug_utils_messenger_func =
(PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
instance, "vkCreateDebugUtilsMessengerEXT");
if (create_debug_utils_messenger_func != nullptr &&
create_debug_utils_messenger_func(instance, &debug_create_info, nullptr,
&debug_messenger) != VK_SUCCESS) {
std::clog << "WARNING: Failed to set up Vulkan debug messenger!\n";
goto ENDOF_VULKAN;
}
utility::Cleanup cleanup_debug_messenger(
[instance](void *ptr) {
auto func =
(PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
instance, "vkDestroyDebugUtilsMessengerEXT");
if (func != nullptr) {
func(instance, *((VkDebugUtilsMessengerEXT *)ptr), nullptr);
}
},
&debug_messenger);
#endif // VULKAN_VALIDATION == 1
}
ENDOF_VULKAN:
std::clog << "TODO: Remove this once Vulkan support is implemented.\n";
return {};
#else
std::clog << "WARNING: Not compiled with Vulkan support!\n";
#endif // DITHERING_VULKAN_ENABLED == 1
#if DITHERING_OPENCL_ENABLED == 1
if (use_opencl) {

View file

@ -28,7 +28,7 @@
namespace dither {
image::Bl blue_noise(int width, int height, int threads = 1,
bool use_opencl = true);
bool use_opencl = true, bool use_vulkan = true);
namespace internal {
std::vector<unsigned int> blue_noise_impl(int width, int height,

View file

@ -41,7 +41,7 @@ int main(int argc, char **argv) {
std::cout << "Generating blue_noise..." << std::endl;
image::Bl bl =
dither::blue_noise(args.blue_noise_size_, args.blue_noise_size_,
args.threads_, args.use_opencl_);
args.threads_, args.use_opencl_, args.use_vulkan_);
if (!bl.writeToFile(image::file_type::PNG, args.overwrite_file_,
args.output_filename_)) {
std::cout << "ERROR: Failed to write blue-noise to file\n";

6
src/utility.cpp Normal file
View file

@ -0,0 +1,6 @@
#include "utility.hpp"
utility::Cleanup::Cleanup(std::function<void(void *)> fn, void *ptr)
: fn(fn), ptr(ptr) {}
utility::Cleanup::~Cleanup() { this->fn(this->ptr); }

View file

@ -2,6 +2,7 @@
#define DITHERING_UTILITY_HPP
#include <cmath>
#include <functional>
#include <utility>
namespace utility {
@ -28,6 +29,24 @@ inline float dist(int a, int b, int width) {
float dy = axy.second - bxy.second;
return std::sqrt(dx * dx + dy * dy);
}
class Cleanup {
public:
Cleanup(std::function<void(void *)> fn, void *ptr);
~Cleanup();
// allow move
Cleanup(Cleanup &&) = default;
Cleanup &operator=(Cleanup &&) = default;
// deny copy
Cleanup(const Cleanup &) = delete;
Cleanup &operator=(const Cleanup &) = delete;
private:
std::function<void(void *)> fn;
void *ptr;
};
} // namespace utility
#endif