This commit is contained in:
Zed A. Shaw 2025-11-25 13:45:08 -05:00
parent 55e38788b4
commit 40717cf8e4
9 changed files with 216 additions and 14 deletions

View file

@ -1,14 +1,15 @@
#include <vk_engine.h>
#include <memory>
int main()
{
VulkanEngine engine;
auto engine = std::make_unique<VulkanEngine>();
engine.init();
engine->init();
engine.run();
engine->run();
engine.cleanup();
engine->cleanup();
return 0;
}

View file

@ -10,7 +10,14 @@ project('hellovulk', 'cpp',
cmake = import('cmake')
# use this for common options only for our executables
cpp_args=['-Wno-sign-conversion']
cpp_args=[
'-Wno-sign-conversion',
'-Wno-unused-parameter',
'-Wno-unused-function',
'-Wno-unused-variable',
'-Wno-conversion',
'-Wno-missing-field-initializers'
]
link_args=[]
# these are passed as override_defaults
exe_defaults = [ 'warning_level=2' ]

View file

@ -12,6 +12,9 @@
#include <chrono>
#include <thread>
#define VMA_IMPLEMENTATION
#include "vk_mem_alloc.h"
constexpr bool bUseValidationLayers = false;
VulkanEngine* loadedEngine = nullptr;
@ -59,8 +62,12 @@ void VulkanEngine::cleanup()
vkDestroyFence(_device, _frames[i]._renderFence, nullptr);
vkDestroySemaphore(_device, _frames[i]._renderSemaphore, nullptr);
vkDestroySemaphore(_device ,_frames[i]._swapchainSemaphore, nullptr);
_frames[i]._deletionQueue.flush();
}
_mainDeletionQueue.flush();
destroy_swapchain();
vkDestroySurfaceKHR(_instance, _surface, nullptr);
@ -77,6 +84,8 @@ void VulkanEngine::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 = 0;
@ -87,19 +96,28 @@ void VulkanEngine::draw()
VkCommandBufferBeginInfo cmdBeginInfo = vkinit::command_buffer_begin_info(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
_drawExtent.width = _drawImage.imageExtent.width;
_drawExtent.height = _drawImage.imageExtent.height;
VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
// transition our main draw image into general layout so we can write into it
// we will overwrite it all so we dont care about what was the older layout
VkClearColorValue clearValue;
float flash = std::abs(std::sin(float(_frameNumber) / 120.0f));
clearValue = { { 0.0f, 0.0f, flash, 1.0f} };
vkutil::transition_image(cmd, _drawImage.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL);
VkImageSubresourceRange clearRange = vkinit::image_subresource_range(VK_IMAGE_ASPECT_COLOR_BIT);
draw_background(cmd);
vkCmdClearColorImage(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1, &clearRange);
vkutil::transition_image(cmd, _drawImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vkutil::copy_image_to_image(cmd, _drawImage.image,
_swapchainImages[swapchainImageIndex],
_drawExtent, _swapchainExtent);
vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
vkutil::transition_image(cmd, _swapchainImages[swapchainImageIndex], VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
VK_CHECK(vkEndCommandBuffer(cmd));
//prepare the submission to the queue.
@ -226,6 +244,18 @@ void VulkanEngine::init_vulkan() {
_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 VulkanEngine::create_swapchain(uint32_t width, uint32_t height) {
@ -261,6 +291,41 @@ void VulkanEngine::destroy_swapchain() {
void VulkanEngine::init_swapchain() {
create_swapchain(_windowExtent.width, _windowExtent.height);
VkExtent3D drawImageExtent = {
_windowExtent.width,
_windowExtent.height,
1
};
_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);
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([=, this]() {
vkDestroyImageView(_device, _drawImage.imageView, nullptr);
vmaDestroyImage(_allocator, _drawImage.image, _drawImage.allocation);
});
}
void VulkanEngine::init_commands() {
@ -291,3 +356,13 @@ void VulkanEngine::init_sync_structures() {
}
}
void VulkanEngine::draw_background(VkCommandBuffer cmd)
{
VkClearColorValue clearValue;
float flash = std::abs(std::sin(float(_frameNumber) / 120.0f));
clearValue = { { 0.0f, 0.0f, flash, 1.0f} };
VkImageSubresourceRange clearRange = vkinit::image_subresource_range(VK_IMAGE_ASPECT_COLOR_BIT);
vkCmdClearColorImage(cmd, _drawImage.image, VK_IMAGE_LAYOUT_GENERAL, &clearValue, 1, &clearRange);
}

View file

@ -5,12 +5,30 @@
#include <vk_types.h>
struct DeletionQueue {
std::deque<std::function<void()>> deletors;
void push_function(std::function<void()>&& function) {
deletors.push_back(function);
}
void flush() {
// reverse itererate the deletion queue
for(auto it = deletors.rbegin(); it != deletors.rend(); it++) {
(*it)();
}
deletors.clear();
}
};
struct FrameData {
VkCommandPool _commandPool;
VkCommandBuffer _mainCommandBuffer;
VkSemaphore _swapchainSemaphore;
VkSemaphore _renderSemaphore;
VkFence _renderFence;
DeletionQueue _deletionQueue;
};
constexpr unsigned int FRAME_OVERLAP=2;
@ -32,6 +50,9 @@ public:
std::vector<VkImageView> _swapchainImageViews;
VkExtent2D _swapchainExtent;
// VMA stuff
VmaAllocator _allocator;
// frames/command buffer
unsigned int _frameNumber = 0;
FrameData _frames[FRAME_OVERLAP];
@ -43,12 +64,15 @@ public:
VkQueue _graphicsQueue;
uint32_t _graphicsQueueFamily;
// draw resources
AllocatedImage _drawImage;
VkExtent2D _drawExtent;
// internal data
bool _isInitialized{ false };
VkExtent2D _windowExtent{ 1700 , 900 };
struct SDL_Window* _window{ nullptr };
DeletionQueue _mainDeletionQueue;
static VulkanEngine& Get();
@ -72,4 +96,5 @@ private:
void create_swapchain(uint32_t width, uint32_t height);
void destroy_swapchain();
void draw_background(VkCommandBuffer cmd);
};

View file

@ -28,3 +28,44 @@ void vkutil::transition_image(VkCommandBuffer cmd, VkImage image, VkImageLayout
vkCmdPipelineBarrier2(cmd, &depInfo);
}
void vkutil::copy_image_to_image(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, VkExtent2D dstSize)
{
VkImageBlit2 blitRegion{
.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
.pNext = nullptr
};
blitRegion.srcOffsets[1].x = srcSize.width;
blitRegion.srcOffsets[1].y = srcSize.height;
blitRegion.srcOffsets[1].z = 1;
blitRegion.dstOffsets[1].x = dstSize.width;
blitRegion.dstOffsets[1].y = dstSize.height;
blitRegion.dstOffsets[1].z = 1;
blitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blitRegion.srcSubresource.baseArrayLayer = 0;
blitRegion.srcSubresource.layerCount = 1;
blitRegion.srcSubresource.mipLevel = 0;
blitRegion.dstSubresource.aspectMask=VK_IMAGE_ASPECT_COLOR_BIT;
blitRegion.dstSubresource.baseArrayLayer=0;
blitRegion.dstSubresource.layerCount=1;
blitRegion.dstSubresource.mipLevel=0;
VkBlitImageInfo2 blitInfo{
.sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, .pNext = nullptr
};
blitInfo.dstImage = destination;
blitInfo.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
blitInfo.srcImage = source;
blitInfo.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
blitInfo.filter = VK_FILTER_LINEAR;
blitInfo.regionCount = 1;
blitInfo.pRegions = &blitRegion;
vkCmdBlitImage2(cmd, &blitInfo);
}

View file

@ -4,4 +4,6 @@
namespace vkutil {
void transition_image(VkCommandBuffer cmd, VkImage image, VkImageLayout currentLayout, VkImageLayout newLayout);
void copy_image_to_image(VkCommandBuffer cmd, VkImage source, VkImage destination, VkExtent2D srcSize, VkExtent2D dstSize);
}

View file

@ -108,3 +108,40 @@ VkSubmitInfo2 vkinit::submit_info(VkCommandBufferSubmitInfo* cmd, VkSemaphoreSub
return info;
}
VkImageCreateInfo vkinit::image_create_info(VkFormat format, VkImageUsageFlags usageFlags, VkExtent3D extent)
{
VkImageCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
info.format = format;
info.extent = extent;
info.mipLevels = 1;
info.arrayLayers = 1;
info.samples = VK_SAMPLE_COUNT_1_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.usage = usageFlags;
return info;
}
VkImageViewCreateInfo vkinit::imageview_create_info(VkFormat format, VkImage image, VkImageAspectFlags aspectFlags)
{
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;
}

View file

@ -26,5 +26,9 @@ namespace vkinit {
VkCommandBufferSubmitInfo command_buffer_submit_info(VkCommandBuffer cmd);
VkSubmitInfo2 submit_info(VkCommandBufferSubmitInfo* cmd, VkSemaphoreSubmitInfo* signalSemaphoreInfo, VkSemaphoreSubmitInfo* waitSemaphoreInfo);
VkImageViewCreateInfo imageview_create_info(VkFormat format, VkImage image, VkImageAspectFlags aspectFlags);
VkImageCreateInfo image_create_info(VkFormat format, VkImageUsageFlags usageFlags, VkExtent3D extent);
}

View file

@ -29,3 +29,13 @@
std::println("Detected Vulkan error: {}", int(err));\
}\
} while (0)
struct AllocatedImage {
VkImage image;
VkImageView imageView;
VmaAllocation allocation;
VkExtent3D imageExtent;
VkFormat imageFormat;
};