Skip to content

Instantly share code, notes, and snippets.

@qis
Last active October 16, 2019 15:40
Show Gist options
  • Save qis/006025b15d9a16689d33ebb2c77ef45d to your computer and use it in GitHub Desktop.
Save qis/006025b15d9a16689d33ebb2c77ef45d to your computer and use it in GitHub Desktop.
#include <result.hpp>
#include <vulkan.hpp>
#include <windows.h>
#include <version.h>
#include <algorithm>
#include <string>
#include <string_view>
// TODO: Read the specification chapter 6 about synchronization.
// https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#synchronization
class Window {
public:
static constexpr PCWSTR error_text = TEXT(PROJECT_DESCRIPTION " Error");
static constexpr PCWSTR title_text = TEXT(PROJECT_DESCRIPTION " " PROJECT_VERSION);
static constexpr PCWSTR class_name = TEXT(PROJECT_VENDOR PROJECT_DESCRIPTION PROJECT_VERSION);
static constexpr PCWSTR class_path = TEXT("Software\\" PROJECT_VENDOR "\\" PROJECT_DESCRIPTION);
Window(HINSTANCE hinstance, LPWSTR cmd, int show) noexcept : hinstance_(hinstance)
{
WNDCLASSEX wc = {};
wc.cbSize = sizeof(wc);
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = Proc;
wc.hInstance = hinstance_;
wc.hIcon = wc.hIconSm = LoadIcon(hinstance_, MAKEINTRESOURCE(101));
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOWFRAME);
wc.lpszClassName = class_name;
RegisterClassEx(&wc);
const auto ws = WS_OVERLAPPEDWINDOW;
const auto ex = WS_EX_APPWINDOW;
CreateWindowEx(ex, class_name, title_text, ws, 0, 0, 640, 480, nullptr, nullptr, hinstance_, this);
}
Window(Window&& other) = delete;
Window(const Window& other) = delete;
Window& operator=(Window&& other) = delete;
Window& operator=(const Window& other) = delete;
~Window()
{
UnregisterClass(class_name, hinstance_);
}
result<void> Initialize() noexcept
{
// Load functions.
co_await vk::Load();
// Create instance.
#ifdef DEBUG
std::string_view layers_requested[] = {
"VK_LAYER_LUNARG_standard_validation",
"VK_LAYER_LUNARG_parameter_validation",
};
for (const auto& e : co_await vk::EnumerateInstanceLayerProperties()) {
const auto it = std::find(std::begin(layers_requested), std::end(layers_requested), e.layerName);
if (it != std::end(layers_requested)) {
layers_.push_back(it->data());
}
}
#endif
std::vector<const char*> extensions;
std::string_view extensions_requested[] = {
"VK_KHR_surface",
"VK_KHR_win32_surface",
#ifdef DEBUG
"VK_EXT_debug_report",
#endif
};
for (const auto& e : co_await vk::EnumerateInstanceExtensionProperties()) {
const auto it = std::find(std::begin(extensions_requested), std::end(extensions_requested), e.extensionName);
if (it != std::end(extensions_requested)) {
extensions.push_back(it->data());
}
}
assert(extensions.size() == std::size(extensions_requested));
VkApplicationInfo application_info = {};
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
application_info.pApplicationName = PROJECT_DESCRIPTION;
application_info.applicationVersion = VK_MAKE_VERSION(PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, PROJECT_VERSION_PATCH);
application_info.pEngineName = PROJECT_VENDOR " " PROJECT_DESCRIPTION;
application_info.engineVersion = VK_MAKE_VERSION(PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR, 0);
application_info.apiVersion = VK_API_VERSION_1_1;
VkInstanceCreateInfo instance_create_info = {};
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_create_info.pApplicationInfo = &application_info;
instance_create_info.enabledLayerCount = static_cast<uint32_t>(layers_.size());
instance_create_info.ppEnabledLayerNames = layers_.data();
instance_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
instance_create_info.ppEnabledExtensionNames = extensions.data();
instance_ = co_await vk::CreateInstance(&instance_create_info);
#ifdef DEBUG
debug_report_callback_ = vk::CreateDebugReportCallback(
instance_, VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
[](VkDebugReportFlagsEXT flags, const char* layer, const char* message) -> VkBool32 {
__debugbreak();
OutputDebugStringA(fmt::format("{}: {}\n", layer, message).data());
return VK_FALSE;
});
#endif
co_return error::success;
}
result<void> CreateSurface() noexcept
{
// Create surface.
VkWin32SurfaceCreateInfoKHR surface_create_info = {};
surface_create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
surface_create_info.hinstance = hinstance_;
surface_create_info.hwnd = hwnd_;
surface_ = co_await vk::CreateWin32Surface(instance_, &surface_create_info);
co_return error::success;
}
void DestroySurface() noexcept
{
surface_ = {};
}
result<void> CreateDevice() noexcept
{
// Select physical device.
for (const auto e : co_await vk::EnumeratePhysicalDevices(instance_)) {
const auto queue_family_properties = vk::GetPhysicalDeviceQueueFamilyProperties(e);
for (uint32_t i = 0, max = static_cast<uint32_t>(queue_family_properties.size()); i < max; i++) {
const auto supports_present = vk::GetPhysicalDeviceSurfaceSupport(e, i, surface_);
if (supports_present && (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) {
physical_device_ = e;
physical_device_properties_ = vk::GetPhysicalDeviceProperties(e);
present_queue_index_ = i;
break;
}
}
}
if (!physical_device_) {
co_return error::vulkan_device_not_found;
}
// Create device.
VkDeviceQueueCreateInfo device_queue_create_nfo = {};
device_queue_create_nfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
device_queue_create_nfo.queueFamilyIndex = present_queue_index_;
device_queue_create_nfo.queueCount = 1;
float queue_priorities[] = { 1.0f };
device_queue_create_nfo.pQueuePriorities = queue_priorities;
VkDeviceCreateInfo device_create_info = {};
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
device_create_info.queueCreateInfoCount = 1;
device_create_info.pQueueCreateInfos = &device_queue_create_nfo;
device_create_info.enabledLayerCount = static_cast<uint32_t>(layers_.size());
device_create_info.ppEnabledLayerNames = layers_.data();
device_create_info.enabledExtensionCount = 1;
const char* device_extensions[] = { "VK_KHR_swapchain" };
device_create_info.ppEnabledExtensionNames = device_extensions;
VkPhysicalDeviceFeatures features = {};
features.shaderClipDistance = VK_TRUE;
device_create_info.pEnabledFeatures = &features;
device_ = co_await vk::CreateDevice(physical_device_, &device_create_info);
co_return error::success;
}
void DestroyDevice() noexcept
{
device_ = {};
present_queue_index_ = 0;
physical_device_properties_ = {};
physical_device_ = nullptr;
}
result<void> CreatePresentQueue() noexcept
{
// Get present queue.
present_queue_ = vk::GetDeviceQueue(device_, present_queue_index_, 0);
co_return present_queue_ ? error::success : error::vk_device_lost;
}
void DestroyPresentQueue() noexcept
{
present_queue_ = nullptr;
}
result<void> CreateCommandBuffers() noexcept
{
// Create command buffers.
VkCommandPoolCreateInfo command_pool_create_info = {};
command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
command_pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
command_pool_create_info.queueFamilyIndex = present_queue_index_;
command_pool_ = co_await vk::CreateCommandPool(device_, &command_pool_create_info);
VkCommandBufferAllocateInfo command_buffer_allocation_nfo = {};
command_buffer_allocation_nfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
command_buffer_allocation_nfo.commandPool = command_pool_;
command_buffer_allocation_nfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
command_buffer_allocation_nfo.commandBufferCount = 2;
command_buffers_ = co_await vk::AllocateCommandBuffers(device_, &command_buffer_allocation_nfo);
co_return error::success;
}
void DestroyCommandBuffers() noexcept
{
command_buffers_ = {};
command_pool_ = {};
}
result<void> CreateSwapchain() noexcept
{
// Choose color format.
color_format_ = VK_FORMAT_B8G8R8_UNORM;
const auto surface_formats = co_await GetPhysicalDeviceSurfaceFormats(physical_device_, surface_);
if (surface_formats.empty()) {
co_return error::vulkan_device_missing_surface_formats;
} else if (surface_formats.size() == 1 && surface_formats[0].format == VK_FORMAT_UNDEFINED) {
color_format_ = VK_FORMAT_B8G8R8_UNORM;
} else {
color_format_ = surface_formats[0].format;
}
// Choose color space.
color_space_ = surface_formats[0].colorSpace;
// Choose buffer count.
const auto surface_capabilities = co_await vk::GetPhysicalDeviceSurfaceCapabilities(physical_device_, surface_);
uint32_t buffer_count = 2;
if (buffer_count < surface_capabilities.minImageCount) {
buffer_count = surface_capabilities.minImageCount;
} else if (surface_capabilities.maxImageCount != 0 && buffer_count > surface_capabilities.maxImageCount) {
buffer_count = surface_capabilities.maxImageCount;
}
// Choose resolution.
RECT rc = {};
if (!GetClientRect(hwnd_, &rc)) {
co_return error::window_connection_error;
}
cx_ = static_cast<decltype(cx_)>(rc.right - rc.left);
cy_ = static_cast<decltype(cy_)>(rc.bottom - rc.top);
auto surface_resolution = surface_capabilities.currentExtent;
if (surface_resolution.width == -1) {
surface_resolution.width = cx_;
surface_resolution.height = cy_;
} else {
cx_ = surface_resolution.width;
cy_ = surface_resolution.height;
}
// Choose transform.
auto transform = surface_capabilities.currentTransform;
if (surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
// Choose present mode.
auto present_mode = VK_PRESENT_MODE_FIFO_KHR;
for (const auto e : co_await vk::GetPhysicalDeviceSurfacePresentModes(physical_device_, surface_)) {
if (e == VK_PRESENT_MODE_MAILBOX_KHR) {
present_mode = e;
break;
}
if (e == VK_PRESENT_MODE_IMMEDIATE_KHR) {
present_mode = e;
}
}
// Create swap chain.
VkSwapchainCreateInfoKHR swap_chain_create_info = {};
swap_chain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swap_chain_create_info.surface = surface_;
swap_chain_create_info.minImageCount = buffer_count;
swap_chain_create_info.imageFormat = color_format_;
swap_chain_create_info.imageColorSpace = color_space_;
swap_chain_create_info.imageExtent = surface_resolution;
swap_chain_create_info.imageArrayLayers = 1;
swap_chain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swap_chain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swap_chain_create_info.preTransform = transform;
swap_chain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
swap_chain_create_info.presentMode = present_mode;
swap_chain_create_info.clipped = VK_TRUE;
swapchain_ = co_await vk::CreateSwapchain(device_, &swap_chain_create_info);
// Move swapchain images to a present layout.
swapchain_images_ = co_await vk::GetSwapchainImages(device_, swapchain_);
VkImageViewCreateInfo present_image_view_create_info = {};
present_image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
present_image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
present_image_view_create_info.format = color_format_;
present_image_view_create_info.components = {
VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_G,
VK_COMPONENT_SWIZZLE_B,
VK_COMPONENT_SWIZZLE_A,
};
present_image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
present_image_view_create_info.subresourceRange.baseMipLevel = 0;
present_image_view_create_info.subresourceRange.levelCount = 1;
present_image_view_create_info.subresourceRange.baseArrayLayer = 0;
present_image_view_create_info.subresourceRange.layerCount = 1;
VkCommandBufferBeginInfo command_buffer_begin_info = {};
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
std::vector<VkImageView> present_image_views;
VkFenceCreateInfo fence_create_info = {};
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
const auto submit_fence = co_await vk::CreateFence(device_, &fence_create_info);
for (const auto& e : swapchain_images_) {
present_image_view_create_info.image = e;
// Record on the setup command buffer.
co_await vk::BeginCommandBuffer(setup_command_buffer(), &command_buffer_begin_info);
VkImageMemoryBarrier layout_transition_barrier = {};
layout_transition_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
layout_transition_barrier.srcAccessMask = 0;
layout_transition_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
layout_transition_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
layout_transition_barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
layout_transition_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
layout_transition_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
layout_transition_barrier.image = e;
layout_transition_barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
VkCommandPipelineBarrierInfo command_pipeline_barrier_info = {};
command_pipeline_barrier_info.commandBuffer = setup_command_buffer();
command_pipeline_barrier_info.srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
command_pipeline_barrier_info.dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
command_pipeline_barrier_info.dependencyFlags = 0;
command_pipeline_barrier_info.memoryBarrierCount = 0;
command_pipeline_barrier_info.pMemoryBarriers = nullptr;
command_pipeline_barrier_info.bufferMemoryBarrierCount = 0;
command_pipeline_barrier_info.pBufferMemoryBarriers = nullptr;
command_pipeline_barrier_info.imageMemoryBarrierCount = 1;
command_pipeline_barrier_info.pImageMemoryBarriers = &layout_transition_barrier;
vk::CommandPipelineBarrier(&command_pipeline_barrier_info);
co_await vk::EndCommandBuffer(setup_command_buffer());
// Submit code to the queue.
VkSubmitInfo submit_info = {};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = nullptr;
const VkPipelineStageFlags wait_stage_mask[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
submit_info.pWaitDstStageMask = wait_stage_mask;
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &setup_command_buffer();
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
co_await vk::QueueSubmit(present_queue_, 1, &submit_info, submit_fence);
// Waiting for commands to finish executing.
co_await vk::WaitForFence(device_, submit_fence, UINT64_MAX);
co_await vk::ResetFence(device_, submit_fence);
co_await vk::ResetCommandBuffer(setup_command_buffer());
// Create image view.
present_image_views.push_back(co_await vk::CreateImageView(device_, &present_image_view_create_info));
}
co_return error::success;
}
void DestroySwapchain() noexcept
{
swapchain_images_ = {};
swapchain_ = {};
color_space_ = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
color_format_ = VK_FORMAT_B8G8R8_UNORM;
cy_ = 1;
cx_ = 1;
}
result<void> Render() noexcept
{
//Sleep(10);
constexpr VkSemaphoreCreateInfo semaphore_create_info = {
VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
nullptr,
0,
};
const auto present_complete_semaphore = co_await vk::CreateSemaphore(device_, &semaphore_create_info);
const auto next_image_index = co_await vk::AcquireNextImage(device_, swapchain_, UINT64_MAX, present_complete_semaphore, VK_NULL_HANDLE);
VkPresentInfoKHR present_info = {};
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
present_info.pNext = nullptr;
present_info.waitSemaphoreCount = 0;
present_info.pWaitSemaphores = nullptr;
present_info.swapchainCount = 1;
present_info.pSwapchains = &swapchain_.get();
present_info.pImageIndices = &next_image_index;
present_info.pResults = nullptr;
co_await vk::QueuePresent(present_queue_, &present_info);
co_return error::success;
}
void OnCreate() noexcept
{
WINDOWPLACEMENT wp = {};
DWORD wt = REG_BINARY;
DWORD ws = sizeof(wp);
if (RegGetValue(HKEY_CURRENT_USER, class_path, L"Window", RRF_RT_REG_BINARY, &wt, &wp, &ws) == ERROR_SUCCESS) {
wp.showCmd = SW_HIDE;
SetWindowPlacement(hwnd_, &wp);
} else {
if (const auto monitor = MonitorFromWindow(hwnd_, MONITOR_DEFAULTTONULL)) {
MONITORINFO mi = {};
mi.cbSize = sizeof(mi);
if (GetMonitorInfo(monitor, &mi)) {
const auto cx = mi.rcMonitor.right - mi.rcMonitor.left;
const auto cy = mi.rcMonitor.bottom - mi.rcMonitor.top;
RECT rc = {};
if (GetWindowRect(hwnd_, &rc) && cx > rc.right - rc.left && cy > rc.bottom - rc.top) {
const auto x = (cx - (rc.right - rc.left)) / 2;
const auto y = (cy - (rc.bottom - rc.top)) / 2;
SetWindowPos(hwnd_, nullptr, x, y, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE);
}
}
}
}
if (const auto result = Initialize(); !result) {
return Close("Could not initialize application: {}", result.error());
}
if (const auto result = CreateSurface(); !result) {
return Close("Could not create surface: {}", result.error());
}
if (const auto result = CreateDevice(); !result) {
return Close("Could not create device: {}", result.error());
}
if (const auto result = CreatePresentQueue(); !result) {
return Close("Could not create present queue: {}", result.error());
}
if (const auto result = CreateCommandBuffers(); !result) {
return Close("Could not create command buffers: {}", result.error());
}
if (const auto result = CreateSwapchain(); !result) {
return Close("Could not create swapchain: {}", result.error());
}
Show();
}
void OnSize(WORD cx, WORD cy) noexcept
{
// TODO: return Close("Vulkan resize not yet implemented. ({}:{})", cx, cy);
}
void OnDestroy() noexcept
{
if (render_) {
WINDOWPLACEMENT wp = {};
if (GetWindowPlacement(hwnd_, &wp) && wp.showCmd == SW_SHOWNORMAL) {
RegSetKeyValue(HKEY_CURRENT_USER, class_path, L"Window", REG_BINARY, &wp, sizeof(wp));
}
}
Hide();
DestroySwapchain();
DestroyCommandBuffers();
DestroyPresentQueue();
DestroyDevice();
DestroySurface();
PostQuitMessage(0);
}
void OnRenderError(error error) noexcept
{
return Close("Vulkan recovery failed: {}", error);
}
void Show() noexcept
{
render_ = true;
ShowWindow(hwnd_, SW_SHOW);
}
void Hide() noexcept
{
render_ = false;
ShowWindow(hwnd_, SW_HIDE);
}
void Close() noexcept
{
PostMessage(hwnd_, WM_CLOSE, 0, 0);
}
template <std::size_t N, typename... Args>
void Close(char const (&format)[N], Args&&... args) noexcept
{
Hide();
std::wstring wcs;
fmt::memory_buffer str;
fmt::format_to(str, format, std::forward<Args>(args)...);
const auto str_size = static_cast<int>(str.size());
const auto wcs_size = MultiByteToWideChar(CP_UTF8, 0, str.data(), str_size, nullptr, 0);
wcs.resize(static_cast<std::size_t>(wcs_size + 1));
wcs.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, 0, str.data(), str_size, wcs.data(), wcs_size + 1)));
MessageBox(nullptr, wcs.data(), error_text, MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
PostMessage(hwnd_, WM_CLOSE, 0, 0);
}
int Run() noexcept
{
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0)) {
DispatchMessage(&msg);
while (render_) {
if (const auto result = Render(); !result) {
OnRenderError(result.error());
}
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
goto exit;
}
DispatchMessage(&msg);
}
}
}
exit:
return static_cast<int>(msg.wParam);
}
private:
static LRESULT __stdcall Proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) noexcept
{
switch (msg) {
case WM_CREATE:
if (const auto window = reinterpret_cast<Window*>(reinterpret_cast<LPCREATESTRUCT>(lparam)->lpCreateParams)) {
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(window));
window->hwnd_ = hwnd;
window->OnCreate();
}
return 0;
case WM_SIZE:
if (const auto window = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA))) {
window->OnSize(LOWORD(lparam), HIWORD(lparam));
}
return 0;
case WM_DESTROY:
if (const auto window = reinterpret_cast<Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA))) {
SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
window->OnDestroy();
}
return 0;
case WM_ERASEBKGND:
return 1;
case WM_PAINT:
ValidateRect(hwnd, nullptr);
return 0;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
// Window
HINSTANCE hinstance_;
HWND hwnd_ = nullptr;
bool render_ = false;
// Instance
std::vector<const char*> layers_;
vk::Instance instance_;
// Surface
vk::Surface surface_;
// Device
VkPhysicalDevice physical_device_ = nullptr;
VkPhysicalDeviceProperties physical_device_properties_ = {};
uint32_t present_queue_index_ = 0;
vk::Device device_;
// Present Queue
VkQueue present_queue_ = nullptr;
// Command Buffers
vk::CommandPool command_pool_;
vk::CommandBuffers command_buffers_;
const VkCommandBuffer& setup_command_buffer() const noexcept
{
return command_buffers_[0];
}
VkCommandBuffer& setup_command_buffer() noexcept
{
return command_buffers_[0];
}
const VkCommandBuffer& render_command_buffer() const noexcept
{
return command_buffers_[1];
}
VkCommandBuffer& render_command_buffer() noexcept
{
return command_buffers_[1];
}
// Swapchain
uint32_t cx_ = 1;
uint32_t cy_ = 1;
VkFormat color_format_ = VK_FORMAT_B8G8R8_UNORM;
VkColorSpaceKHR color_space_ = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
vk::Swapchain swapchain_;
std::vector<VkImage> swapchain_images_;
#ifdef DEBUG
vk::DebugReportCallback debug_report_callback_;
#endif
};
int WINAPI wWinMain(HINSTANCE hinstance, HINSTANCE, LPWSTR cmd, int show)
{
Window Window(hinstance, cmd, show);
return Window.Run();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment