From bbf493f860073f422cb263a2197b9dc9ccee1612 Mon Sep 17 00:00:00 2001 From: ouczbs Date: Thu, 22 Feb 2024 00:23:37 +0800 Subject: [PATCH] create window & instance & device & swapchain --- engine/src/engine/renderapi/window.cpp | 101 +++++++++ engine/src/engine/renderapi/window.h | 36 +++ engine/src/engine/vulkanapi/backend.cpp | 32 +++ engine/src/engine/vulkanapi/backend.h | 22 ++ engine/src/engine/vulkanapi/vulkan.cpp | 14 ++ engine/src/engine/vulkanapi/vulkan.h | 26 +++ .../engine/vulkanapi/vulkan_function_list.inl | 205 ++++++++++++++++++ engine/src/engine/vulkanapi/window.cpp | 25 +++ engine/src/engine/vulkanapi/window.h | 16 ++ .../src/engine/vulkanapi/wrapper/device.cpp | 64 ++++++ engine/src/engine/vulkanapi/wrapper/device.h | 25 +++ .../engine/vulkanapi/wrapper/device_help.h | 43 ++++ .../src/engine/vulkanapi/wrapper/instance.cpp | 80 +++++++ .../src/engine/vulkanapi/wrapper/instance.h | 18 ++ .../engine/vulkanapi/wrapper/instance_help.h | 190 ++++++++++++++++ .../engine/vulkanapi/wrapper/swapchain.cpp | 33 +++ .../src/engine/vulkanapi/wrapper/swapchain.h | 16 ++ .../engine/vulkanapi/wrapper/swapchain_help.h | 160 ++++++++++++++ engine/src/main.cpp | 9 +- engine/xmake.lua | 2 +- 20 files changed, 1115 insertions(+), 2 deletions(-) create mode 100644 engine/src/engine/renderapi/window.cpp create mode 100644 engine/src/engine/renderapi/window.h create mode 100644 engine/src/engine/vulkanapi/backend.cpp create mode 100644 engine/src/engine/vulkanapi/backend.h create mode 100644 engine/src/engine/vulkanapi/vulkan.cpp create mode 100644 engine/src/engine/vulkanapi/vulkan.h create mode 100644 engine/src/engine/vulkanapi/vulkan_function_list.inl create mode 100644 engine/src/engine/vulkanapi/window.cpp create mode 100644 engine/src/engine/vulkanapi/window.h create mode 100644 engine/src/engine/vulkanapi/wrapper/device.cpp create mode 100644 engine/src/engine/vulkanapi/wrapper/device.h create mode 100644 engine/src/engine/vulkanapi/wrapper/device_help.h create mode 100644 engine/src/engine/vulkanapi/wrapper/instance.cpp create mode 100644 engine/src/engine/vulkanapi/wrapper/instance.h create mode 100644 engine/src/engine/vulkanapi/wrapper/instance_help.h create mode 100644 engine/src/engine/vulkanapi/wrapper/swapchain.cpp create mode 100644 engine/src/engine/vulkanapi/wrapper/swapchain.h create mode 100644 engine/src/engine/vulkanapi/wrapper/swapchain_help.h diff --git a/engine/src/engine/renderapi/window.cpp b/engine/src/engine/renderapi/window.cpp new file mode 100644 index 0000000..15c915c --- /dev/null +++ b/engine/src/engine/renderapi/window.cpp @@ -0,0 +1,101 @@ +#include "window.h" +namespace renderapi { + Window::WindowClass Window::WindowClass::wndClass; + + Window::WindowClass::WindowClass() noexcept + : + hInst(GetModuleHandle(nullptr)) + { + WNDCLASSEX wc = { 0 }; + wc.cbSize = sizeof(wc); + wc.style = CS_OWNDC; + wc.lpfnWndProc = HandleMsgSetup; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = GetInstance(); + wc.hCursor = nullptr; + wc.hbrBackground = nullptr; + wc.lpszMenuName = nullptr; + wc.lpszClassName = GetName(); + RegisterClassEx(&wc); + } + Window::Window(int width, int height, const char* title) + :mWidth(width), mHeight(height) + { + RECT wr{}; + wr.left = 100; + wr.right = width + wr.left; + wr.top = 100; + wr.bottom = height + wr.top; + mPtr = CreateWindow( + WindowClass::GetName(), title, + WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU, + CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, + nullptr, nullptr, WindowClass::GetInstance(), this + ); + ShowWindow(mPtr, SW_SHOW); + } + bool Window::ProcessMessages(int& code) + { + MSG msg; + // while queue has messages, remove and dispatch them (but do not block on empty queue) + while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) + { + // check for quit because peekmessage does not signal this via return val + if (msg.message == WM_QUIT) + { + // return optional wrapping int (arg to PostQuitMessage is in wparam) signals quit + code = (int)msg.wParam; + return true; + } + + // TranslateMessage will post auxilliary WM_CHAR messages from key msgs + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return false; + } + LRESULT CALLBACK Window::HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept + { + // use create parameter passed in from CreateWindow() to store window class pointer at WinAPI side + if (msg == WM_NCCREATE) + { + // extract ptr to window class from creation data + const CREATESTRUCTW* const pCreate = reinterpret_cast(lParam); + Window* const pWnd = static_cast(pCreate->lpCreateParams); + // set WinAPI-managed user data to store ptr to window instance + SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pWnd)); + // set message proc to normal (non-setup) handler now that setup is finished + SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast(&Window::HandleMsgThunk)); + // forward message to window instance handler + return pWnd->HandleMsg(hWnd, msg, wParam, lParam); + } + // if we get a message before the WM_NCCREATE message, handle with default handler + return DefWindowProc(hWnd, msg, wParam, lParam); + } + + LRESULT CALLBACK Window::HandleMsgThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept + { + // retrieve ptr to window instance + Window* const pWnd = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + // forward message to window instance handler + return pWnd->HandleMsg(hWnd, msg, wParam, lParam); + } + + LRESULT Window::HandleMsg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept + { + switch (msg) + { + // we don't want the DefProc to handle this message because + // we want our destructor to destroy the window, so return 0 instead of break + case WM_CLOSE: + PostQuitMessage(0); + return 0; + // clear keystate when window loses focus to prevent input getting "stuck" + /************** END MOUSE MESSAGES **************/ + } + + return DefWindowProc(hWnd, msg, wParam, lParam); + } + +} diff --git a/engine/src/engine/renderapi/window.h b/engine/src/engine/renderapi/window.h new file mode 100644 index 0000000..5da0485 --- /dev/null +++ b/engine/src/engine/renderapi/window.h @@ -0,0 +1,36 @@ +#include +namespace renderapi { + class Window { + protected: + int mWidth; + int mHeight; + HWND mPtr; + protected: + class WindowClass + { + public: + static const char* GetName() noexcept { + return wndClassName; + } + static HINSTANCE GetInstance() noexcept { + return wndClass.hInst; + } + private: + WindowClass() noexcept; + WindowClass(const WindowClass&) = delete; + WindowClass& operator=(const WindowClass&) = delete; + static constexpr const char* wndClassName = "MainWnd"; + static WindowClass wndClass; + HINSTANCE hInst; + }; + static LRESULT CALLBACK HandleMsgSetup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept; + static LRESULT CALLBACK HandleMsgThunk(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept; + LRESULT HandleMsg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) noexcept; + public: + Window(int width, int height, const char* title); + HWND Ptr() { + return mPtr; + } + static bool ProcessMessages(int& code); + }; +}; \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/backend.cpp b/engine/src/engine/vulkanapi/backend.cpp new file mode 100644 index 0000000..cf490e0 --- /dev/null +++ b/engine/src/engine/vulkanapi/backend.cpp @@ -0,0 +1,32 @@ +#include "backend.h" +#include "wrapper/instance.h" +#include "wrapper/device.h" +#include + +namespace vulkanapi { + Backend::Backend(const char* appName, int deviceIndex) { + mInstance = new Instance(appName); + std::vector available_devices; + mInstance->EnumerateAvailablePhysicalDevices(available_devices); + int device_count = available_devices.size(); + if (device_count <= deviceIndex) { + std::cout << "Could not get the number of available physical devices." << deviceIndex << device_count << std::endl; + if (device_count == 0) { + return; + } + deviceIndex = 0; + } + mDevice = new Device(mInstance->Ptr(), available_devices[deviceIndex]); + } + Backend::~Backend() + { + if (mInstance) { + delete mInstance; + mInstance = nullptr; + } + if (mDevice) { + delete mDevice; + mDevice = nullptr; + } + } +} diff --git a/engine/src/engine/vulkanapi/backend.h b/engine/src/engine/vulkanapi/backend.h new file mode 100644 index 0000000..e5a9e77 --- /dev/null +++ b/engine/src/engine/vulkanapi/backend.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +namespace vulkanapi { + class Instance; + class Device; + class Backend{ + protected: + Instance* mInstance; + Device* mDevice; + public: + Instance* GetInstance() { + return mInstance; + } + Device* GetDevice() { + return mDevice; + } + public: + Backend(const char* appName, int deviceIndex = 0); + ~Backend(); + }; +}; \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/vulkan.cpp b/engine/src/engine/vulkanapi/vulkan.cpp new file mode 100644 index 0000000..bf955a3 --- /dev/null +++ b/engine/src/engine/vulkanapi/vulkan.cpp @@ -0,0 +1,14 @@ +#include "vulkan.h" + +namespace vulkanapi { + +#define EXPORTED_VULKAN_FUNCTION( name ) PFN_##name name; +#define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; +#define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) PFN_##name name; +#define DEVICE_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) PFN_##name name; + +#include "vulkan_function_list.inl" + +} \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/vulkan.h b/engine/src/engine/vulkanapi/vulkan.h new file mode 100644 index 0000000..79a26df --- /dev/null +++ b/engine/src/engine/vulkanapi/vulkan.h @@ -0,0 +1,26 @@ +//#pragma once +#include +#include +#include +namespace vulkanapi { +// Vulkan library type +#ifdef _WIN32 +#define LIBRARY_TYPE HMODULE +#elif defined __linux +#define LIBRARY_TYPE void* +#endif + + using voidFn = std::function; + using commandFn = std::function; + +//Vulkan Function Addr Variable lg:PFN_##name name; +#define EXPORTED_VULKAN_FUNCTION( name ) extern PFN_##name name; +#define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; +#define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) extern PFN_##name name; +#define DEVICE_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) extern PFN_##name name; + +#include "vulkan_function_list.inl" + extern const char* EngineName; +} \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/vulkan_function_list.inl b/engine/src/engine/vulkanapi/vulkan_function_list.inl new file mode 100644 index 0000000..da81737 --- /dev/null +++ b/engine/src/engine/vulkanapi/vulkan_function_list.inl @@ -0,0 +1,205 @@ + +// MIT License +// +// Copyright( c ) 2017 Packt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files( the "Software" ), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. +// +// Vulkan Cookbook +// ISBN: 9781786468154 +// ?Packt Publishing Limited +// +// Author: Pawel Lapinski +// LinkedIn: https://www.linkedin.com/in/pawel-lapinski-84522329 +// +// List of Vulkan Functions + +// + +#ifndef EXPORTED_VULKAN_FUNCTION +#define EXPORTED_VULKAN_FUNCTION( function ) +#endif + +//EXPORTED_VULKAN_FUNCTION(vkGetInstanceProcAddr) + +#undef EXPORTED_VULKAN_FUNCTION + +// + +#ifndef GLOBAL_LEVEL_VULKAN_FUNCTION +#define GLOBAL_LEVEL_VULKAN_FUNCTION( function ) +#endif + +//GLOBAL_LEVEL_VULKAN_FUNCTION(vkEnumerateInstanceExtensionProperties) +//GLOBAL_LEVEL_VULKAN_FUNCTION(vkEnumerateInstanceLayerProperties) +//GLOBAL_LEVEL_VULKAN_FUNCTION(vkCreateInstance) + +#undef GLOBAL_LEVEL_VULKAN_FUNCTION + +// + +#ifndef INSTANCE_LEVEL_VULKAN_FUNCTION +#define INSTANCE_LEVEL_VULKAN_FUNCTION( function ) +#endif + +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkEnumeratePhysicalDevices) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkEnumerateDeviceExtensionProperties) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkGetPhysicalDeviceFeatures) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkGetPhysicalDeviceProperties) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkGetPhysicalDeviceMemoryProperties) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkGetPhysicalDeviceFormatProperties) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkCreateDevice) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkGetDeviceProcAddr) +//INSTANCE_LEVEL_VULKAN_FUNCTION(vkDestroyInstance) + +#undef INSTANCE_LEVEL_VULKAN_FUNCTION + +// + +#ifndef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( function, extension ) +#endif + +//INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkGetPhysicalDeviceSurfaceSupportKHR, VK_KHR_SURFACE_EXTENSION_NAME) +//INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, VK_KHR_SURFACE_EXTENSION_NAME) +//INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkGetPhysicalDeviceSurfaceFormatsKHR, VK_KHR_SURFACE_EXTENSION_NAME) +//INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkGetPhysicalDeviceSurfacePresentModesKHR, VK_KHR_SURFACE_EXTENSION_NAME) +//INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkDestroySurfaceKHR, VK_KHR_SURFACE_EXTENSION_NAME) + +#ifdef VK_USE_PLATFORM_WIN32_KHR +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkCreateWin32SurfaceKHR, VK_KHR_WIN32_SURFACE_EXTENSION_NAME) +#elif defined VK_USE_PLATFORM_XCB_KHR +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkCreateXcbSurfaceKHR, VK_KHR_XCB_SURFACE_EXTENSION_NAME) +#elif defined VK_USE_PLATFORM_XLIB_KHR +INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkCreateXlibSurfaceKHR, VK_KHR_XLIB_SURFACE_EXTENSION_NAME) +#endif + +#undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION + +// + +#ifndef DEVICE_LEVEL_VULKAN_FUNCTION +#define DEVICE_LEVEL_VULKAN_FUNCTION( function ) +#endif + +//DEVICE_LEVEL_VULKAN_FUNCTION(vkGetDeviceQueue) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDeviceWaitIdle) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyDevice) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateBuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkGetBufferMemoryRequirements) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkAllocateMemory) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkBindBufferMemory) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdPipelineBarrier) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateImage) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkGetImageMemoryRequirements) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkBindImageMemory) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateImageView) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkMapMemory) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkFlushMappedMemoryRanges) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkUnmapMemory) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdCopyBuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdCopyBufferToImage) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdCopyImageToBuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkBeginCommandBuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkEndCommandBuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkQueueSubmit) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyImageView) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyImage) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyBuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkFreeMemory) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateCommandPool) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkAllocateCommandBuffers) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateSemaphore) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateFence) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkWaitForFences) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkResetFences) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyFence) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroySemaphore) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkResetCommandBuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkFreeCommandBuffers) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkResetCommandPool) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyCommandPool) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateBufferView) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyBufferView) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkQueueWaitIdle) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateSampler) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateDescriptorSetLayout) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateDescriptorPool) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkAllocateDescriptorSets) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkUpdateDescriptorSets) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdBindDescriptorSets) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkFreeDescriptorSets) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkResetDescriptorPool) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyDescriptorPool) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyDescriptorSetLayout) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroySampler) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateRenderPass) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateFramebuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyFramebuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyRenderPass) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdBeginRenderPass) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdNextSubpass) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdEndRenderPass) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreatePipelineCache) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkGetPipelineCacheData) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkMergePipelineCaches) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyPipelineCache) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateGraphicsPipelines) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateComputePipelines) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyPipeline) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyEvent) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyQueryPool) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreateShaderModule) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyShaderModule) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCreatePipelineLayout) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkDestroyPipelineLayout) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdBindPipeline) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdSetViewport) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdSetScissor) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdBindVertexBuffers) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdDraw) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdDrawIndexed) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdDispatch) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdCopyImage) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdPushConstants) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdClearColorImage) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdClearDepthStencilImage) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdBindIndexBuffer) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdSetLineWidth) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdSetDepthBias) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdSetBlendConstants) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdExecuteCommands) +//DEVICE_LEVEL_VULKAN_FUNCTION(vkCmdClearAttachments) + +#undef DEVICE_LEVEL_VULKAN_FUNCTION + +// + +#ifndef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION +#define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( function, extension ) +#endif + +//DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkCreateSwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +//DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkGetSwapchainImagesKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +//DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkAcquireNextImageKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +//DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkQueuePresentKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) +//DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION(vkDestroySwapchainKHR, VK_KHR_SWAPCHAIN_EXTENSION_NAME) + +#undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/window.cpp b/engine/src/engine/vulkanapi/window.cpp new file mode 100644 index 0000000..b24c3ab --- /dev/null +++ b/engine/src/engine/vulkanapi/window.cpp @@ -0,0 +1,25 @@ +#include "window.h" +#include "backend.h" +#include "wrapper/instance.h" +#include "wrapper/device.h" +#include "wrapper/swapchain.h" +#include +namespace vulkanapi { + Window::Window(Backend* backend, int frames, uint32_t width, uint32_t height, const char* title) + :renderapi::Window(width, height , title) + , mSurfaceKHR(nullptr) + , mSwapchain(nullptr) + { + VkInstance instance = backend->GetInstance()->Ptr(); + VkWin32SurfaceCreateInfoKHR surface_create_info = { + VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, // VkStructureType sType + nullptr, // const void * pNext + 0, // VkWin32SurfaceCreateFlagsKHR flags + WindowClass::GetInstance(), // HINSTANCE hinstance + mPtr // HWND hwnd + }; + vkCreateWin32SurfaceKHR(instance, &surface_create_info, nullptr, &mSurfaceKHR); + + mSwapchain = new Swapchain(backend->GetDevice(), frames, width, height, mSurfaceKHR); + } +} \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/window.h b/engine/src/engine/vulkanapi/window.h new file mode 100644 index 0000000..b725ec1 --- /dev/null +++ b/engine/src/engine/vulkanapi/window.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include +#include "engine/renderapi/window.h" +#include "vulkan.h" +namespace vulkanapi { + class Backend; + class Swapchain; + class Window : public renderapi::Window { + protected: + VkSurfaceKHR mSurfaceKHR; + Swapchain* mSwapchain; + public: + Window(Backend* backend,int frames, uint32_t width, uint32_t height, const char* title); + }; +}; \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/wrapper/device.cpp b/engine/src/engine/vulkanapi/wrapper/device.cpp new file mode 100644 index 0000000..11cc3a2 --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/device.cpp @@ -0,0 +1,64 @@ +#include "device.h" +#include "device_help.h" +namespace vulkanapi { + Device::Device(VkInstance instance, VkPhysicalDevice physDevice):mPhysical(physDevice) + { + std::vector queue_families; + CheckAvailableQueueFamiliesAndTheirProperties(physDevice, queue_families); + + std::vector queue_create_infos; + _QueueCreateInfos(queue_create_infos, queue_families); + std::vector desired_extensions = { + "VK_KHR_swapchain", + }; + + VkPhysicalDeviceFeatures device_features{}; + _EnabledFeatures(device_features); + VkDeviceCreateInfo device_create_info = { + VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, // VkStructureType sType + nullptr, // const void * pNext + 0, // VkDeviceCreateFlags flags + static_cast(queue_create_infos.size()), // uint32_t queueCreateInfoCount + queue_create_infos.data(), // const VkDeviceQueueCreateInfo * pQueueCreateInfos + 0, // uint32_t enabledLayerCount + nullptr, // const char * const * ppEnabledLayerNames + static_cast(desired_extensions.size()), // uint32_t enabledExtensionCount + desired_extensions.data(), // const char * const * ppEnabledExtensionNames + &device_features // const VkPhysicalDeviceFeatures * pEnabledFeatures + }; + VkResult result = vkCreateDevice(physDevice, &device_create_info, nullptr, &mPtr); + if((result != VK_SUCCESS) || (mPtr == VK_NULL_HANDLE)) { + std::cout << "Could not create logical device." << std::endl; + } + } + uint32_t Device::GetQueueFamilyIndex(VkQueueFlags flag) + { + std::vector queue_families; + CheckAvailableQueueFamiliesAndTheirProperties(mPhysical, queue_families); + for (uint32_t i = 0, l = queue_families.size(); i < l; i++) { + if ((queue_families[i].queueFlags & flag) == flag) { + return i; + } + } + return 0; + } + VkCommandPool Device::CreateCommandPool(const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator) + { + VkCommandPool pCommandPool; + vkCreateCommandPool(mPtr, pCreateInfo, pAllocator, &pCommandPool); + return pCommandPool; + } + VkQueue Device::GetQueue(uint32_t familyIndex, uint32_t queueIndex) + { + VkQueue pQueue; + vkGetDeviceQueue(mPtr, familyIndex, queueIndex, &pQueue); + return pQueue; + } + VkDescriptorPool Device::CreateDescriptorPool(const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator) + { + VkDescriptorPool pDescriptorPool; + vkCreateDescriptorPool(mPtr, pCreateInfo, pAllocator, &pDescriptorPool); + return pDescriptorPool; + } +} + diff --git a/engine/src/engine/vulkanapi/wrapper/device.h b/engine/src/engine/vulkanapi/wrapper/device.h new file mode 100644 index 0000000..562f24d --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/device.h @@ -0,0 +1,25 @@ +#pragma once +#include +#include "../vulkan.h" + +namespace vulkanapi { + class Device{ + protected: + VkDevice mPtr; + VkPhysicalDevice mPhysical; + public: + VkDevice Ptr() { + return mPtr; + } + VkPhysicalDevice GetPhysical() { + return mPhysical; + } + public: + Device(VkInstance ptr, VkPhysicalDevice physDevice); + + uint32_t GetQueueFamilyIndex(VkQueueFlags flag); + VkCommandPool CreateCommandPool(const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator); + VkQueue GetQueue(uint32_t familyIndex, uint32_t queueIndex); + VkDescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator); + }; +}; \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/wrapper/device_help.h b/engine/src/engine/vulkanapi/wrapper/device_help.h new file mode 100644 index 0000000..7f30c7c --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/device_help.h @@ -0,0 +1,43 @@ +#pragma once +#include "../vulkan.h" +#include +#include +#include +namespace vulkanapi { + constexpr float DEFAULT_QUEUE_PRIORITY = 1.0f; + bool CheckAvailableQueueFamiliesAndTheirProperties(VkPhysicalDevice physical_device,std::vector& queue_families) { + uint32_t queue_families_count = 0; + + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, nullptr); + if (queue_families_count == 0) { + std::cout << "Could not get the number of queue families." << std::endl; + return false; + } + + queue_families.resize(queue_families_count); + vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_families_count, queue_families.data()); + if (queue_families_count == 0) { + std::cout << "Could not acquire properties of queue families." << std::endl; + return false; + } + + return true; + } + void _QueueCreateInfos(std::vector& queue_create_infos, std::vector& queue_families) { + for (uint32_t i = 0, l = queue_families.size(); i < l; i++) { + queue_create_infos.push_back({ + VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType + nullptr, // const void * pNext + 0, // VkDeviceQueueCreateFlags flags + i, // uint32_t queueFamilyIndex + 1, // uint32_t queueCount + &DEFAULT_QUEUE_PRIORITY // const float * pQueuePriorities + }); + } + } + void _EnabledFeatures(VkPhysicalDeviceFeatures& device_features) { + device_features.independentBlend = true; + device_features.depthClamp = true; + //device_features.protectedMemory = true; + } +} \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/wrapper/instance.cpp b/engine/src/engine/vulkanapi/wrapper/instance.cpp new file mode 100644 index 0000000..fb96ffc --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/instance.cpp @@ -0,0 +1,80 @@ +#include "instance.h" +#include "instance_help.h" + +const char* vulkanapi::EngineName = "Vulkan"; +std::vector extensions = { + "VK_KHR_surface", + "VK_EXT_debug_utils", + "VK_KHR_get_physical_device_properties2", + "VK_KHR_win32_surface", + "VK_EXT_debug_report", + "VK_KHR_portability_enumeration", +}; +std::vector layers = { + "VK_LAYER_KHRONOS_validation", + //"VK_LAYER_LUNARG_api_dump", +}; +namespace vulkanapi { + Instance::Instance(const char* appName) { + //加载dll + LIBRARY_TYPE vulkan_library; + ConnectWithVulkanLoaderLibrary(vulkan_library); + + //加载vulkan接口 + LoadFunctionExportedFromVulkanLoaderLibrary(vulkan_library); + + //调用vulkan接口,加载全局函数指针 + LoadGlobalLevelFunctions(); + VkApplicationInfo application_info = { + VK_STRUCTURE_TYPE_APPLICATION_INFO, // VkStructureType sType + nullptr, // const void * pNext + appName, // const char * pApplicationName + VK_MAKE_VERSION(1, 0, 0), // uint32_t applicationVersion + EngineName, // const char * pEngineName + VK_MAKE_VERSION(1, 0, 0), // uint32_t engineVersion + VK_MAKE_VERSION(1, 0, 0) // uint32_t apiVersion + }; + extensions = _EnabledExtensionNames(extensions); + layers = _EnabledLayerNames(layers); + VkDebugUtilsMessengerCreateInfoEXT createInfo = _DebugUtilsLayerNext(); + VkInstanceCreateInfo instance_create_info = { + VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // VkStructureType sType + &createInfo, // const void * pNext + 0, // VkInstanceCreateFlags flags + &application_info, // const VkApplicationInfo * pApplicationInfo + static_cast(layers.size()), // uint32_t enabledLayerCount + layers.data(), // const char * const * ppEnabledLayerNames + static_cast(extensions.size()), // uint32_t enabledExtensionCount + extensions.data() // const char * const * ppEnabledExtensionNames + }; + VkResult result = vkCreateInstance(&instance_create_info, nullptr, &mPtr); + if ((result != VK_SUCCESS) || (mPtr == VK_NULL_HANDLE)) { + std::cout << "Could not create Instance." << std::endl; + } + + //调用vulkan接口,加载实例函数指针 + LoadInstanceLevelFunctions(mPtr, extensions); + } + bool Instance::EnumerateAvailablePhysicalDevices(std::vector& available_devices) + { + uint32_t devices_count = 0; + VkResult result = VK_SUCCESS; + + result = vkEnumeratePhysicalDevices(mPtr, &devices_count, nullptr); + if ((result != VK_SUCCESS) || + (devices_count == 0)) { + std::cout << "Could not get the number of available physical devices." << std::endl; + return false; + } + + available_devices.resize(devices_count); + result = vkEnumeratePhysicalDevices(mPtr, &devices_count, available_devices.data()); + if ((result != VK_SUCCESS) || + (devices_count == 0)) { + std::cout << "Could not enumerate physical devices." << std::endl; + return false; + } + + return true; + } +}; \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/wrapper/instance.h b/engine/src/engine/vulkanapi/wrapper/instance.h new file mode 100644 index 0000000..edb4a45 --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/instance.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include "../vulkan.h" + +namespace vulkanapi { + class Instance{ + protected: + VkInstance mPtr; + public: + Instance(const char* appName); + + VkInstance Ptr() { + return mPtr; + } + bool EnumerateAvailablePhysicalDevices(std::vector& available_devices); + }; +}; \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/wrapper/instance_help.h b/engine/src/engine/vulkanapi/wrapper/instance_help.h new file mode 100644 index 0000000..0a2e0b3 --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/instance_help.h @@ -0,0 +1,190 @@ +#pragma once +#include "../vulkan.h" +#include +#include +#include +namespace vulkanapi { + bool ConnectWithVulkanLoaderLibrary(LIBRARY_TYPE& vulkan_library) { +#if defined _WIN32 + vulkan_library = LoadLibrary("vulkan-1.dll"); +#elif defined __linux + vulkan_library = dlopen("libvulkan.so.1", RTLD_NOW); +#endif + + if (vulkan_library == nullptr) { + std::cout << "Could not connect with a Vulkan Runtime library." << std::endl; + return false; + } + return true; + } + bool LoadFunctionExportedFromVulkanLoaderLibrary(LIBRARY_TYPE const& vulkan_library) { +#if defined _WIN32 +#define LoadFunction GetProcAddress +#elif defined __linux +#define LoadFunction dlsym +#endif + +#define EXPORTED_VULKAN_FUNCTION( name ) \ + name = (PFN_##name)LoadFunction( vulkan_library, #name ); \ + if( name == nullptr ) { \ + std::cout << "Could not load exported Vulkan function named: " \ + #name << std::endl; \ + return false; \ + } +#include "engine/vulkanapi/vulkan_function_list.inl" + return true; + } + + bool LoadGlobalLevelFunctions() { +#define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) \ + name = (PFN_##name)vkGetInstanceProcAddr( nullptr, #name ); \ + if( name == nullptr ) { \ + std::cout << "Could not load global level Vulkan function named: " \ + #name << std::endl; \ + return false; \ + } + +#include "engine/vulkanapi/vulkan_function_list.inl" + + return true; + } + bool LoadInstanceLevelFunctions(VkInstance instance, + std::vector const& enabled_extensions) { + // Load core Vulkan API instance-level functions +#define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) \ + name = (PFN_##name)vkGetInstanceProcAddr( instance, #name ); \ + if( name == nullptr ) { \ + std::cout << "Could not load instance-level Vulkan function named: " \ + #name << std::endl; \ + return false; \ + } + + // Load instance-level functions from enabled extensions +#define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) \ + for( auto & enabled_extension : enabled_extensions ) { \ + if( std::string( enabled_extension ) == std::string( extension ) ) { \ + name = (PFN_##name)vkGetInstanceProcAddr( instance, #name ); \ + if( name == nullptr ) { \ + std::cout << "Could not load instance-level Vulkan function named: " \ + #name << std::endl; \ + return false; \ + } \ + } \ + } + +#include "engine/vulkanapi/vulkan_function_list.inl" + + return true; + } + bool IsExtensionSupported(std::vector const& available_extensions, + char const* const extension) { + for (auto& available_extension : available_extensions) { + if (strstr(available_extension.extensionName, extension)) { + return true; + } + } + return false; + } + bool IsLayerSupported(std::vector const& available_layers, + char const* const layer) { + for (auto& available_layer : available_layers) { + if (strstr(available_layer.layerName, layer)) { + return true; + } + } + return false; + } + bool CheckAvailableInstanceLayers(std::vector& available_layers) { + uint32_t extensions_count = 0; + VkResult result = VK_SUCCESS; + + result = vkEnumerateInstanceLayerProperties(&extensions_count, nullptr); + if ((result != VK_SUCCESS) || + (extensions_count == 0)) { + std::cout << "Could not get the number of instance layers." << std::endl; + return false; + } + + available_layers.resize(extensions_count); + result = vkEnumerateInstanceLayerProperties(&extensions_count, available_layers.data()); + if ((result != VK_SUCCESS) || + (extensions_count == 0)) { + std::cout << "Could not enumerate instance layers." << std::endl; + return false; + } + + return true; + } + bool CheckAvailableInstanceExtensions(std::vector& available_extensions) { + uint32_t extensions_count = 0; + VkResult result = VK_SUCCESS; + + result = vkEnumerateInstanceExtensionProperties(nullptr, &extensions_count, nullptr); + if ((result != VK_SUCCESS) || + (extensions_count == 0)) { + std::cout << "Could not get the number of instance extensions." << std::endl; + return false; + } + + available_extensions.resize(extensions_count); + result = vkEnumerateInstanceExtensionProperties(nullptr, &extensions_count, available_extensions.data()); + if ((result != VK_SUCCESS) || + (extensions_count == 0)) { + std::cout << "Could not enumerate instance extensions." << std::endl; + return false; + } + + return true; + } + std::vector _EnabledExtensionNames(std::vector& extensions) { + std::vector available_extensions; + std::vector _extension; + if (!CheckAvailableInstanceExtensions(available_extensions)) { + return _extension; + } + for (int i = 0, l = extensions.size(); i < l; i++) { + if (IsExtensionSupported(available_extensions, extensions[i])) { + _extension.push_back(extensions[i]); + } + else { + std::cout << "cann't support extension: " << extensions[i] << std::endl; + } + } + return _extension; + } + std::vector _EnabledLayerNames(std::vector& layers) { + std::vector available_layers; + std::vector _layers; + if (!CheckAvailableInstanceLayers(available_layers)) { + return _layers; + } + for (int i = 0, l = layers.size(); i < l; i++) { + if (IsLayerSupported(available_layers, layers[i])) { + _layers.push_back(layers[i]); + } + else { + std::cout << "cann't support layer: " << layers[i] << std::endl; + } + } + return _layers; + } + // debug callback + static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT, + VkDebugUtilsMessageTypeFlagsEXT, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void*) + { + std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl; + return VK_FALSE; + } + VkDebugUtilsMessengerCreateInfoEXT _DebugUtilsLayerNext() { + VkDebugUtilsMessengerCreateInfoEXT createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + createInfo.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + createInfo.messageType = + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + createInfo.pfnUserCallback = debugCallback; + return createInfo; + } +}; \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/wrapper/swapchain.cpp b/engine/src/engine/vulkanapi/wrapper/swapchain.cpp new file mode 100644 index 0000000..92a7beb --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/swapchain.cpp @@ -0,0 +1,33 @@ +#include "swapchain.h" +#include "swapchain_help.h" +#include "device.h" +namespace vulkanapi { + Swapchain::Swapchain(Device* device, int frames, int width, int height, VkSurfaceKHR presentation_surface) + : mPtr(nullptr) + { + uint32_t queue_family_index; + VkPhysicalDevice physical_device = device->GetPhysical(); + + //选择交换链图像的格式与颜色空间 + VkFormat image_format; + VkColorSpaceKHR image_color_space; + SelectFormatOfSwapchainImages(physical_device, presentation_surface, { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }, + image_format, image_color_space); + + VkSurfaceCapabilitiesKHR surface_capabilities; + GetCapabilitiesOfPresentationSurface(physical_device, presentation_surface, surface_capabilities); + + VkExtent2D image_size{ (uint32_t)width ,(uint32_t)height }; + ChooseSizeOfSwapchainImages(surface_capabilities, image_size); + + //调用设备接口,创建交换链 + VkSwapchainKHR old_swapchain = VK_NULL_HANDLE; + VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + CreateSwapchain(device->Ptr(), presentation_surface, frames, { image_format, image_color_space }, image_size + , imageUsage, VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,VK_PRESENT_MODE_FIFO_KHR, old_swapchain, mPtr); + + std::vector swapchain_images; + GetHandlesOfSwapchainImages(device->Ptr(), mPtr, swapchain_images); + + } +} diff --git a/engine/src/engine/vulkanapi/wrapper/swapchain.h b/engine/src/engine/vulkanapi/wrapper/swapchain.h new file mode 100644 index 0000000..9d59dff --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/swapchain.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include +#include "../vulkan.h" + +namespace vulkanapi { + class Device; + class Image; + class Swapchain { + protected: + VkSwapchainKHR mPtr; + std::vector mImages; + public: + Swapchain(Device* device,int frames, int width, int height, VkSurfaceKHR presentation_surface); + }; +}; \ No newline at end of file diff --git a/engine/src/engine/vulkanapi/wrapper/swapchain_help.h b/engine/src/engine/vulkanapi/wrapper/swapchain_help.h new file mode 100644 index 0000000..81f48c4 --- /dev/null +++ b/engine/src/engine/vulkanapi/wrapper/swapchain_help.h @@ -0,0 +1,160 @@ +#include "instance.h" +#include +namespace vulkanapi { + bool GetCapabilitiesOfPresentationSurface(VkPhysicalDevice physical_device, + VkSurfaceKHR presentation_surface, + VkSurfaceCapabilitiesKHR& surface_capabilities) { + VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, presentation_surface, &surface_capabilities); + + if (VK_SUCCESS != result) { + std::cout << "Could not get the capabilities of a presentation surface." << std::endl; + return false; + } + return true; + } + bool ChooseSizeOfSwapchainImages(VkSurfaceCapabilitiesKHR const& surface_capabilities, + VkExtent2D& size_of_images) { + if (0xFFFFFFFF == surface_capabilities.currentExtent.width) { + if (size_of_images.width < surface_capabilities.minImageExtent.width) { + size_of_images.width = surface_capabilities.minImageExtent.width; + } + else if (size_of_images.width > surface_capabilities.maxImageExtent.width) { + size_of_images.width = surface_capabilities.maxImageExtent.width; + } + + if (size_of_images.height < surface_capabilities.minImageExtent.height) { + size_of_images.height = surface_capabilities.minImageExtent.height; + } + else if (size_of_images.height > surface_capabilities.maxImageExtent.height) { + size_of_images.height = surface_capabilities.maxImageExtent.height; + } + } + else { + size_of_images = surface_capabilities.currentExtent; + } + return true; + } + bool SelectFormatOfSwapchainImages(VkPhysicalDevice physical_device, + VkSurfaceKHR presentation_surface, + VkSurfaceFormatKHR desired_surface_format, + VkFormat& image_format, + VkColorSpaceKHR& image_color_space) { + // Enumerate supported formats + uint32_t formats_count = 0; + VkResult result = VK_SUCCESS; + + result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, presentation_surface, &formats_count, nullptr); + if ((VK_SUCCESS != result) || + (0 == formats_count)) { + std::cout << "Could not get the number of supported surface formats." << std::endl; + return false; + } + + std::vector surface_formats(formats_count); + result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, presentation_surface, &formats_count, surface_formats.data()); + if ((VK_SUCCESS != result) || + (0 == formats_count)) { + std::cout << "Could not enumerate supported surface formats." << std::endl; + return false; + } + + // Select surface format + if ((1 == surface_formats.size()) && + (VK_FORMAT_UNDEFINED == surface_formats[0].format)) { + image_format = desired_surface_format.format; + image_color_space = desired_surface_format.colorSpace; + return true; + } + + for (auto& surface_format : surface_formats) { + if ((desired_surface_format.format == surface_format.format) && + (desired_surface_format.colorSpace == surface_format.colorSpace)) { + image_format = desired_surface_format.format; + image_color_space = desired_surface_format.colorSpace; + return true; + } + } + + for (auto& surface_format : surface_formats) { + if (desired_surface_format.format == surface_format.format) { + image_format = desired_surface_format.format; + image_color_space = surface_format.colorSpace; + std::cout << "Desired combination of format and colorspace is not supported. Selecting other colorspace." << std::endl; + return true; + } + } + + image_format = surface_formats[0].format; + image_color_space = surface_formats[0].colorSpace; + std::cout << "Desired format is not supported. Selecting available format - colorspace combination." << std::endl; + return true; + } + bool CreateSwapchain(VkDevice logical_device, + VkSurfaceKHR presentation_surface, + uint32_t image_count, + VkSurfaceFormatKHR surface_format, + VkExtent2D image_size, + VkImageUsageFlags image_usage, + VkSurfaceTransformFlagBitsKHR surface_transform, + VkPresentModeKHR present_mode, + VkSwapchainKHR& old_swapchain, + VkSwapchainKHR& swapchain) { + VkSwapchainCreateInfoKHR swapchain_create_info = { + VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // VkStructureType sType + nullptr, // const void * pNext + 0, // VkSwapchainCreateFlagsKHR flags + presentation_surface, // VkSurfaceKHR surface + image_count, // uint32_t minImageCount + surface_format.format, // VkFormat imageFormat + surface_format.colorSpace, // VkColorSpaceKHR imageColorSpace + image_size, // VkExtent2D imageExtent + 1, // uint32_t imageArrayLayers + image_usage, // VkImageUsageFlags imageUsage + VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode imageSharingMode + 0, // uint32_t queueFamilyIndexCount + nullptr, // const uint32_t * pQueueFamilyIndices + surface_transform, // VkSurfaceTransformFlagBitsKHR preTransform + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, // VkCompositeAlphaFlagBitsKHR compositeAlpha + present_mode, // VkPresentModeKHR presentMode + VK_TRUE, // VkBool32 clipped + old_swapchain // VkSwapchainKHR oldSwapchain + }; + + VkResult result = vkCreateSwapchainKHR(logical_device, &swapchain_create_info, nullptr, &swapchain); + if ((VK_SUCCESS != result) || + (VK_NULL_HANDLE == swapchain)) { + std::cout << "Could not create a swapchain." << std::endl; + return false; + } + + if (VK_NULL_HANDLE != old_swapchain) { + vkDestroySwapchainKHR(logical_device, old_swapchain, nullptr); + old_swapchain = VK_NULL_HANDLE; + } + + return true; + } + bool GetHandlesOfSwapchainImages(VkDevice logical_device, + VkSwapchainKHR swapchain, + std::vector& swapchain_images) { + uint32_t images_count = 0; + VkResult result = VK_SUCCESS; + + result = vkGetSwapchainImagesKHR(logical_device, swapchain, &images_count, nullptr); + if ((VK_SUCCESS != result) || + (0 == images_count)) { + std::cout << "Could not get the number of swapchain images." << std::endl; + return false; + } + + swapchain_images.resize(images_count); + result = vkGetSwapchainImagesKHR(logical_device, swapchain, &images_count, swapchain_images.data()); + if ((VK_SUCCESS != result) || + (0 == images_count)) { + std::cout << "Could not enumerate swapchain images." << std::endl; + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/engine/src/main.cpp b/engine/src/main.cpp index 22650cf..6d76c77 100644 --- a/engine/src/main.cpp +++ b/engine/src/main.cpp @@ -1,9 +1,16 @@ #include +#include +#include "engine/vulkanapi/backend.h" +#include "engine/vulkanapi/window.h" using namespace std; - int main(int argc, char** argv) { const char* name = "hello"; cout << name << endl; + auto vulkan = vulkanapi::Backend(name); + auto wnd = vulkanapi::Window(&vulkan, 3, 640, 720, name); + while (true) { + this_thread::sleep_for(chrono::milliseconds(1000)); + } return 0; } diff --git a/engine/xmake.lua b/engine/xmake.lua index ee42e84..94e1242 100644 --- a/engine/xmake.lua +++ b/engine/xmake.lua @@ -8,4 +8,4 @@ target("zengine") add_includedirs("src") add_syslinks("user32") add_files("src/*.cpp", "src/**.cpp") - --add_headerfiles("src/**.h", "src/**.inl") \ No newline at end of file + add_headerfiles("src/**.h", "src/**.inl") \ No newline at end of file