Last active
May 11, 2021 07:02
-
-
Save bl4ckb0ne/92906f3b00531396a61eaf2966676b16 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <cassert> | |
#include <cstring> | |
#include <iostream> | |
#include <memory> | |
#include <vector> | |
#if defined(VK_USE_PLATFORM_WIN32_KHR) | |
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) | |
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) | |
#define GLFW_EXPOSE_NATIVE_WAYLAND | |
#include <wayland-client.h> | |
#elif defined(VK_USE_PLATFORM_XCB_KHR) | |
#define GLFW_EXPOSE_NATIVE_X11 | |
#include <X11/Xlib-xcb.h> | |
#elif defined(VK_USE_PLATFORM_XLIB_KHR) | |
#define GLFW_EXPOSE_NATIVE_X11 | |
#include <X11/Xlib.h> | |
#elif defined(VK_USE_PLATFORM_IOS_MVK) | |
#elif defined(VK_USE_PLATFORM_MACOS_MVK) | |
#endif | |
#include <vulkan/vulkan.h> | |
#include <GLFW/glfw3.h> | |
#include <GLFW/glfw3native.h> | |
#include <vlk/device.hpp> | |
#include <vlk/instance.hpp> | |
#include <vlk/surface.hpp> | |
#include <vlk/swapchain.hpp> | |
#include <vlk/utils.hpp> | |
uint32_t WIDTH = 640; | |
uint32_t HEIGHT = 480; | |
const std::vector<const char*> device_extensions | |
{ | |
VK_KHR_SWAPCHAIN_EXTENSION_NAME | |
}; | |
bool is_device_suitable(const vlk::Physical_Device& p) | |
{ | |
#ifndef NDEBUG | |
vlk::print_device(p); | |
#endif | |
// We need to be sure the vlk::PhysicalDevice has the basics | |
if (p.device_type() != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU || | |
!p.has_extension("VK_KHR_swapchain") || | |
!p.features().geometryShader) | |
{ | |
return false; | |
} | |
return true; | |
} | |
#ifndef NDEBUG | |
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback_fun( | |
VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, | |
int32_t code, const char* layerPrefix, const char* msg, void* userData) | |
{ | |
std::string prefix(""); | |
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) | |
{ | |
prefix += "ERROR:"; | |
} | |
if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) | |
{ | |
prefix += "WARNING:"; | |
} | |
if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) | |
{ | |
prefix += "PERFORMANCE:"; | |
} | |
if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) | |
{ | |
prefix += "INFO:"; | |
} | |
if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) | |
{ | |
prefix += "DEBUG:"; | |
} | |
std::printf("%s [%s] Code %i : %s\n", prefix.c_str(), layerPrefix, code, msg); | |
return VK_FALSE; | |
} | |
#endif | |
struct Destroy_GLFWwindow | |
{ | |
void operator()(GLFWwindow* ptr) | |
{ | |
glfwDestroyWindow(ptr); | |
} | |
}; | |
int main() | |
{ | |
glfwInit(); | |
// Prevent glfw to create an OpenGL context | |
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); | |
// Create GLFWwindow | |
std::unique_ptr<GLFWwindow, Destroy_GLFWwindow> window; | |
window.reset(glfwCreateWindow(WIDTH, HEIGHT, "Surtr Triangle Example", NULL, NULL)); | |
if (window == nullptr) | |
{ | |
std::printf("Surtr Triangle example : Failed to create glfw window\n"); | |
return -1; | |
} | |
// Check for vulkan support | |
if (GLFW_FALSE == glfwVulkanSupported()) | |
{ | |
std::printf("Surtr Triangle example : Vulkan not supported\n"); | |
return -1; | |
} | |
// Prepare the extensions for the vlk::Instance creation | |
std::vector<const char*> extensions; | |
unsigned int glfw_extension_count = 0; | |
const char** glfw_extensions; | |
// glfw will give the appropriate extension for the surface | |
glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count); | |
for (unsigned int i = 0; i < glfw_extension_count; i++) | |
{ | |
extensions.push_back(glfw_extensions[i]); | |
} | |
//TODO: Xlib surface extension seems to not be loaded by glfw | |
#if defined(VK_USE_PLATFORM_XLIB_KHR) | |
extensions.push_back("VK_KHR_xlib_surface"); | |
#endif | |
std::vector<const char*> validation_layers; | |
#ifndef NDEBUG | |
// Add the debug extensions | |
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); | |
std::printf("Using extensions :\n"); | |
for (auto& it : extensions) | |
{ | |
std::printf("\t%s\n", it); | |
} | |
validation_layers.push_back("VK_LAYER_LUNARG_standard_validation"); | |
std::printf("Using validation layers :\n"); | |
for (auto& it : validation_layers) | |
{ | |
std::printf("\t%s\n", it); | |
} | |
#endif | |
// Create the instance and setup the debug callback | |
std::shared_ptr<vlk::Instance> instance = std::make_shared<vlk::Instance>("vlk Triangle Example", "NO_ENGINE", extensions, validation_layers); | |
#ifndef NDEBUG | |
instance->set_debug_callback(&debug_callback_fun); | |
#endif | |
// Now that we have the instance, we can | |
// generate a Surface for the right platform | |
#if defined(VK_USE_PLATFORM_WIN32_KHR) | |
#elif defined(VK_USE_PLATFORM_ANDROID_KHR) | |
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) | |
std::printf("Using Wayland interface\n"); | |
std::shared_ptr<vlk::Surface> surface = std::make_shared<vlk::Surface>(instance, glfwGetWaylandDisplay(), glfwGetWaylandWindow(window.get())); | |
#elif defined(VK_USE_PLATFORM_XCB_KHR) | |
// TODO: convert Display to xcb_window_t | |
std::printf("Using Xcb interface\n"); | |
std::shared_ptr<vlk::Surface> surface = std::make_shared<vlk::Surface>(instance, XGetXCBConnection(glfwGetX11Display()), glfwGetX11Window(window.get())); | |
#elif defined(VK_USE_PLATFORM_XLIB_KHR) | |
// On X11, Vulkan expects a Xlib window to draw on | |
// Since we are using glfw3, we can extract that from the GLFWwindow | |
std::printf("Using Xlib interface\n"); | |
std::shared_ptr<vlk::Surface> surface = std::make_shared<vlk::Surface>(instance, glfwGetX11Display(), glfwGetX11Window(window.get())); | |
#elif defined(VK_USE_PLATFORM_IOS_MVK) | |
#elif defined(VK_USE_PLATFORM_MACOS_MVK) | |
#else | |
// Empty constructor, will throw :trollface: | |
std::unique_ptr<vlk::Surface> surface = std::make_unique<vlk::Surface>(); | |
#endif | |
// Get the physical devices from the instance | |
std::vector<vlk::Physical_Device> physical_devices = instance->get_physical_devices(); | |
#ifndef NDEBUG | |
std::printf("%zo physical devices found\n", physical_devices.size()); | |
#endif | |
// Find a physical device with geometry shader, might not work on integrated graphics | |
std::vector<vlk::Physical_Device> valid_physical_devices; | |
std::copy_if(std::begin(physical_devices), std::end(physical_devices), std::back_inserter(valid_physical_devices), is_device_suitable); | |
assert(valid_physical_devices.size() > 0u && "No suitable physical devices found"); | |
// Pick the first suitable device | |
std::unique_ptr<vlk::Physical_Device> physical_device = std::make_unique<vlk::Physical_Device>(valid_physical_devices.at(0)); | |
#ifndef NDEBUG | |
std::printf("vlk::Physical_Device in use : %s\n", physical_device->name().c_str()); | |
std::printf("Available vlk::Physical_Device extensions :\n"); | |
for (const auto& extension : physical_device->get_extensions()) | |
{ | |
std::printf("\t%s\n", extension.extensionName); | |
} | |
#endif | |
// Create the logical device for Vulkan to use | |
std::shared_ptr<vlk::Device> device = std::make_shared<vlk::Device>(instance, std::move(physical_device), static_cast<uint32_t>(physical_device->queue_indice(VK_QUEUE_GRAPHICS_BIT)), device_extensions, validation_layers); | |
// Now that we have a surface and a logical device, its time to create a vlk::Swapchain | |
// First, we see if the physical device supports the wanted format. | |
// https://en.wikipedia.org/wiki/SRGB | |
VkSurfaceFormatKHR format = { VK_FORMAT_B8G8R8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }; | |
{ | |
const vlk::Physical_Device* ptr_p_device = device->get_physical_device(); | |
std::vector<VkSurfaceFormatKHR> formats = ptr_p_device->get_surface_formats(surface); | |
assert(formats.size() > 0u && "vlk::Physical_Device : no surface formats"); | |
// Modern C++ sure is pretty | |
if (std::find_if( | |
std::begin(formats), | |
std::end(formats), | |
[&format](const VkSurfaceFormatKHR& f) | |
{ | |
return ((format.format == f.format) && (format.colorSpace == f.colorSpace)); | |
}) == std::end(formats)) | |
{ | |
std::printf("vlk Triangle example error : SRGB format not available"); | |
return 1; | |
} | |
} | |
// VK_PRESENT_MODE_FIFO_KHR is assured to be present. Also avoid screen tearing | |
VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; | |
// Size of the buffer | |
VkExtent2D extent = { WIDTH, HEIGHT }; | |
// The minimum number of presentable images that the application needs. | |
uint32_t img_count = 2u; | |
vlk::Swapchain swapchain(device, surface, format, present_mode, extent, img_count); | |
// Terminate glfw at the end | |
glfwTerminate(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment