AliMehrabani
4 weeks ago
23 changed files with 1349 additions and 163 deletions
@ -1,2 +1,4 @@ |
|||||
.gradle/ |
.gradle/ |
||||
build/ |
build/ |
||||
|
third_party/ |
||||
|
glm/ |
||||
|
@ -0,0 +1,29 @@ |
|||||
|
QMAKE_CXX.QT_COMPILER_STDCXX = 201402L |
||||
|
QMAKE_CXX.QMAKE_CLANG_MAJOR_VERSION = 8 |
||||
|
QMAKE_CXX.QMAKE_CLANG_MINOR_VERSION = 0 |
||||
|
QMAKE_CXX.QMAKE_CLANG_PATCH_VERSION = 7 |
||||
|
QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 4 |
||||
|
QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 2 |
||||
|
QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 1 |
||||
|
QMAKE_CXX.COMPILER_MACROS = \ |
||||
|
QT_COMPILER_STDCXX \ |
||||
|
QMAKE_CLANG_MAJOR_VERSION \ |
||||
|
QMAKE_CLANG_MINOR_VERSION \ |
||||
|
QMAKE_CLANG_PATCH_VERSION \ |
||||
|
QMAKE_GCC_MAJOR_VERSION \ |
||||
|
QMAKE_GCC_MINOR_VERSION \ |
||||
|
QMAKE_GCC_PATCH_VERSION |
||||
|
QMAKE_CXX.INCDIRS = \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sysroot/usr/include/aarch64-linux-android \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sources/cxx-stl/llvm-libc++/include \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sources/android/support/include \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sources/cxx-stl/llvm-libc++abi/include \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/8.0.7/include \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sysroot/usr/include |
||||
|
QMAKE_CXX.LIBDIRS = \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/8.0.7 \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/8.0.7/lib/linux/aarch64 \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/lib/gcc/aarch64-linux-android/4.9.x \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/aarch64-linux-android/lib64 \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/aarch64-linux-android/lib \ |
||||
|
/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/platforms/android-21/arch-arm64/usr/lib |
@ -0,0 +1,6 @@ |
|||||
|
#include "VkDescriptors.h" |
||||
|
|
||||
|
VkDescriptors::VkDescriptors() |
||||
|
{ |
||||
|
|
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
#ifndef VKDESCRIPTORS_H |
||||
|
#define VKDESCRIPTORS_H |
||||
|
|
||||
|
#include <QObject> |
||||
|
|
||||
|
class VkDescriptors |
||||
|
{ |
||||
|
public: |
||||
|
VkDescriptors(); |
||||
|
}; |
||||
|
|
||||
|
#endif // VKDESCRIPTORS_H
|
@ -0,0 +1,402 @@ |
|||||
|
#include "VkEngine.h" |
||||
|
|
||||
|
#include <SDL.h> |
||||
|
#include <SDL_vulkan.h> |
||||
|
|
||||
|
#include <VkInitializers.h> |
||||
|
#include <VkTypes.h> |
||||
|
|
||||
|
//bootstrap library
|
||||
|
#include "VkBootstrap.h" |
||||
|
#include "VkImages.h" |
||||
|
|
||||
|
#define VMA_IMPLEMENTATION |
||||
|
#include "vma/vk_mem_alloc.h" |
||||
|
|
||||
|
#include <chrono> |
||||
|
#include <thread> |
||||
|
//< includes
|
||||
|
|
||||
|
//> init
|
||||
|
constexpr bool bUseValidationLayers = false; |
||||
|
|
||||
|
VkEngine* loadedEngine = nullptr; |
||||
|
|
||||
|
VkEngine::VkEngine() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
VkEngine& VkEngine::Get() |
||||
|
{ |
||||
|
return *loadedEngine; |
||||
|
} |
||||
|
|
||||
|
void VkEngine::init() |
||||
|
{ |
||||
|
// only one engine initialization is allowed with the application.
|
||||
|
assert(loadedEngine == nullptr); |
||||
|
loadedEngine = this; |
||||
|
|
||||
|
// We initialize SDL and create a window with it.
|
||||
|
SDL_Init(SDL_INIT_VIDEO); |
||||
|
|
||||
|
SDL_WindowFlags window_flags = static_cast<SDL_WindowFlags>(SDL_WINDOW_VULKAN); |
||||
|
|
||||
|
_window = SDL_CreateWindow( |
||||
|
"Vulkan Engine", |
||||
|
SDL_WINDOWPOS_UNDEFINED, |
||||
|
SDL_WINDOWPOS_UNDEFINED, |
||||
|
_windowExtent.width, |
||||
|
_windowExtent.height, |
||||
|
window_flags); |
||||
|
|
||||
|
init_vulkan(); |
||||
|
|
||||
|
init_swapchain(); |
||||
|
|
||||
|
init_commands(); |
||||
|
|
||||
|
init_sync_structures(); |
||||
|
|
||||
|
// everything went fine
|
||||
|
_isInitialized = true; |
||||
|
} |
||||
|
|
||||
|
void VkEngine::cleanup() |
||||
|
{ |
||||
|
if (_isInitialized) { |
||||
|
|
||||
|
vkDeviceWaitIdle(_device); |
||||
|
|
||||
|
for (int i = 0; i < static_cast<int>(FRAME_OVERLAP); i++) |
||||
|
{ |
||||
|
//already written from before
|
||||
|
vkDestroyCommandPool(_device, _frames[i]._commandPool, nullptr); |
||||
|
|
||||
|
//destroy sync objects
|
||||
|
vkDestroyFence(_device, _frames[i]._renderFence, nullptr); |
||||
|
vkDestroySemaphore(_device, _frames[i]._renderSemaphore, nullptr); |
||||
|
vkDestroySemaphore(_device ,_frames[i]._swapchainSemaphore, nullptr); |
||||
|
|
||||
|
_frames[i]._deletionQueue.flush(); |
||||
|
} |
||||
|
|
||||
|
_mainDeletionQueue.flush(); |
||||
|
|
||||
|
vkDeviceWaitIdle(_device); |
||||
|
|
||||
|
for (int i = 0; i < static_cast<int>(FRAME_OVERLAP); i++) { |
||||
|
vkDestroyCommandPool(_device, _frames[i]._commandPool, nullptr); |
||||
|
} |
||||
|
|
||||
|
destroy_swapchain(); |
||||
|
|
||||
|
vkDestroySurfaceKHR(_instance, _surface, nullptr); |
||||
|
vkDestroyDevice(_device, nullptr); |
||||
|
|
||||
|
vkb::destroy_debug_utils_messenger(_instance, _debug_messenger); |
||||
|
vkDestroyInstance(_instance, nullptr); |
||||
|
SDL_DestroyWindow(_window); |
||||
|
} |
||||
|
|
||||
|
// clear engine pointer
|
||||
|
loadedEngine = nullptr; |
||||
|
} |
||||
|
|
||||
|
void VkEngine::draw() |
||||
|
{ |
||||
|
// wait until the gpu has finished rendering the last frame. Timeout of 1
|
||||
|
// second
|
||||
|
VK_CHECK(vkWaitForFences(_device, 1, &get_current_frame()._renderFence, true, 1000000000)); |
||||
|
|
||||
|
get_current_frame()._deletionQueue.flush(); |
||||
|
|
||||
|
VK_CHECK(vkResetFences(_device, 1, &get_current_frame()._renderFence)); |
||||
|
|
||||
|
uint32_t swapchainImageIndex; |
||||
|
VK_CHECK(vkAcquireNextImageKHR(_device, _swapchain, 1000000000, get_current_frame()._swapchainSemaphore, nullptr, &swapchainImageIndex)); |
||||
|
|
||||
|
//naming it cmd for shorter writing
|
||||
|
VkCommandBuffer cmd = get_current_frame()._mainCommandBuffer; |
||||
|
|
||||
|
// now that we are sure that the commands finished executing, we can safely
|
||||
|
// reset the command buffer to begin recording again.
|
||||
|
VK_CHECK(vkResetCommandBuffer(cmd, 0)); |
||||
|
|
||||
|
//begin the command buffer recording. We will use this command buffer exactly once, so we want to let vulkan know that
|
||||
|
VkCommandBufferBeginInfo cmdBeginInfo = vkinit::command_buffer_begin_info(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); |
||||
|
|
||||
|
//start the command buffer recording
|
||||
|
VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo)); |
||||
|
|
||||
|
//make the swapchain image into writeable mode before rendering
|
||||
|
vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL); |
||||
|
|
||||
|
//make a clear-color from frame number. This will flash with a 120 frame period.
|
||||
|
VkClearColorValue clearValue; |
||||
|
float flash = std::abs(std::sin(_frameNumber / 120.f)); |
||||
|
clearValue = { { 0.0f, 0.0f, flash, 1.0f } }; |
||||
|
|
||||
|
VkImageSubresourceRange clearRange = vkinit::image_subresource_range(VK_IMAGE_ASPECT_COLOR_BIT); |
||||
|
|
||||
|
//clear image
|
||||
|
vkCmdClearColorImage(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1, &clearRange); |
||||
|
|
||||
|
//make the swapchain image into presentable mode
|
||||
|
vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex],VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); |
||||
|
|
||||
|
//finalize the command buffer (we can no longer add commands, but it can now be executed)
|
||||
|
VK_CHECK(vkEndCommandBuffer(cmd)); |
||||
|
|
||||
|
//prepare the submission to the queue.
|
||||
|
//we want to wait on the _presentSemaphore, as that semaphore is signaled when the swapchain is ready
|
||||
|
//we will signal the _renderSemaphore, to signal that rendering has finished
|
||||
|
|
||||
|
VkCommandBufferSubmitInfo cmdinfo = vkinit::command_buffer_submit_info(cmd); |
||||
|
|
||||
|
VkSemaphoreSubmitInfo waitInfo = vkinit::semaphore_submit_info(VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR,get_current_frame()._swapchainSemaphore); |
||||
|
VkSemaphoreSubmitInfo signalInfo = vkinit::semaphore_submit_info(VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, get_current_frame()._renderSemaphore); |
||||
|
|
||||
|
VkSubmitInfo2 submit = vkinit::submit_info(&cmdinfo,&signalInfo,&waitInfo); |
||||
|
|
||||
|
//submit command buffer to the queue and execute it.
|
||||
|
// _renderFence will now block until the graphic commands finish execution
|
||||
|
VK_CHECK(vkQueueSubmit2(_graphicsQueue, 1, &submit, get_current_frame()._renderFence)); |
||||
|
|
||||
|
//prepare present
|
||||
|
// this will put the image we just rendered to into the visible window.
|
||||
|
// we want to wait on the _renderSemaphore for that,
|
||||
|
// as its necessary that drawing commands have finished before the image is displayed to the user
|
||||
|
VkPresentInfoKHR presentInfo = {}; |
||||
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; |
||||
|
presentInfo.pNext = nullptr; |
||||
|
presentInfo.pSwapchains = &_swapchain; |
||||
|
presentInfo.swapchainCount = 1; |
||||
|
|
||||
|
presentInfo.pWaitSemaphores = &get_current_frame()._renderSemaphore; |
||||
|
presentInfo.waitSemaphoreCount = 1; |
||||
|
|
||||
|
presentInfo.pImageIndices = &swapchainImageIndex; |
||||
|
|
||||
|
VK_CHECK(vkQueuePresentKHR(_graphicsQueue, &presentInfo)); |
||||
|
|
||||
|
//increase the number of frames drawn
|
||||
|
_frameNumber++; |
||||
|
} |
||||
|
//< extras
|
||||
|
|
||||
|
//> drawloop
|
||||
|
void VkEngine::run() |
||||
|
{ |
||||
|
SDL_Event e; |
||||
|
bool bQuit = false; |
||||
|
|
||||
|
// main loop
|
||||
|
while (!bQuit) { |
||||
|
// Handle events on queue
|
||||
|
while (SDL_PollEvent(&e) != 0) { |
||||
|
// close the window when user alt-f4s or clicks the X button
|
||||
|
if (e.type == SDL_QUIT) |
||||
|
bQuit = true; |
||||
|
|
||||
|
if (e.type == SDL_WINDOWEVENT) { |
||||
|
if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) { |
||||
|
stop_rendering = true; |
||||
|
} |
||||
|
if (e.window.event == SDL_WINDOWEVENT_RESTORED) { |
||||
|
stop_rendering = false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// do not draw if we are minimized
|
||||
|
if (stop_rendering) { |
||||
|
// throttle the speed to avoid the endless spinning
|
||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
draw(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void VkEngine::init_vulkan() |
||||
|
{ |
||||
|
vkb::InstanceBuilder builder; |
||||
|
|
||||
|
//make the vulkan instance, with basic debug features
|
||||
|
auto inst_ret = builder.set_app_name("Example Vulkan Application") |
||||
|
.request_validation_layers(bUseValidationLayers) |
||||
|
.use_default_debug_messenger() |
||||
|
.require_api_version(1, 3, 0) |
||||
|
.build(); |
||||
|
|
||||
|
vkb::Instance vkb_inst = inst_ret.value(); |
||||
|
|
||||
|
//grab the instance
|
||||
|
_instance = vkb_inst.instance; |
||||
|
_debug_messenger = vkb_inst.debug_messenger; |
||||
|
|
||||
|
SDL_Vulkan_CreateSurface(_window, _instance, &_surface); |
||||
|
|
||||
|
//vulkan 1.3 features
|
||||
|
VkPhysicalDeviceVulkan13Features features{}; |
||||
|
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; |
||||
|
features.dynamicRendering = true; |
||||
|
features.synchronization2 = true; |
||||
|
|
||||
|
//vulkan 1.2 features
|
||||
|
VkPhysicalDeviceVulkan12Features features12{}; |
||||
|
features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; |
||||
|
features12.bufferDeviceAddress = true; |
||||
|
features12.descriptorIndexing = true; |
||||
|
|
||||
|
|
||||
|
//use vkbootstrap to select a gpu.
|
||||
|
//We want a gpu that can write to the SDL surface and supports vulkan 1.3 with the correct features
|
||||
|
vkb::PhysicalDeviceSelector selector{ vkb_inst }; |
||||
|
vkb::PhysicalDevice physicalDevice = selector |
||||
|
.set_minimum_version(1, 3) |
||||
|
.set_required_features_13(features) |
||||
|
.set_required_features_12(features12) |
||||
|
.set_surface(_surface) |
||||
|
.select() |
||||
|
.value(); |
||||
|
|
||||
|
|
||||
|
//create the final vulkan device
|
||||
|
vkb::DeviceBuilder deviceBuilder{ physicalDevice }; |
||||
|
|
||||
|
vkb::Device vkbDevice = deviceBuilder.build().value(); |
||||
|
|
||||
|
// Get the VkDevice handle used in the rest of a vulkan application
|
||||
|
_device = vkbDevice.device; |
||||
|
_chosenGPU = physicalDevice.physical_device; |
||||
|
|
||||
|
_graphicsQueue = vkbDevice.get_queue(vkb::QueueType::graphics).value(); |
||||
|
_graphicsQueueFamily = vkbDevice.get_queue_index(vkb::QueueType::graphics).value(); |
||||
|
|
||||
|
// initialize the memory allocator
|
||||
|
VmaAllocatorCreateInfo allocatorInfo = {}; |
||||
|
allocatorInfo.physicalDevice = _chosenGPU; |
||||
|
allocatorInfo.device = _device; |
||||
|
allocatorInfo.instance = _instance; |
||||
|
allocatorInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT; |
||||
|
vmaCreateAllocator(&allocatorInfo, &_allocator); |
||||
|
|
||||
|
_mainDeletionQueue.push_function([&]() { |
||||
|
vmaDestroyAllocator(_allocator); |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void VkEngine::create_swapchain(uint32_t width, uint32_t height) |
||||
|
{ |
||||
|
vkb::SwapchainBuilder swapchainBuilder{ _chosenGPU,_device,_surface }; |
||||
|
|
||||
|
_swapchainImageFormat = VK_FORMAT_B8G8R8A8_UNORM; |
||||
|
|
||||
|
vkb::Swapchain vkbSwapchain = swapchainBuilder |
||||
|
//.use_default_format_selection()
|
||||
|
.set_desired_format(VkSurfaceFormatKHR{ .format = _swapchainImageFormat, .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }) |
||||
|
//use vsync present mode
|
||||
|
.set_desired_present_mode(VK_PRESENT_MODE_FIFO_KHR) |
||||
|
.set_desired_extent(width, height) |
||||
|
.add_image_usage_flags(VK_IMAGE_USAGE_TRANSFER_DST_BIT) |
||||
|
.build() |
||||
|
.value(); |
||||
|
|
||||
|
_swapchainExtent = vkbSwapchain.extent; |
||||
|
//store swapchain and its related images
|
||||
|
_swapchain = vkbSwapchain.swapchain; |
||||
|
_swapchainImages = vkbSwapchain.get_images().value(); |
||||
|
_swapchainImageViews = vkbSwapchain.get_image_views().value(); |
||||
|
} |
||||
|
|
||||
|
void VkEngine::destroy_swapchain() |
||||
|
{ |
||||
|
vkDestroySwapchainKHR(_device, _swapchain, nullptr); |
||||
|
|
||||
|
// destroy swapchain resources
|
||||
|
for (int i = 0; i < static_cast<int>(_swapchainImageViews.size()); i++) { |
||||
|
|
||||
|
vkDestroyImageView(_device, _swapchainImageViews[i], nullptr); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void VkEngine::init_swapchain() |
||||
|
{ |
||||
|
create_swapchain(_windowExtent.width, _windowExtent.height); |
||||
|
|
||||
|
//draw image size will match the window
|
||||
|
VkExtent3D drawImageExtent = { |
||||
|
_windowExtent.width, |
||||
|
_windowExtent.height, |
||||
|
1 |
||||
|
}; |
||||
|
|
||||
|
//hardcoding the draw format to 32 bit float
|
||||
|
_drawImage.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; |
||||
|
_drawImage.imageExtent = drawImageExtent; |
||||
|
|
||||
|
VkImageUsageFlags drawImageUsages{}; |
||||
|
drawImageUsages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; |
||||
|
drawImageUsages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; |
||||
|
drawImageUsages |= VK_IMAGE_USAGE_STORAGE_BIT; |
||||
|
drawImageUsages |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; |
||||
|
|
||||
|
VkImageCreateInfo rimg_info = vkinit::image_create_info(_drawImage.imageFormat, drawImageUsages, drawImageExtent); |
||||
|
|
||||
|
//for the draw image, we want to allocate it from gpu local memory
|
||||
|
VmaAllocationCreateInfo rimg_allocinfo = {}; |
||||
|
rimg_allocinfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; |
||||
|
rimg_allocinfo.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
||||
|
|
||||
|
//allocate and create the image
|
||||
|
vmaCreateImage(_allocator, &rimg_info, &rimg_allocinfo, &_drawImage.image, &_drawImage.allocation, nullptr); |
||||
|
|
||||
|
//build a image-view for the draw image to use for rendering
|
||||
|
VkImageViewCreateInfo rview_info = vkinit::imageview_create_info(_drawImage.imageFormat, _drawImage.image, VK_IMAGE_ASPECT_COLOR_BIT); |
||||
|
|
||||
|
VK_CHECK(vkCreateImageView(_device, &rview_info, nullptr, &_drawImage.imageView)); |
||||
|
|
||||
|
//add to deletion queues
|
||||
|
_mainDeletionQueue.push_function([=]() { |
||||
|
vkDestroyImageView(_device, _drawImage.imageView, nullptr); |
||||
|
vmaDestroyImage(_allocator, _drawImage.image, _drawImage.allocation); |
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void VkEngine::init_commands() |
||||
|
{ |
||||
|
VkCommandPoolCreateInfo commandPoolInfo = vkinit::command_pool_create_info(_graphicsQueueFamily, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); |
||||
|
|
||||
|
for (int i = 0; i < static_cast<int>(FRAME_OVERLAP); i++) { |
||||
|
|
||||
|
VK_CHECK(vkCreateCommandPool(_device, &commandPoolInfo, nullptr, &_frames[i]._commandPool)); |
||||
|
|
||||
|
// allocate the default command buffer that we will use for rendering
|
||||
|
VkCommandBufferAllocateInfo cmdAllocInfo = vkinit::command_buffer_allocate_info(_frames[i]._commandPool, 1); |
||||
|
|
||||
|
VK_CHECK(vkAllocateCommandBuffers(_device, &cmdAllocInfo, &_frames[i]._mainCommandBuffer)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void VkEngine::init_sync_structures() |
||||
|
{ |
||||
|
//create syncronization structures
|
||||
|
//one fence to control when the gpu has finished rendering the frame,
|
||||
|
//and 2 semaphores to syncronize rendering with swapchain
|
||||
|
//we want the fence to start signalled so we can wait on it on the first frame
|
||||
|
VkFenceCreateInfo fenceCreateInfo = vkinit::fence_create_info(VK_FENCE_CREATE_SIGNALED_BIT); |
||||
|
VkSemaphoreCreateInfo semaphoreCreateInfo = vkinit::semaphore_create_info(); |
||||
|
|
||||
|
for (int i = 0; i < static_cast<int>(FRAME_OVERLAP); i++) { |
||||
|
VK_CHECK(vkCreateFence(_device, &fenceCreateInfo, nullptr, &_frames[i]._renderFence)); |
||||
|
|
||||
|
VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_frames[i]._swapchainSemaphore)); |
||||
|
VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_frames[i]._renderSemaphore)); |
||||
|
} |
||||
|
} |
@ -0,0 +1,110 @@ |
|||||
|
#ifndef VKENGINE_H |
||||
|
#define VKENGINE_H |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <VkTypes.h> |
||||
|
|
||||
|
#include <QObject> |
||||
|
|
||||
|
struct DeletionQueue |
||||
|
{ |
||||
|
std::deque<std::function<void()>> deletors; |
||||
|
|
||||
|
void push_function(std::function<void()>&& function) { |
||||
|
deletors.push_back(function); |
||||
|
} |
||||
|
|
||||
|
void flush() { |
||||
|
// reverse iterate the deletion queue to execute all the functions
|
||||
|
for (auto it = deletors.rbegin(); it != deletors.rend(); it++) { |
||||
|
(*it)(); //call functors
|
||||
|
} |
||||
|
|
||||
|
deletors.clear(); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
struct FrameData { |
||||
|
|
||||
|
VkCommandPool _commandPool; |
||||
|
VkCommandBuffer _mainCommandBuffer; |
||||
|
|
||||
|
VkSemaphore _swapchainSemaphore, _renderSemaphore; |
||||
|
VkFence _renderFence; |
||||
|
|
||||
|
DeletionQueue _deletionQueue; |
||||
|
}; |
||||
|
|
||||
|
constexpr unsigned int FRAME_OVERLAP = 2; |
||||
|
|
||||
|
class VkEngine |
||||
|
{ |
||||
|
public: |
||||
|
VkEngine(); |
||||
|
|
||||
|
bool _isInitialized{ false }; |
||||
|
int _frameNumber {0}; |
||||
|
bool stop_rendering{ false }; |
||||
|
VkExtent2D _windowExtent{ 1700 , 900 }; |
||||
|
|
||||
|
struct SDL_Window* _window{ nullptr }; |
||||
|
|
||||
|
VkInstance _instance;// Vulkan library handle
|
||||
|
VkDebugUtilsMessengerEXT _debug_messenger;// Vulkan debug output handle
|
||||
|
VkPhysicalDevice _chosenGPU;// GPU chosen as the default device
|
||||
|
VkDevice _device; // Vulkan device for commands
|
||||
|
VkSurfaceKHR _surface;// Vulkan window surface
|
||||
|
|
||||
|
VkSwapchainKHR _swapchain; |
||||
|
VkFormat _swapchainImageFormat; |
||||
|
|
||||
|
std::vector<VkImage> _swapchainImages; |
||||
|
std::vector<VkImageView> _swapchainImageViews; |
||||
|
VkExtent2D _swapchainExtent; |
||||
|
|
||||
|
FrameData _frames[FRAME_OVERLAP]; |
||||
|
|
||||
|
FrameData& get_current_frame() |
||||
|
{ |
||||
|
return _frames[_frameNumber % FRAME_OVERLAP]; |
||||
|
} |
||||
|
|
||||
|
DeletionQueue _mainDeletionQueue; |
||||
|
|
||||
|
VkQueue _graphicsQueue; |
||||
|
uint32_t _graphicsQueueFamily; |
||||
|
|
||||
|
VmaAllocator _allocator; |
||||
|
|
||||
|
//draw resources
|
||||
|
AllocatedImage _drawImage; |
||||
|
VkExtent2D _drawExtent; |
||||
|
|
||||
|
static VkEngine& Get(); |
||||
|
|
||||
|
//initializes everything in the engine
|
||||
|
void init(); |
||||
|
|
||||
|
//shuts down the engine
|
||||
|
void cleanup(); |
||||
|
|
||||
|
//draw loop
|
||||
|
void draw(); |
||||
|
|
||||
|
//run main loop
|
||||
|
void run(); |
||||
|
|
||||
|
private: |
||||
|
|
||||
|
void init_vulkan(); |
||||
|
void init_swapchain(); |
||||
|
void init_commands(); |
||||
|
void init_sync_structures(); |
||||
|
|
||||
|
void create_swapchain(uint32_t width, uint32_t height); |
||||
|
void destroy_swapchain(); |
||||
|
}; |
||||
|
|
||||
|
#endif // VKENGINE_H
|
@ -0,0 +1,34 @@ |
|||||
|
#include "VkImages.h" |
||||
|
#include "VkInitializers.h" |
||||
|
|
||||
|
void vkutil::transition_image(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout newLayout) |
||||
|
{ |
||||
|
VkImageMemoryBarrier2 imageBarrier {.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2}; |
||||
|
imageBarrier.pNext = nullptr; |
||||
|
|
||||
|
imageBarrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; |
||||
|
imageBarrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT; |
||||
|
imageBarrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; |
||||
|
imageBarrier.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT; |
||||
|
|
||||
|
imageBarrier.oldLayout = currentLayout; |
||||
|
imageBarrier.newLayout = newLayout; |
||||
|
|
||||
|
VkImageAspectFlags aspectMask = (newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; |
||||
|
imageBarrier.subresourceRange = vkinit::image_subresource_range(aspectMask); |
||||
|
imageBarrier.image = image; |
||||
|
|
||||
|
VkDependencyInfo depInfo {}; |
||||
|
depInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; |
||||
|
depInfo.pNext = nullptr; |
||||
|
|
||||
|
depInfo.imageMemoryBarrierCount = 1; |
||||
|
depInfo.pImageMemoryBarriers = &imageBarrier; |
||||
|
|
||||
|
vkCmdPipelineBarrier2(cmd, &depInfo); |
||||
|
} |
||||
|
|
||||
|
//VkImages::VkImages()
|
||||
|
//{
|
||||
|
|
||||
|
//}
|
@ -0,0 +1,22 @@ |
|||||
|
#ifndef VKIMAGES_H |
||||
|
#define VKIMAGES_H |
||||
|
|
||||
|
#include <QObject> |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <vulkan/vulkan.h> |
||||
|
|
||||
|
namespace vkutil { |
||||
|
|
||||
|
void transition_image(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout newLayout); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
//class VkImages
|
||||
|
//{
|
||||
|
//public:
|
||||
|
// VkImages();
|
||||
|
//};
|
||||
|
|
||||
|
#endif // VKIMAGES_H
|
@ -0,0 +1,342 @@ |
|||||
|
#include "VkInitializers.h" |
||||
|
|
||||
|
//> init_cmd
|
||||
|
VkCommandPoolCreateInfo vkinit::command_pool_create_info(uint32_t queueFamilyIndex, |
||||
|
VkCommandPoolCreateFlags flags /*= 0*/) |
||||
|
{ |
||||
|
VkCommandPoolCreateInfo info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
info.queueFamilyIndex = queueFamilyIndex; |
||||
|
info.flags = flags; |
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
VkCommandBufferAllocateInfo vkinit::command_buffer_allocate_info( |
||||
|
VkCommandPool pool, uint32_t count /*= 1*/) |
||||
|
{ |
||||
|
VkCommandBufferAllocateInfo info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
info.commandPool = pool; |
||||
|
info.commandBufferCount = count; |
||||
|
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
||||
|
return info; |
||||
|
} |
||||
|
//< init_cmd
|
||||
|
//
|
||||
|
//> init_cmd_draw
|
||||
|
VkCommandBufferBeginInfo vkinit::command_buffer_begin_info(VkCommandBufferUsageFlags flags /*= 0*/) |
||||
|
{ |
||||
|
VkCommandBufferBeginInfo info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
info.pInheritanceInfo = nullptr; |
||||
|
info.flags = flags; |
||||
|
return info; |
||||
|
} |
||||
|
//< init_cmd_draw
|
||||
|
|
||||
|
//> init_sync
|
||||
|
VkFenceCreateInfo vkinit::fence_create_info(VkFenceCreateFlags flags /*= 0*/) |
||||
|
{ |
||||
|
VkFenceCreateInfo info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
info.flags = flags; |
||||
|
|
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
VkSemaphoreCreateInfo vkinit::semaphore_create_info(VkSemaphoreCreateFlags flags /*= 0*/) |
||||
|
{ |
||||
|
VkSemaphoreCreateInfo info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
info.flags = flags; |
||||
|
return info; |
||||
|
} |
||||
|
//< init_sync
|
||||
|
|
||||
|
//> init_submit
|
||||
|
VkSemaphoreSubmitInfo vkinit::semaphore_submit_info(VkPipelineStageFlags2 stageMask, VkSemaphore semaphore) |
||||
|
{ |
||||
|
VkSemaphoreSubmitInfo submitInfo{}; |
||||
|
submitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO; |
||||
|
submitInfo.pNext = nullptr; |
||||
|
submitInfo.semaphore = semaphore; |
||||
|
submitInfo.stageMask = stageMask; |
||||
|
submitInfo.deviceIndex = 0; |
||||
|
submitInfo.value = 1; |
||||
|
|
||||
|
return submitInfo; |
||||
|
} |
||||
|
|
||||
|
VkCommandBufferSubmitInfo vkinit::command_buffer_submit_info(VkCommandBuffer cmd) |
||||
|
{ |
||||
|
VkCommandBufferSubmitInfo info{}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
info.commandBuffer = cmd; |
||||
|
info.deviceMask = 0; |
||||
|
|
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
VkSubmitInfo2 vkinit::submit_info(VkCommandBufferSubmitInfo* cmd, VkSemaphoreSubmitInfo* signalSemaphoreInfo, |
||||
|
VkSemaphoreSubmitInfo* waitSemaphoreInfo) |
||||
|
{ |
||||
|
VkSubmitInfo2 info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
info.waitSemaphoreInfoCount = waitSemaphoreInfo == nullptr ? 0 : 1; |
||||
|
info.pWaitSemaphoreInfos = waitSemaphoreInfo; |
||||
|
|
||||
|
info.signalSemaphoreInfoCount = signalSemaphoreInfo == nullptr ? 0 : 1; |
||||
|
info.pSignalSemaphoreInfos = signalSemaphoreInfo; |
||||
|
|
||||
|
info.commandBufferInfoCount = 1; |
||||
|
info.pCommandBufferInfos = cmd; |
||||
|
|
||||
|
return info; |
||||
|
} |
||||
|
//< init_submit
|
||||
|
|
||||
|
VkPresentInfoKHR vkinit::present_info() |
||||
|
{ |
||||
|
VkPresentInfoKHR info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; |
||||
|
info.pNext = 0; |
||||
|
|
||||
|
info.swapchainCount = 0; |
||||
|
info.pSwapchains = nullptr; |
||||
|
info.pWaitSemaphores = nullptr; |
||||
|
info.waitSemaphoreCount = 0; |
||||
|
info.pImageIndices = nullptr; |
||||
|
|
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
//> color_info
|
||||
|
VkRenderingAttachmentInfo vkinit::attachment_info( |
||||
|
VkImageView view, VkClearValue* clear ,VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/) |
||||
|
{ |
||||
|
VkRenderingAttachmentInfo colorAttachment {}; |
||||
|
colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; |
||||
|
colorAttachment.pNext = nullptr; |
||||
|
|
||||
|
colorAttachment.imageView = view; |
||||
|
colorAttachment.imageLayout = layout; |
||||
|
colorAttachment.loadOp = clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; |
||||
|
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; |
||||
|
if (clear) { |
||||
|
colorAttachment.clearValue = *clear; |
||||
|
} |
||||
|
|
||||
|
return colorAttachment; |
||||
|
} |
||||
|
//< color_info
|
||||
|
//> depth_info
|
||||
|
VkRenderingAttachmentInfo vkinit::depth_attachment_info( |
||||
|
VkImageView view, VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/) |
||||
|
{ |
||||
|
VkRenderingAttachmentInfo depthAttachment {}; |
||||
|
depthAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; |
||||
|
depthAttachment.pNext = nullptr; |
||||
|
|
||||
|
depthAttachment.imageView = view; |
||||
|
depthAttachment.imageLayout = layout; |
||||
|
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; |
||||
|
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; |
||||
|
depthAttachment.clearValue.depthStencil.depth = 0.f; |
||||
|
|
||||
|
return depthAttachment; |
||||
|
} |
||||
|
//< depth_info
|
||||
|
//> render_info
|
||||
|
VkRenderingInfo vkinit::rendering_info(VkExtent2D renderExtent, VkRenderingAttachmentInfo* colorAttachment, |
||||
|
VkRenderingAttachmentInfo* depthAttachment) |
||||
|
{ |
||||
|
VkRenderingInfo renderInfo {}; |
||||
|
renderInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; |
||||
|
renderInfo.pNext = nullptr; |
||||
|
|
||||
|
renderInfo.renderArea = VkRect2D { VkOffset2D { 0, 0 }, renderExtent }; |
||||
|
renderInfo.layerCount = 1; |
||||
|
renderInfo.colorAttachmentCount = 1; |
||||
|
renderInfo.pColorAttachments = colorAttachment; |
||||
|
renderInfo.pDepthAttachment = depthAttachment; |
||||
|
renderInfo.pStencilAttachment = nullptr; |
||||
|
|
||||
|
return renderInfo; |
||||
|
} |
||||
|
//< render_info
|
||||
|
//> subresource
|
||||
|
VkImageSubresourceRange vkinit::image_subresource_range(VkImageAspectFlags aspectMask) |
||||
|
{ |
||||
|
VkImageSubresourceRange subImage {}; |
||||
|
subImage.aspectMask = aspectMask; |
||||
|
subImage.baseMipLevel = 0; |
||||
|
subImage.levelCount = VK_REMAINING_MIP_LEVELS; |
||||
|
subImage.baseArrayLayer = 0; |
||||
|
subImage.layerCount = VK_REMAINING_ARRAY_LAYERS; |
||||
|
|
||||
|
return subImage; |
||||
|
} |
||||
|
//< subresource
|
||||
|
|
||||
|
|
||||
|
|
||||
|
VkDescriptorSetLayoutBinding vkinit::descriptorset_layout_binding(VkDescriptorType type, VkShaderStageFlags stageFlags, |
||||
|
uint32_t binding) |
||||
|
{ |
||||
|
VkDescriptorSetLayoutBinding setbind = {}; |
||||
|
setbind.binding = binding; |
||||
|
setbind.descriptorCount = 1; |
||||
|
setbind.descriptorType = type; |
||||
|
setbind.pImmutableSamplers = nullptr; |
||||
|
setbind.stageFlags = stageFlags; |
||||
|
|
||||
|
return setbind; |
||||
|
} |
||||
|
|
||||
|
VkDescriptorSetLayoutCreateInfo vkinit::descriptorset_layout_create_info(VkDescriptorSetLayoutBinding* bindings, |
||||
|
uint32_t bindingCount) |
||||
|
{ |
||||
|
VkDescriptorSetLayoutCreateInfo info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
info.pBindings = bindings; |
||||
|
info.bindingCount = bindingCount; |
||||
|
info.flags = 0; |
||||
|
|
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
VkWriteDescriptorSet vkinit::write_descriptor_image(VkDescriptorType type, VkDescriptorSet dstSet, |
||||
|
VkDescriptorImageInfo* imageInfo, uint32_t binding) |
||||
|
{ |
||||
|
VkWriteDescriptorSet write = {}; |
||||
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; |
||||
|
write.pNext = nullptr; |
||||
|
|
||||
|
write.dstBinding = binding; |
||||
|
write.dstSet = dstSet; |
||||
|
write.descriptorCount = 1; |
||||
|
write.descriptorType = type; |
||||
|
write.pImageInfo = imageInfo; |
||||
|
|
||||
|
return write; |
||||
|
} |
||||
|
|
||||
|
VkWriteDescriptorSet vkinit::write_descriptor_buffer(VkDescriptorType type, VkDescriptorSet dstSet, |
||||
|
VkDescriptorBufferInfo* bufferInfo, uint32_t binding) |
||||
|
{ |
||||
|
VkWriteDescriptorSet write = {}; |
||||
|
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; |
||||
|
write.pNext = nullptr; |
||||
|
|
||||
|
write.dstBinding = binding; |
||||
|
write.dstSet = dstSet; |
||||
|
write.descriptorCount = 1; |
||||
|
write.descriptorType = type; |
||||
|
write.pBufferInfo = bufferInfo; |
||||
|
|
||||
|
return write; |
||||
|
} |
||||
|
|
||||
|
VkDescriptorBufferInfo vkinit::buffer_info(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range) |
||||
|
{ |
||||
|
VkDescriptorBufferInfo binfo {}; |
||||
|
binfo.buffer = buffer; |
||||
|
binfo.offset = offset; |
||||
|
binfo.range = range; |
||||
|
return binfo; |
||||
|
} |
||||
|
|
||||
|
//> image_set
|
||||
|
VkImageCreateInfo vkinit::image_create_info(VkFormat format, VkImageUsageFlags usageFlags, VkExtent3D extent) |
||||
|
{ |
||||
|
VkImageCreateInfo info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
info.imageType = VK_IMAGE_TYPE_2D; |
||||
|
|
||||
|
info.format = format; |
||||
|
info.extent = extent; |
||||
|
|
||||
|
info.mipLevels = 1; |
||||
|
info.arrayLayers = 1; |
||||
|
|
||||
|
//for MSAA. we will not be using it by default, so default it to 1 sample per pixel.
|
||||
|
info.samples = VK_SAMPLE_COUNT_1_BIT; |
||||
|
|
||||
|
//optimal tiling, which means the image is stored on the best gpu format
|
||||
|
info.tiling = VK_IMAGE_TILING_OPTIMAL; |
||||
|
info.usage = usageFlags; |
||||
|
|
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
VkImageViewCreateInfo vkinit::imageview_create_info(VkFormat format, VkImage image, VkImageAspectFlags aspectFlags) |
||||
|
{ |
||||
|
// build a image-view for the depth image to use for rendering
|
||||
|
VkImageViewCreateInfo info = {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
info.viewType = VK_IMAGE_VIEW_TYPE_2D; |
||||
|
info.image = image; |
||||
|
info.format = format; |
||||
|
info.subresourceRange.baseMipLevel = 0; |
||||
|
info.subresourceRange.levelCount = 1; |
||||
|
info.subresourceRange.baseArrayLayer = 0; |
||||
|
info.subresourceRange.layerCount = 1; |
||||
|
info.subresourceRange.aspectMask = aspectFlags; |
||||
|
|
||||
|
return info; |
||||
|
} |
||||
|
//< image_set
|
||||
|
VkPipelineLayoutCreateInfo vkinit::pipeline_layout_create_info() |
||||
|
{ |
||||
|
VkPipelineLayoutCreateInfo info {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
// empty defaults
|
||||
|
info.flags = 0; |
||||
|
info.setLayoutCount = 0; |
||||
|
info.pSetLayouts = nullptr; |
||||
|
info.pushConstantRangeCount = 0; |
||||
|
info.pPushConstantRanges = nullptr; |
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
VkPipelineShaderStageCreateInfo vkinit::pipeline_shader_stage_create_info(VkShaderStageFlagBits stage, |
||||
|
VkShaderModule shaderModule, |
||||
|
const char * entry) |
||||
|
{ |
||||
|
VkPipelineShaderStageCreateInfo info {}; |
||||
|
info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; |
||||
|
info.pNext = nullptr; |
||||
|
|
||||
|
// shader stage
|
||||
|
info.stage = stage; |
||||
|
// module containing the code for this shader stage
|
||||
|
info.module = shaderModule; |
||||
|
// the entry point of the shader
|
||||
|
info.pName = entry; |
||||
|
return info; |
||||
|
} |
||||
|
|
||||
|
//VkInitializers::VkInitializers()
|
||||
|
//{
|
||||
|
|
||||
|
//}
|
@ -0,0 +1,62 @@ |
|||||
|
#ifndef VKINITIALIZERS_H |
||||
|
#define VKINITIALIZERS_H |
||||
|
|
||||
|
#include <QObject> |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <VkTypes.h> |
||||
|
|
||||
|
namespace vkinit { |
||||
|
//> init_cmd
|
||||
|
VkCommandPoolCreateInfo command_pool_create_info(uint32_t queueFamilyIndex, VkCommandPoolCreateFlags flags = 0); |
||||
|
VkCommandBufferAllocateInfo command_buffer_allocate_info(VkCommandPool pool, uint32_t count = 1); |
||||
|
//< init_cmd
|
||||
|
|
||||
|
VkCommandBufferBeginInfo command_buffer_begin_info(VkCommandBufferUsageFlags flags = 0); |
||||
|
VkCommandBufferSubmitInfo command_buffer_submit_info(VkCommandBuffer cmd); |
||||
|
|
||||
|
VkFenceCreateInfo fence_create_info(VkFenceCreateFlags flags = 0); |
||||
|
|
||||
|
VkSemaphoreCreateInfo semaphore_create_info(VkSemaphoreCreateFlags flags = 0); |
||||
|
|
||||
|
VkSubmitInfo2 submit_info(VkCommandBufferSubmitInfo* cmd, VkSemaphoreSubmitInfo* signalSemaphoreInfo, |
||||
|
VkSemaphoreSubmitInfo* waitSemaphoreInfo); |
||||
|
VkPresentInfoKHR present_info(); |
||||
|
|
||||
|
VkRenderingAttachmentInfo attachment_info(VkImageView view, VkClearValue* clear, VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/); |
||||
|
|
||||
|
VkRenderingAttachmentInfo depth_attachment_info(VkImageView view, |
||||
|
VkImageLayout layout /*= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL*/); |
||||
|
|
||||
|
VkRenderingInfo rendering_info(VkExtent2D renderExtent, VkRenderingAttachmentInfo* colorAttachment, |
||||
|
VkRenderingAttachmentInfo* depthAttachment); |
||||
|
|
||||
|
VkImageSubresourceRange image_subresource_range(VkImageAspectFlags aspectMask); |
||||
|
|
||||
|
VkSemaphoreSubmitInfo semaphore_submit_info(VkPipelineStageFlags2 stageMask, VkSemaphore semaphore); |
||||
|
VkDescriptorSetLayoutBinding descriptorset_layout_binding(VkDescriptorType type, VkShaderStageFlags stageFlags, |
||||
|
uint32_t binding); |
||||
|
VkDescriptorSetLayoutCreateInfo descriptorset_layout_create_info(VkDescriptorSetLayoutBinding* bindings, |
||||
|
uint32_t bindingCount); |
||||
|
VkWriteDescriptorSet write_descriptor_image(VkDescriptorType type, VkDescriptorSet dstSet, |
||||
|
VkDescriptorImageInfo* imageInfo, uint32_t binding); |
||||
|
VkWriteDescriptorSet write_descriptor_buffer(VkDescriptorType type, VkDescriptorSet dstSet, |
||||
|
VkDescriptorBufferInfo* bufferInfo, uint32_t binding); |
||||
|
VkDescriptorBufferInfo buffer_info(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range); |
||||
|
|
||||
|
VkImageCreateInfo image_create_info(VkFormat format, VkImageUsageFlags usageFlags, VkExtent3D extent); |
||||
|
VkImageViewCreateInfo imageview_create_info(VkFormat format, VkImage image, VkImageAspectFlags aspectFlags); |
||||
|
VkPipelineLayoutCreateInfo pipeline_layout_create_info(); |
||||
|
VkPipelineShaderStageCreateInfo pipeline_shader_stage_create_info(VkShaderStageFlagBits stage, |
||||
|
VkShaderModule shaderModule, |
||||
|
const char * entry = "main"); |
||||
|
} // namespace vkinit
|
||||
|
|
||||
|
//class VkInitializers
|
||||
|
//{
|
||||
|
//public:
|
||||
|
// VkInitializers();
|
||||
|
//};
|
||||
|
|
||||
|
#endif // VKINITIALIZERS_H
|
@ -0,0 +1,6 @@ |
|||||
|
#include "VkLoader.h" |
||||
|
|
||||
|
VkLoader::VkLoader() |
||||
|
{ |
||||
|
|
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
#ifndef VKLOADER_H |
||||
|
#define VKLOADER_H |
||||
|
|
||||
|
#include <QObject> |
||||
|
|
||||
|
class VkLoader |
||||
|
{ |
||||
|
public: |
||||
|
VkLoader(); |
||||
|
}; |
||||
|
|
||||
|
#endif // VKLOADER_H
|
@ -0,0 +1,17 @@ |
|||||
|
#include "VkMain.h" |
||||
|
|
||||
|
VkMain::VkMain() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void VkMain::mainRun() |
||||
|
{ |
||||
|
VkEngine engine; |
||||
|
|
||||
|
engine.init(); |
||||
|
|
||||
|
engine.run(); |
||||
|
|
||||
|
engine.cleanup(); |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
#ifndef VKMAIN_H |
||||
|
#define VKMAIN_H |
||||
|
|
||||
|
#include <VkEngine.h> |
||||
|
|
||||
|
#include <QObject> |
||||
|
|
||||
|
class VkMain |
||||
|
{ |
||||
|
public: |
||||
|
VkMain(); |
||||
|
void mainRun(); |
||||
|
}; |
||||
|
|
||||
|
#endif // VKMAIN_H
|
@ -0,0 +1,6 @@ |
|||||
|
#include "VkPipelines.h" |
||||
|
|
||||
|
VkPipelines::VkPipelines() |
||||
|
{ |
||||
|
|
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
#ifndef VKPIPELINES_H |
||||
|
#define VKPIPELINES_H |
||||
|
|
||||
|
#include <QObject> |
||||
|
|
||||
|
class VkPipelines |
||||
|
{ |
||||
|
public: |
||||
|
VkPipelines(); |
||||
|
}; |
||||
|
|
||||
|
#endif // VKPIPELINES_H
|
@ -0,0 +1,41 @@ |
|||||
|
#ifndef VKTYPES_H |
||||
|
#define VKTYPES_H |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <memory> |
||||
|
#include <optional> |
||||
|
#include <string> |
||||
|
#include <vector> |
||||
|
#include <span> |
||||
|
#include <array> |
||||
|
#include <functional> |
||||
|
#include <deque> |
||||
|
|
||||
|
#include <vulkan.h> |
||||
|
#include <vk_enum_string_helper.h> |
||||
|
#include <vma/vk_mem_alloc.h> |
||||
|
|
||||
|
#include <fmt/core.h> |
||||
|
|
||||
|
#include <glm/mat4x4.hpp> |
||||
|
#include <glm/vec4.hpp> |
||||
|
|
||||
|
struct AllocatedImage { |
||||
|
VkImage image; |
||||
|
VkImageView imageView; |
||||
|
VmaAllocation allocation; |
||||
|
VkExtent3D imageExtent; |
||||
|
VkFormat imageFormat; |
||||
|
}; |
||||
|
|
||||
|
#define VK_CHECK(x) \ |
||||
|
do { \ |
||||
|
VkResult err = x; \ |
||||
|
if (err) { \ |
||||
|
fmt::print("Detected Vulkan error: {}", string_VkResult(err)); \ |
||||
|
abort(); \ |
||||
|
} \ |
||||
|
} while (0) |
||||
|
|
||||
|
#endif // VKTYPES_H
|
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"description": "This file is generated by qmake to be read by androiddeployqt and should not be modified by hand.", |
||||
|
"qt": "/opt/Qt5.13.2/5.13.2/android_arm64_v8a", |
||||
|
"sdk": "/home/ali-mehrabani/host-projects/Android/Sdk", |
||||
|
"sdkBuildToolsRevision": "30.0.0", |
||||
|
"ndk": "/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b", |
||||
|
"toolchain-prefix": "llvm", |
||||
|
"tool-prefix": "llvm", |
||||
|
"toolchain-version": "4.9", |
||||
|
"ndk-host": "linux-x86_64", |
||||
|
"target-architecture": "arm64-v8a", |
||||
|
"android-package-source-directory": "/home/ali-mehrabani/Qt_projects/VkTest/android", |
||||
|
"qml-root-path": "/home/ali-mehrabani/Qt_projects/VkTest", |
||||
|
"stdcpp-path": "/home/ali-mehrabani/host-projects/Android/Sdk/ndk/android-ndk-r20b/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so", |
||||
|
"useLLVM": true, |
||||
|
"application-binary": "/home/ali-mehrabani/Qt_projects/VkTest/libVkTest.so" |
||||
|
} |
Loading…
Reference in new issue