This commit is contained in:
Mars 2024-10-15 20:38:05 -04:00
parent 154a81721d
commit b2779c119a
Signed by: pupbrained
GPG key ID: 874E22DF2F9DFCB5

View file

@ -91,97 +91,110 @@ class VulkanApp {
}
private:
// GLFW instance
vkfw::UniqueInstance mVKFWInstance;
// GLFW window
vkfw::UniqueWindow mWindow;
// Instances
vkfw::UniqueInstance mVKFWInstance; // Unique handle to the GLFW instance
vkfw::UniqueWindow mWindow; // Unique handle to the GLFW window
vk::UniqueInstance mInstance; // Unique handle to the Vulkan instance
// Vulkan instance
vk::UniqueInstance mInstance;
// Debug messenger for Vulkan validation layers
vk::UniqueDebugUtilsMessengerEXT mDebugMessenger; // Unique handle to the debug messenger
// Debug messenger
vk::UniqueDebugUtilsMessengerEXT mDebugMessenger;
// Window surface
vk::UniqueSurfaceKHR mSurface;
// Surface for rendering
vk::UniqueSurfaceKHR mSurface; // Unique handle to the Vulkan surface
// Represents the physical device
vk::PhysicalDevice mPhysicalDevice;
// Number of MSAA samples
vk::SampleCountFlagBits mMsaaSamples;
// Represents the logical device
vk::UniqueDevice mDevice;
// Physical device and logical device
vk::PhysicalDevice mPhysicalDevice; // Handle to the selected physical device (GPU)
vk::SampleCountFlagBits mMsaaSamples; // Multisample anti-aliasing (MSAA) sample count
vk::UniqueDevice mDevice; // Unique handle to the logical device
vk::Queue mGraphicsQueue;
vk::Queue mPresentQueue;
// Vulkan queues for graphics and presentation
vk::Queue mGraphicsQueue; // Handle to the graphics queue
vk::Queue mPresentQueue; // Handle to the presentation queue
vk::UniqueSwapchainKHR mSwapChain;
std::vector<vk::Image> mSwapChainImages;
vk::Format mSwapChainImageFormat;
vk::Extent2D mSwapChainExtent;
std::vector<vk::UniqueImageView> mSwapChainImageViews;
std::vector<vk::UniqueFramebuffer> mSwapChainFramebuffers;
// Swapchain and related resources
vk::UniqueSwapchainKHR mSwapChain; // The swapchain handle
std::vector<vk::Image> mSwapChainImages; // Images in the swapchain
vk::Format mSwapChainImageFormat; // Format of the swapchain images
vk::Extent2D mSwapChainExtent; // Dimensions of the swapchain images
std::vector<vk::UniqueImageView> mSwapChainImageViews; // Image views for the swapchain images
std::vector<vk::UniqueFramebuffer> mSwapChainFramebuffers; // Framebuffers for the swapchain images
vk::UniqueRenderPass mRenderPass;
vk::UniqueDescriptorSetLayout mDescriptorSetLayout;
vk::UniquePipelineLayout mPipelineLayout;
vk::UniquePipeline mGraphicsPipeline;
// Render pass and pipeline configurations
vk::UniqueRenderPass mRenderPass; // Render pass configuration
vk::UniqueDescriptorSetLayout mDescriptorSetLayout; // Descriptor set layout
vk::UniquePipelineLayout mPipelineLayout; // Pipeline layout
vk::UniquePipeline mGraphicsPipeline; // Graphics pipeline
// Command pool for allocating command buffers
vk::UniqueCommandPool mCommandPool;
vk::UniqueImage mColorImage;
vk::UniqueDeviceMemory mColorImageMemory;
vk::UniqueImageView mColorImageView;
// Color image resources
vk::UniqueImage mColorImage; // Color image
vk::UniqueDeviceMemory mColorImageMemory; // Memory for the color image
vk::UniqueImageView mColorImageView; // Image view for the color image
vk::UniqueImage mDepthImage;
vk::UniqueDeviceMemory mDepthImageMemory;
vk::UniqueImageView mDepthImageView;
// Depth image resources
vk::UniqueImage mDepthImage; // Depth image
vk::UniqueDeviceMemory mDepthImageMemory; // Memory for the depth image
vk::UniqueImageView mDepthImageView; // Image view for the depth image
u32 mMipLevels;
vk::UniqueImage mTextureImage;
vk::UniqueDeviceMemory mTextureImageMemory;
vk::UniqueImageView mTextureImageView;
vk::UniqueSampler mTextureSampler;
// Texture resources
u32 mMipLevels; // Number of mipmap levels
vk::UniqueImage mTextureImage; // Texture image
vk::UniqueDeviceMemory mTextureImageMemory; // Memory for the texture image
vk::UniqueImageView mTextureImageView; // Image view for the texture image
vk::UniqueSampler mTextureSampler; // Sampler for the texture
std::vector<Vertex> mVertices;
std::vector<u32> mIndices;
vk::UniqueBuffer mVertexBuffer;
vk::UniqueDeviceMemory mVertexBufferMemory;
vk::UniqueBuffer mIndexBuffer;
vk::UniqueDeviceMemory mIndexBufferMemory;
// Vertex and index buffers
std::vector<Vertex> mVertices; // Vertex data
std::vector<u32> mIndices; // Index data
vk::UniqueBuffer mVertexBuffer; // Vertex buffer
vk::UniqueDeviceMemory mVertexBufferMemory; // Memory for the vertex buffer
vk::UniqueBuffer mIndexBuffer; // Index buffer
vk::UniqueDeviceMemory mIndexBufferMemory; // Memory for the index buffer
std::vector<vk::UniqueBuffer> mUniformBuffers;
std::vector<vk::UniqueDeviceMemory> mUniformBuffersMemory;
std::vector<void*> mUniformBuffersMapped;
// Uniform buffers
std::vector<vk::UniqueBuffer> mUniformBuffers; // Uniform buffers
std::vector<vk::UniqueDeviceMemory> mUniformBuffersMemory; // Memory for the uniform buffers
std::vector<void*> mUniformBuffersMapped; // Mapped pointers for the uniform buffers
vk::UniqueDescriptorPool mDescriptorPool;
std::vector<vk::DescriptorSet> mDescriptorSets;
// Descriptor pool and sets
vk::UniqueDescriptorPool mDescriptorPool; // Descriptor pool
std::vector<vk::DescriptorSet> mDescriptorSets; // Descriptor sets
std::vector<vk::UniqueCommandBuffer> mCommandBuffers;
// Command buffers
std::vector<vk::UniqueCommandBuffer> mCommandBuffers; // Command buffers
std::vector<vk::UniqueSemaphore> mImageAvailableSemaphores;
std::vector<vk::UniqueSemaphore> mRenderFinishedSemaphores;
std::vector<vk::UniqueFence> mInFlightFences;
// Synchronization primitives
std::vector<vk::UniqueSemaphore> mImageAvailableSemaphores; // Semaphores for image availability
std::vector<vk::UniqueSemaphore> mRenderFinishedSemaphores; // Semaphores for render completion
std::vector<vk::UniqueFence> mInFlightFences; // Fences for in-flight frames
bool mFramebufferResized = false;
u32 mCurrentFrame = 0;
// Framebuffer resize flag and current frame index
bool mFramebufferResized = false; // Flag indicating if the framebuffer was resized
u32 mCurrentFrame = 0; // Index of the current frame
// Struct to hold queue family indices
struct QueueFamilyIndices {
std::optional<u32> graphics_family;
std::optional<u32> present_family;
std::optional<u32> graphics_family; // Index of the graphics queue family
std::optional<u32> present_family; // Index of the presentation queue family
// Check if both queue families are available
fn isComplete() -> bool { return graphics_family.has_value() && present_family.has_value(); }
};
// Struct to hold swapchain support details
struct SwapChainSupportDetails {
vk::SurfaceCapabilitiesKHR capabilities;
std::vector<vk::SurfaceFormatKHR> formats;
std::vector<vk::PresentModeKHR> present_modes;
vk::SurfaceCapabilitiesKHR capabilities; // Surface capabilities
std::vector<vk::SurfaceFormatKHR> formats; // Supported surface formats
std::vector<vk::PresentModeKHR> present_modes; // Supported presentation modes
};
// Struct to hold uniform buffer object data
struct UniformBufferObject {
alignas(16) glm::mat4 model;
alignas(16) glm::mat4 view;
alignas(16) glm::mat4 proj;
alignas(16) glm::mat4 model; // Model matrix
alignas(16) glm::mat4 view; // View matrix
alignas(16) glm::mat4 proj; // Projection matrix
};
// Read a file into a vector of chars
@ -1157,14 +1170,17 @@ class VulkanApp {
return { std::move(image), std::move(imageMemory) };
}
// Transition image between layouts
fn transitionImageLayout(
const vk::Image& image,
const vk::ImageLayout& oldLayout,
const vk::ImageLayout& newLayout,
const u32& mipLevels
) -> void {
// Create a command buffer
vk::CommandBuffer commandBuffer = beginSingleTimeCommands();
// Define the image memory barrier
vk::ImageMemoryBarrier barrier {
.oldLayout = oldLayout,
.newLayout = newLayout,
@ -1180,9 +1196,11 @@ class VulkanApp {
},
};
// Define the source and destination stages
vk::PipelineStageFlags sourceStage;
vk::PipelineStageFlags destinationStage;
// Define the access masks
if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) {
barrier.srcAccessMask = {};
barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
@ -1197,11 +1215,14 @@ class VulkanApp {
sourceStage = vk::PipelineStageFlagBits::eTransfer;
destinationStage = vk::PipelineStageFlagBits::eFragmentShader;
} else {
// Ensure that the layout transition is supported
throw std::invalid_argument("Unsupported layout transition!");
}
// Record the pipeline barrier
commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier);
// End the command buffer
endSingleTimeCommands(commandBuffer);
}
@ -1646,17 +1667,27 @@ class VulkanApp {
}
fn updateUniformBuffer(const u32& currentImage) -> void {
// For convenience
using namespace std::chrono;
using time_point = high_resolution_clock::time_point;
using time_point = high_resolution_clock::time_point;
// Time of the program start
static time_point StartTime = high_resolution_clock::now();
// Current time
time_point currentTime = high_resolution_clock::now();
f32 time = duration<f32, seconds::period>(currentTime - StartTime).count();
// Time since the program started
f32 time = duration<f32, seconds::period>(currentTime - StartTime).count();
// Uniform buffer object
UniformBufferObject ubo {
// Model matrix - glm::rotate(matrix, angle, axis)
.model = glm::rotate(glm::mat4(1.0F), time * glm::radians(90.0F), glm::vec3(0.0F, 0.0F, 1.0F)),
// View matrix - glm::lookAt(eye, center, up)
.view =
glm::lookAt(glm::vec3(2.0F, 2.0F, 2.0F), glm::vec3(0.0F, 0.0F, 0.0F), glm::vec3(0.0F, 0.0F, 1.0F)),
// Projection matrix - glm::perspective(fov, aspect, near, far)
.proj = glm::perspective(
glm::radians(45.0F),
static_cast<f32>(mSwapChainExtent.width) / static_cast<f32>(mSwapChainExtent.height),
@ -1668,37 +1699,46 @@ class VulkanApp {
// Flip the Y axis, because glm was designed for OpenGL
ubo.proj[1][1] *= -1;
// Copy the uniform buffer object to the mapped memory
memcpy(mUniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
}
// Draw a frame to the window
fn drawFrame() -> void {
try {
// Wait for the fence to signal that the frame is finished
vk::Result result =
mDevice->waitForFences(mInFlightFences[mCurrentFrame].get(), vk::Bool32(vk::True), UINT64_MAX);
// Make sure the result is successful
if (result != vk::Result::eSuccess)
throw std::runtime_error("Failed to wait for fences!");
vk::Result imageIndexResult = vk::Result::eSuccess;
u32 imageIndexValue = 0;
std::tie(imageIndexResult, imageIndexValue) = mDevice->acquireNextImageKHR(
// Acquire the next image from the swap chain
auto [imageIndexResult, imageIndexValue] = mDevice->acquireNextImageKHR(
mSwapChain.get(), UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame].get(), nullptr
);
// Check if the swap chain needs to be recreated
if (imageIndexResult == vk::Result::eErrorOutOfDateKHR) {
recreateSwapChain();
return;
}
// Check if the image index is valid
if (imageIndexResult != vk::Result::eSuccess && imageIndexResult != vk::Result::eSuboptimalKHR)
throw std::runtime_error("Failed to acquire swap chain image!");
// Update the uniform buffer with the current image
updateUniformBuffer(mCurrentFrame);
// Reset the current fence
mDevice->resetFences(mInFlightFences[mCurrentFrame].get());
// Reset the current command buffer
mCommandBuffers[mCurrentFrame]->reset(vk::CommandBufferResetFlagBits::eReleaseResources);
// Define the command buffer submit info
recordCommandBuffer(mCommandBuffers[mCurrentFrame].get(), imageIndexValue);
std::array<vk::PipelineStageFlags, 1> waitStages = {
@ -1715,6 +1755,7 @@ class VulkanApp {
.pSignalSemaphores = &mRenderFinishedSemaphores[mCurrentFrame].get(),
};
// Submit the graphics queue
mGraphicsQueue.submit(submitInfo, mInFlightFences[mCurrentFrame].get());
vk::PresentInfoKHR presentInfo {
@ -1725,23 +1766,30 @@ class VulkanApp {
.pImageIndices = &imageIndexValue,
};
// Present the swap chain image
vk::Result presentResult = mPresentQueue.presentKHR(presentInfo);
// Check if the swap chain needs to be recreated
if (presentResult == vk::Result::eErrorOutOfDateKHR || presentResult == vk::Result::eSuboptimalKHR ||
mFramebufferResized) {
mFramebufferResized = false;
recreateSwapChain();
} else if (presentResult != vk::Result::eSuccess)
} else if (presentResult != vk::Result::eSuccess) {
// Throw if present failed
throw std::runtime_error("Failed to present swap chain image!");
}
// Increment the current frame (or loop back to 0)
mCurrentFrame = (mCurrentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
} catch (vk::OutOfDateKHRError& /*err*/) {
// Recreate the swap chain if it's out of date
mFramebufferResized = false;
recreateSwapChain();
return;
}
}
// Create the shader module
fn createShaderModule(const std::vector<char>& code) -> vk::UniqueShaderModule {
vk::ShaderModuleCreateInfo createInfo {
.codeSize = code.size(),