forked from pupbrained/vulkan-test
urggh
This commit is contained in:
parent
154a81721d
commit
b2779c119a
190
src/main.cpp
190
src/main.cpp
|
@ -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(),
|
||||
|
|
Loading…
Reference in a new issue