refactor
This commit is contained in:
parent
f5bd6f85a8
commit
dc88120f58
29 changed files with 321 additions and 278 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -1,3 +1,6 @@
|
|||
[submodule "extern/Modules"]
|
||||
path = extern/Modules
|
||||
url = https://github.com/elushaX/Modules.git
|
||||
[submodule "extern/imgui"]
|
||||
path = extern/imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@ project(App)
|
|||
set(CMAKE_CXX_STANDARD 26)
|
||||
|
||||
add_subdirectory(extern/Modules)
|
||||
add_subdirectory(extern/Utils)
|
||||
|
||||
add_subdirectory(src/Common)
|
||||
add_subdirectory(src/GPU)
|
||||
add_subdirectory(src/PlatformWindow)
|
||||
add_subdirectory(src/VulkanGraphics)
|
||||
add_subdirectory(src/App)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.30)
|
||||
|
||||
project(Common)
|
||||
project(Utils)
|
||||
|
||||
file(GLOB SOURCES "./private/*.cpp")
|
||||
add_library(${PROJECT_NAME} ${SOURCES})
|
||||
1
extern/imgui
vendored
Submodule
1
extern/imgui
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 5b7feebfd8f3e58392d955b4c8ae01f77eae25ed
|
||||
|
|
@ -5,6 +5,6 @@ project(App)
|
|||
file(GLOB SOURCES "./private/*.cpp")
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC public)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC Common GPU PlatformWindow)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC VulkanGraphics)
|
||||
|
||||
file(COPY shaders DESTINATION ${PROJECT_BINARY_DIR}/)
|
||||
|
|
@ -1,12 +1,29 @@
|
|||
#include "app_interactive.hpp"
|
||||
#include "app_offscreen.hpp"
|
||||
#include "VulkanWindow.hpp"
|
||||
#include "VulkanOffscreen.hpp"
|
||||
|
||||
#include "renderer.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int runOffscreen() {
|
||||
try {
|
||||
AppOffscreen app;
|
||||
app.run();
|
||||
VulkanOffscreen app;
|
||||
Renderer renderer;
|
||||
|
||||
renderer.create(app.getRenderInfo());
|
||||
app.setRenderPass(renderer.getRenderPass());
|
||||
|
||||
auto frameData = app.beginDrawFrame();
|
||||
|
||||
renderer.fillRenderCommands(frameData.commandBuffer, frameData.framebuffer, frameData.extent2D);
|
||||
renderer.updateUniformBuffer({frameData.extent2D.width, frameData.extent2D.height});
|
||||
|
||||
app.endDrawFrame(frameData);
|
||||
|
||||
app.saveFrame();
|
||||
|
||||
renderer.destroy(app.getDevice());
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
|
|
@ -16,10 +33,28 @@ int runOffscreen() {
|
|||
}
|
||||
|
||||
int runInteractive() {
|
||||
AppInteractive app;
|
||||
|
||||
try {
|
||||
app.run();
|
||||
Renderer renderer;
|
||||
VulkanWindow app;
|
||||
|
||||
renderer.create(app.getRenderInfo());
|
||||
app.setRenderPass(renderer.getRenderPass());
|
||||
|
||||
while (!glfwWindowShouldClose(app.getWindow())) {
|
||||
app.pollEvents();
|
||||
|
||||
auto drawData = app.startDrawFrame();
|
||||
|
||||
renderer.fillRenderCommands(drawData.commandBuffer, drawData.frameBuffer, drawData.extent2D);
|
||||
renderer.updateUniformBuffer({drawData.extent2D.width, drawData.extent2D.height});
|
||||
|
||||
app.endDrawFrame(drawData);
|
||||
}
|
||||
|
||||
app.waitDevice();
|
||||
renderer.destroy(app.getDevice());
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#include "renderer.hpp"
|
||||
#include "vulkan_utils.hpp"
|
||||
#include "VulkanUtils.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
|
||||
void Renderer::create(const CreateInfo &info) {
|
||||
void Renderer::create(const RenderCreateInfo &info) {
|
||||
mShader.create(info.device);
|
||||
|
||||
createRenderPass(info.device, info.format, info.finalImageLayout);
|
||||
|
|
@ -371,7 +371,7 @@ void Renderer::destroyBuffer(VkDevice device, VkBuffer buffer, VkDeviceMemory me
|
|||
}
|
||||
|
||||
void
|
||||
Renderer::populateGraphicsCommandBuffer(VkCommandBuffer commandBuffer, VkFramebuffer framebuffer, VkExtent2D extend) {
|
||||
Renderer::fillRenderCommands(VkCommandBuffer commandBuffer, VkFramebuffer framebuffer, VkExtent2D extend) {
|
||||
VkCommandBufferBeginInfo commandBufferBeginInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
};
|
||||
|
|
@ -472,3 +472,24 @@ void Renderer::copyBuffer(VkDevice device, VkCommandPool commandPool, VkQueue qu
|
|||
|
||||
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
|
||||
}
|
||||
|
||||
void Renderer::updateUniformBuffer(const std::pair<uint32_t, uint32_t>& frameBufferSize) const {
|
||||
static float time = 0;
|
||||
time += 0.001;
|
||||
|
||||
glm::mat4 model = glm::rotate(glm::mat4(1.0f), (time * glm::radians(90.f)), glm::vec3(0.f, 0.f, 1.f));
|
||||
glm::mat4 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});
|
||||
glm::mat4 perspective = glm::perspective(glm::radians(45.f),
|
||||
(float) frameBufferSize.first /
|
||||
(float) frameBufferSize.second, 0.1f, 10.f);
|
||||
|
||||
auto transforms = perspective * view * model;
|
||||
|
||||
CustomShader::UniformBuffer ubo{
|
||||
.transforms = transforms,
|
||||
.origin = glm::vec4(0, 0, 0, 0),
|
||||
};
|
||||
|
||||
memcpy(mUniformBufferMemoryMapped, &ubo, sizeof(ubo));
|
||||
// ubo.transforms =
|
||||
}
|
||||
|
|
@ -3,39 +3,11 @@
|
|||
#include "shader.hpp"
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
struct Renderer {
|
||||
CustomShader mShader;
|
||||
VkPipeline mGraphicsPipeline = VK_NULL_HANDLE;
|
||||
VkRenderPass mGraphicsRenderPass = VK_NULL_HANDLE;
|
||||
VkPipelineLayout mGraphicsPipelineLayout{}; // no uniforms used in the shader
|
||||
class Renderer {
|
||||
public:
|
||||
Renderer() = default;
|
||||
|
||||
// Buffers
|
||||
VkBuffer mVertexBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory mVertexBufferMemory = VK_NULL_HANDLE;
|
||||
|
||||
VkBuffer mIndexBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory mIndexBufferMemory = VK_NULL_HANDLE;
|
||||
|
||||
VkDescriptorPool mDescriptorPool = VK_NULL_HANDLE;
|
||||
VkDescriptorSet mDescriptorSet = VK_NULL_HANDLE;
|
||||
|
||||
VkBuffer mUniformBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory mUniformBufferMemory = VK_NULL_HANDLE;
|
||||
void* mUniformBufferMemoryMapped = nullptr;
|
||||
|
||||
struct CreateInfo {
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
VkExtent2D extent2D;
|
||||
VkFormat format;
|
||||
|
||||
VkCommandPool commandPool;
|
||||
VkQueue queue;
|
||||
|
||||
VkImageLayout finalImageLayout;
|
||||
};
|
||||
|
||||
void create(const CreateInfo& info);
|
||||
void create(const RenderCreateInfo& info);
|
||||
|
||||
void destroy(VkDevice device) const;
|
||||
|
||||
|
|
@ -56,7 +28,7 @@ struct Renderer {
|
|||
void createUniformBuffer(VkPhysicalDevice physicalDevice, VkDevice device);
|
||||
|
||||
|
||||
void populateGraphicsCommandBuffer(VkCommandBuffer commandBuffer, VkFramebuffer framebuffer, VkExtent2D extend);
|
||||
void fillRenderCommands(VkCommandBuffer commandBuffer, VkFramebuffer framebuffer, VkExtent2D extend);
|
||||
|
||||
struct BufferCreateInfo {
|
||||
VkBuffer *buffer;
|
||||
|
|
@ -74,4 +46,28 @@ struct Renderer {
|
|||
static void destroyBuffer(VkDevice device, VkBuffer buffer, VkDeviceMemory memory);
|
||||
|
||||
void destroyGraphicsPipeline(VkDevice device) const;
|
||||
|
||||
void updateUniformBuffer(const std::pair<uint32_t, uint32_t>& frameBufferSize) const;
|
||||
|
||||
VkRenderPass getRenderPass() { return mGraphicsRenderPass; }
|
||||
|
||||
private:
|
||||
CustomShader mShader;
|
||||
VkPipeline mGraphicsPipeline = VK_NULL_HANDLE;
|
||||
VkRenderPass mGraphicsRenderPass = VK_NULL_HANDLE;
|
||||
VkPipelineLayout mGraphicsPipelineLayout{}; // no uniforms used in the shader
|
||||
|
||||
// Buffers
|
||||
VkBuffer mVertexBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory mVertexBufferMemory = VK_NULL_HANDLE;
|
||||
|
||||
VkBuffer mIndexBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory mIndexBufferMemory = VK_NULL_HANDLE;
|
||||
|
||||
VkDescriptorPool mDescriptorPool = VK_NULL_HANDLE;
|
||||
VkDescriptorSet mDescriptorSet = VK_NULL_HANDLE;
|
||||
|
||||
VkBuffer mUniformBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory mUniformBufferMemory = VK_NULL_HANDLE;
|
||||
void* mUniformBufferMemoryMapped = nullptr;
|
||||
};
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.hpp"
|
||||
#include "VulkanInterface.hpp"
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "common.hpp"
|
||||
|
||||
struct CustomShader {
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
#pragma once
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.30)
|
||||
|
||||
project(PlatformWindow)
|
||||
|
||||
file(GLOB SOURCES "./private/*.cpp")
|
||||
add_library(${PROJECT_NAME} ${SOURCES})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC public)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC glfw GPU)
|
||||
|
|
@ -1 +0,0 @@
|
|||
#pragma once
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
cmake_minimum_required(VERSION 3.30)
|
||||
|
||||
project(GPU)
|
||||
project(VulkanGraphics)
|
||||
|
||||
file(GLOB SOURCES "./private/*.cpp")
|
||||
add_library(${PROJECT_NAME} ${SOURCES})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC public)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC vulkan Common)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC vulkan glfw Containers Math Utils)
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include "swapchain.hpp"
|
||||
#include "SwapChain.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
|
|
@ -1,23 +1,15 @@
|
|||
#include "app_offscreen.hpp"
|
||||
#include "VulkanOffscreen.hpp"
|
||||
|
||||
#include "Buffer2D.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
AppOffscreen::AppOffscreen() {
|
||||
VulkanOffscreen::VulkanOffscreen() {
|
||||
initDevice();
|
||||
initPipeline();
|
||||
initFramebuffer();
|
||||
initStagingBuffer();
|
||||
}
|
||||
|
||||
void AppOffscreen::run() {
|
||||
updateUniformBuffer();
|
||||
draw();
|
||||
transitionImageLayout();
|
||||
transferToHost();
|
||||
readMemory();
|
||||
}
|
||||
|
||||
AppOffscreen::~AppOffscreen() {
|
||||
VulkanOffscreen::~VulkanOffscreen() {
|
||||
vkDeviceWaitIdle(mDevice);
|
||||
|
||||
finalizeStagingBuffer();
|
||||
|
|
@ -26,7 +18,55 @@ AppOffscreen::~AppOffscreen() {
|
|||
finalizeDevice();
|
||||
}
|
||||
|
||||
void AppOffscreen::initDevice() {
|
||||
RenderCreateInfo VulkanOffscreen::getRenderInfo() {
|
||||
return {
|
||||
.device = mDevice,
|
||||
.physicalDevice = mPhysicalDevice,
|
||||
.extent2D = mExtent,
|
||||
.format = mFormat,
|
||||
.commandPool = mCommandPool,
|
||||
.queue = mGraphicsQueue,
|
||||
.finalImageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
// .finalImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
}
|
||||
|
||||
void VulkanOffscreen::setRenderPass(VkRenderPass renderPass) {
|
||||
initFramebuffer(renderPass);
|
||||
initStagingBuffer();
|
||||
}
|
||||
|
||||
VulkanOffscreen::FrameData VulkanOffscreen::beginDrawFrame() {
|
||||
return {
|
||||
mCommandBuffer, mFramebuffer, mExtent,
|
||||
};
|
||||
}
|
||||
|
||||
void VulkanOffscreen::endDrawFrame(const FrameData&) {
|
||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
|
||||
VkSubmitInfo submitInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitSemaphores = nullptr,
|
||||
.pWaitDstStageMask = waitStages,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &mCommandBuffer,
|
||||
.signalSemaphoreCount = 0,
|
||||
.pSignalSemaphores = nullptr,
|
||||
};
|
||||
|
||||
if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, nullptr) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to submit to graphics queue");
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanOffscreen::saveFrame() {
|
||||
transferToHost();
|
||||
readMemory();
|
||||
}
|
||||
|
||||
void VulkanOffscreen::initDevice() {
|
||||
std::vector<const char*> extensions = {};
|
||||
std::vector<const char*> validationLayers = {};
|
||||
std::vector<const char*> deviceExtensions = {};
|
||||
|
|
@ -97,8 +137,7 @@ void AppOffscreen::initDevice() {
|
|||
vkGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue);
|
||||
}
|
||||
|
||||
void AppOffscreen::initPipeline() {
|
||||
mShader.create(mDevice);
|
||||
void VulkanOffscreen::initPipeline() {
|
||||
|
||||
VkCommandPoolCreateInfo commandPoolCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
|
|
@ -117,22 +156,9 @@ void AppOffscreen::initPipeline() {
|
|||
};
|
||||
|
||||
vkAllocateCommandBuffers(mDevice, &allocateInfo, &mCommandBuffer);
|
||||
|
||||
Renderer::CreateInfo renderCreateInfo {
|
||||
.device = mDevice,
|
||||
.physicalDevice = mPhysicalDevice,
|
||||
.extent2D = mExtent,
|
||||
.format = mFormat,
|
||||
.commandPool = mCommandPool,
|
||||
.queue = mGraphicsQueue,
|
||||
.finalImageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
// .finalImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
||||
};
|
||||
|
||||
mRenderer.create(renderCreateInfo);
|
||||
}
|
||||
|
||||
void AppOffscreen::initFramebuffer() {
|
||||
void VulkanOffscreen::initFramebuffer(VkRenderPass renderPass) {
|
||||
// vkGetDeviceImageMemoryRequirements();
|
||||
|
||||
VkImageCreateInfo imageCreateInfo {
|
||||
|
|
@ -193,7 +219,7 @@ void AppOffscreen::initFramebuffer() {
|
|||
|
||||
VkFramebufferCreateInfo createInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
.renderPass = mRenderer.mGraphicsRenderPass,
|
||||
.renderPass = renderPass,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &mImageView,
|
||||
.width = mExtent.width,
|
||||
|
|
@ -206,32 +232,7 @@ void AppOffscreen::initFramebuffer() {
|
|||
}
|
||||
}
|
||||
|
||||
void AppOffscreen::draw() {
|
||||
mRenderer.populateGraphicsCommandBuffer(mCommandBuffer, mFramebuffer, mExtent);
|
||||
|
||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
|
||||
VkSubmitInfo submitInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitSemaphores = nullptr,
|
||||
.pWaitDstStageMask = waitStages,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &mCommandBuffer,
|
||||
.signalSemaphoreCount = 0,
|
||||
.pSignalSemaphores = nullptr,
|
||||
};
|
||||
|
||||
if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, nullptr) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to submit to graphics queue");
|
||||
}
|
||||
}
|
||||
|
||||
void AppOffscreen::transitionImageLayout() {
|
||||
|
||||
}
|
||||
|
||||
void AppOffscreen::transferToHost() {
|
||||
void VulkanOffscreen::transferToHost() {
|
||||
vkDeviceWaitIdle(mDevice);
|
||||
|
||||
VkBufferImageCopy stagingBufferToImageCopy {
|
||||
|
|
@ -289,7 +290,7 @@ void AppOffscreen::transferToHost() {
|
|||
}
|
||||
}
|
||||
|
||||
void AppOffscreen::readMemory() {
|
||||
void VulkanOffscreen::readMemory() {
|
||||
void* data;
|
||||
uint32_t size = mExtent.height * mExtent.width * sizeof(float) * 4;
|
||||
if (vkMapMemory(mDevice, mStagingBufferMemory, 0, size, 0, &data) != VK_SUCCESS) {
|
||||
|
|
@ -304,25 +305,7 @@ void AppOffscreen::readMemory() {
|
|||
vkUnmapMemory(mDevice, mStagingBufferMemory);
|
||||
}
|
||||
|
||||
void AppOffscreen::updateUniformBuffer() const {
|
||||
static float time = 0;
|
||||
time += 0.001;
|
||||
|
||||
glm::mat4 model = glm::rotate(glm::mat4(1.0f), (time * glm::radians(90.f)), glm::vec3(0.f, 0.f, 1.f));
|
||||
glm::mat4 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});
|
||||
glm::mat4 perspective = glm::perspective(glm::radians(45.f), (float) mExtent.width / (float) mExtent.height, 0.1f, 10.f);
|
||||
|
||||
auto transforms = perspective * view * model;
|
||||
|
||||
CustomShader::UniformBuffer ubo{
|
||||
.transforms = transforms,
|
||||
.origin = glm::vec4(0, 0, 0, 0),
|
||||
};
|
||||
|
||||
memcpy(mRenderer.mUniformBufferMemoryMapped, &ubo, sizeof(ubo));
|
||||
}
|
||||
|
||||
void AppOffscreen::initStagingBuffer() {
|
||||
void VulkanOffscreen::initStagingBuffer() {
|
||||
|
||||
VkBufferCreateInfo stagingBufferCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
|
|
@ -346,27 +329,24 @@ void AppOffscreen::initStagingBuffer() {
|
|||
vkBindBufferMemory(mDevice, mStagingBuffer, mStagingBufferMemory, 0);
|
||||
}
|
||||
|
||||
void AppOffscreen::finalizeStagingBuffer() {
|
||||
void VulkanOffscreen::finalizeStagingBuffer() {
|
||||
vkFreeMemory(mDevice, mStagingBufferMemory, nullptr);
|
||||
vkDestroyBuffer(mDevice, mStagingBuffer, nullptr);
|
||||
}
|
||||
|
||||
void AppOffscreen::finalizeFramebuffer() {
|
||||
void VulkanOffscreen::finalizeFramebuffer() {
|
||||
vkFreeMemory(mDevice, mFramebufferMemory, nullptr);
|
||||
vkDestroyFramebuffer(mDevice, mFramebuffer, nullptr);
|
||||
vkDestroyImageView(mDevice, mImageView, nullptr);
|
||||
vkDestroyImage(mDevice, mImage, nullptr);
|
||||
}
|
||||
|
||||
void AppOffscreen::finalizePipeline() {
|
||||
void VulkanOffscreen::finalizePipeline() {
|
||||
vkFreeCommandBuffers(mDevice, mCommandPool, 1, &mCommandBuffer);
|
||||
vkDestroyCommandPool(mDevice, mCommandPool, nullptr);
|
||||
|
||||
mShader.destroy(mDevice);
|
||||
mRenderer.destroy(mDevice);
|
||||
}
|
||||
|
||||
void AppOffscreen::finalizeDevice() {
|
||||
void VulkanOffscreen::finalizeDevice() {
|
||||
vkDestroyDevice(mDevice, nullptr);
|
||||
vkDestroyInstance(mInstance, nullptr);
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "vulkan_utils.hpp"
|
||||
#include "VulkanUtils.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
|
@ -1,32 +1,69 @@
|
|||
#include "app_interactive.hpp"
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "renderer.hpp"
|
||||
#include "swapchain.hpp"
|
||||
#include "vulkan_utils.hpp"
|
||||
#include "VulkanWindow.hpp"
|
||||
#include "SwapChain.hpp"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <chrono>
|
||||
|
||||
VulkanWindow::VulkanWindow() {
|
||||
mSwapChain = new SwapChain();
|
||||
|
||||
void AppInteractive::run() {
|
||||
initWindow();
|
||||
initVulkan();
|
||||
mainLoop();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void AppInteractive::scheduleWindowResize(int sizeX, int sizeY) {
|
||||
VulkanWindow::~VulkanWindow() {
|
||||
cleanup();
|
||||
delete mSwapChain;
|
||||
}
|
||||
|
||||
RenderCreateInfo VulkanWindow::getRenderInfo() {
|
||||
return {
|
||||
mDevice, mPhysicalDevice,
|
||||
mSwapChain->mSwapChainExtent, mSwapChain->mSwapChainFormat,
|
||||
mCommandPool, mGraphicsQueue, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
|
||||
};
|
||||
}
|
||||
|
||||
GLFWwindow* VulkanWindow::getWindow() {
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
VkDevice VulkanWindow::getDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
void VulkanWindow::setRenderPass(VkRenderPass renderPass) {
|
||||
mRenderPass = renderPass;
|
||||
mSwapChain->createSwapChainFramebuffers(mDevice, mRenderPass);
|
||||
}
|
||||
|
||||
void VulkanWindow::pollEvents() {
|
||||
glfwPollEvents();
|
||||
|
||||
if (mWindowSizeDirtyFlag) {
|
||||
if (timeDeltaMs(mWindowSizeDirtyFlagTime) > mWindowSizeApplyMinDelay) {
|
||||
recreateSwapChain(mWindowFramebufferSize.first, mWindowFramebufferSize.second);
|
||||
mWindowSizeDirtyFlag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanWindow::waitDevice() {
|
||||
vkDeviceWaitIdle(mDevice);
|
||||
}
|
||||
|
||||
void VulkanWindow::scheduleWindowResize(int sizeX, int sizeY) {
|
||||
mWindowSizeDirtyFlagTime = std::chrono::system_clock::now();
|
||||
mWindowSizeDirtyFlag = true;
|
||||
mWindowFramebufferSize = std::make_pair(sizeX, sizeY);
|
||||
assert(!(sizeX <= 0 || sizeY <= 0));
|
||||
}
|
||||
|
||||
void AppInteractive::initWindow() {
|
||||
void VulkanWindow::initWindow() {
|
||||
// glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11);
|
||||
glfwInit();
|
||||
|
||||
|
|
@ -37,11 +74,11 @@ void AppInteractive::initWindow() {
|
|||
|
||||
glfwSetWindowUserPointer(mWindow, this);
|
||||
glfwSetFramebufferSizeCallback(mWindow, [](GLFWwindow *window, int sizeX, int sizeY) {
|
||||
((AppInteractive *) glfwGetWindowUserPointer(window))->scheduleWindowResize(sizeX, sizeY);
|
||||
((VulkanWindow *) glfwGetWindowUserPointer(window))->scheduleWindowResize(sizeX, sizeY);
|
||||
});
|
||||
}
|
||||
|
||||
void AppInteractive::initVulkan() {
|
||||
void VulkanWindow::initVulkan() {
|
||||
const std::vector<const char *> deviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
};
|
||||
|
|
@ -105,44 +142,16 @@ void AppInteractive::initVulkan() {
|
|||
.presentationQueueFamilyIndex = (uint32_t) mPresentationQueueFamilyIndex,
|
||||
};
|
||||
|
||||
mSwapChain.createSwapChain(swapChainCreateInfo);
|
||||
mSwapChain.createSwapChainImageViews(mDevice);
|
||||
mSwapChain->createSwapChain(swapChainCreateInfo);
|
||||
mSwapChain->createSwapChainImageViews(mDevice);
|
||||
|
||||
createCommandPool();
|
||||
createCommandBuffer();
|
||||
|
||||
Renderer::CreateInfo rendererCreateInfo{
|
||||
mDevice, mPhysicalDevice,
|
||||
mSwapChain.mSwapChainExtent, mSwapChain.mSwapChainFormat,
|
||||
mCommandPool, mGraphicsQueue, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
|
||||
};
|
||||
|
||||
mRenderer.create(rendererCreateInfo);
|
||||
|
||||
mSwapChain.createSwapChainFramebuffers(mDevice, mRenderer.mGraphicsRenderPass);
|
||||
|
||||
createSynchronizationObjects();
|
||||
}
|
||||
|
||||
void AppInteractive::mainLoop() {
|
||||
while (!glfwWindowShouldClose(mWindow)) {
|
||||
glfwPollEvents();
|
||||
|
||||
if (mWindowSizeDirtyFlag) {
|
||||
auto timeDelayMs = timeDeltaMs(mWindowSizeDirtyFlagTime);
|
||||
if (timeDelayMs > mWindowSizeApplyMinDelay) {
|
||||
recreateSwapChain(mWindowFramebufferSize.first, mWindowFramebufferSize.second);
|
||||
mWindowSizeDirtyFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
drawFrame();
|
||||
}
|
||||
|
||||
vkDeviceWaitIdle(mDevice);
|
||||
}
|
||||
|
||||
void AppInteractive::createLogicalDevice(const std::vector<const char *> &deviceExtensions) {
|
||||
void VulkanWindow::createLogicalDevice(const std::vector<const char *> &deviceExtensions) {
|
||||
float queuePriority = 1.f;
|
||||
|
||||
VkDeviceQueueCreateInfo graphicsQueueCreateInfos{
|
||||
|
|
@ -181,21 +190,21 @@ void AppInteractive::createLogicalDevice(const std::vector<const char *> &device
|
|||
if (mDevice == VK_NULL_HANDLE) throw std::runtime_error("failed to create vulkan logical device");
|
||||
}
|
||||
|
||||
void AppInteractive::getQueues() {
|
||||
void VulkanWindow::getQueues() {
|
||||
vkGetDeviceQueue(mDevice, mGraphicsQueueFamilyIndex, 0, &mGraphicsQueue);
|
||||
vkGetDeviceQueue(mDevice, mPresentationQueueFamilyIndex, 0, &mPresentQueue);
|
||||
}
|
||||
|
||||
void AppInteractive::createWindowSurface() {
|
||||
void VulkanWindow::createWindowSurface() {
|
||||
if (glfwCreateWindowSurface(mInstance, mWindow, nullptr, &mSurface) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create vulkan window surface");
|
||||
}
|
||||
}
|
||||
|
||||
void AppInteractive::recreateSwapChain(int sizeX, int sizeY) {
|
||||
void VulkanWindow::recreateSwapChain(int sizeX, int sizeY) {
|
||||
vkDeviceWaitIdle(mDevice);
|
||||
|
||||
mSwapChain.destroySwapChain(mDevice);
|
||||
mSwapChain->destroySwapChain(mDevice);
|
||||
|
||||
SwapChain::CreateInfo createInfo{
|
||||
.device = mDevice,
|
||||
|
|
@ -207,13 +216,12 @@ void AppInteractive::recreateSwapChain(int sizeX, int sizeY) {
|
|||
.presentationQueueFamilyIndex = (uint32_t) mPresentationQueueFamilyIndex,
|
||||
};
|
||||
|
||||
mSwapChain.createSwapChain(createInfo);
|
||||
mSwapChain.createSwapChainImageViews(mDevice);
|
||||
mSwapChain.createSwapChainFramebuffers(mDevice, mRenderer.mGraphicsRenderPass);
|
||||
mSwapChain->createSwapChain(createInfo);
|
||||
mSwapChain->createSwapChainImageViews(mDevice);
|
||||
mSwapChain->createSwapChainFramebuffers(mDevice, mRenderPass);
|
||||
}
|
||||
|
||||
|
||||
void AppInteractive::createSynchronizationObjects() {
|
||||
void VulkanWindow::createSynchronizationObjects() {
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
};
|
||||
|
|
@ -232,18 +240,27 @@ void AppInteractive::createSynchronizationObjects() {
|
|||
if (failure) throw std::runtime_error("failed to create synchronization objects");
|
||||
}
|
||||
|
||||
void AppInteractive::drawFrame() {
|
||||
VulkanWindow::DrawFrame VulkanWindow::startDrawFrame() {
|
||||
vkWaitForFences(mDevice, 1, &mFenceCanStartNewFrame, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(mDevice, 1, &mFenceCanStartNewFrame);
|
||||
|
||||
uint32_t imageIndex = 0;
|
||||
vkAcquireNextImageKHR(mDevice, mSwapChain.mSwapChain, UINT64_MAX, mSemaphoreImageAcquired, VK_NULL_HANDLE,
|
||||
vkAcquireNextImageKHR(mDevice, mSwapChain->mSwapChain, UINT64_MAX, mSemaphoreImageAcquired, VK_NULL_HANDLE,
|
||||
&imageIndex);
|
||||
|
||||
vkResetCommandBuffer(mCommandBuffer, 0);
|
||||
mRenderer.populateGraphicsCommandBuffer(mCommandBuffer, mSwapChain.mSwapChainFrameBuffers[imageIndex],
|
||||
mSwapChain.mSwapChainExtent);
|
||||
|
||||
VkFramebuffer framebuffer = mSwapChain->mSwapChainFrameBuffers[imageIndex];
|
||||
|
||||
return {
|
||||
.commandBuffer = mCommandBuffer,
|
||||
.frameBuffer = framebuffer,
|
||||
.extent2D = mSwapChain->mSwapChainExtent,
|
||||
.swapChainImageIndex = imageIndex,
|
||||
};
|
||||
}
|
||||
|
||||
void VulkanWindow::endDrawFrame(const DrawFrame& frame) {
|
||||
VkSemaphore waitSemaphores[] = {mSemaphoreImageAcquired};
|
||||
VkSemaphore signalSemaphores[] = {mSemaphoreFramebufferDrawn};
|
||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||
|
|
@ -259,13 +276,11 @@ void AppInteractive::drawFrame() {
|
|||
.pSignalSemaphores = signalSemaphores,
|
||||
};
|
||||
|
||||
updateUniformBuffer();
|
||||
|
||||
if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mFenceCanStartNewFrame) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to submit to graphics queue");
|
||||
}
|
||||
|
||||
VkSwapchainKHR swapchains[] = {mSwapChain.mSwapChain};
|
||||
VkSwapchainKHR swapchains[] = {mSwapChain->mSwapChain};
|
||||
|
||||
VkPresentInfoKHR presentInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
|
|
@ -273,53 +288,23 @@ void AppInteractive::drawFrame() {
|
|||
.pWaitSemaphores = signalSemaphores,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = swapchains,
|
||||
.pImageIndices = &imageIndex,
|
||||
.pImageIndices = &frame.swapChainImageIndex,
|
||||
};
|
||||
|
||||
vkQueuePresentKHR(mPresentQueue, &presentInfo);
|
||||
/* Somehow res is always VK_SUCCESS
|
||||
if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) {
|
||||
recreateSwapChain();
|
||||
} else if (res != VK_SUCCESS) {
|
||||
throw std::runtime_error("cannot acquire new khr image");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void AppInteractive::updateUniformBuffer() const {
|
||||
static float time = 0;
|
||||
time += 0.001;
|
||||
|
||||
glm::mat4 model = glm::rotate(glm::mat4(1.0f), (time * glm::radians(90.f)), glm::vec3(0.f, 0.f, 1.f));
|
||||
glm::mat4 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});
|
||||
glm::mat4 perspective = glm::perspective(glm::radians(45.f),
|
||||
(float) mWindowFramebufferSize.first /
|
||||
(float) mWindowFramebufferSize.second, 0.1f, 10.f);
|
||||
|
||||
auto transforms = perspective * view * model;
|
||||
|
||||
CustomShader::UniformBuffer ubo{
|
||||
.transforms = transforms,
|
||||
.origin = glm::vec4(0, 0, 0, 0),
|
||||
};
|
||||
|
||||
memcpy(mRenderer.mUniformBufferMemoryMapped, &ubo, sizeof(ubo));
|
||||
// ubo.transforms =
|
||||
}
|
||||
|
||||
void AppInteractive::destroySynchronizationObjects() {
|
||||
void VulkanWindow::destroySynchronizationObjects() {
|
||||
vkDestroySemaphore(mDevice, mSemaphoreImageAcquired, nullptr);
|
||||
vkDestroySemaphore(mDevice, mSemaphoreFramebufferDrawn, nullptr);
|
||||
vkDestroyFence(mDevice, mFenceCanStartNewFrame, nullptr);
|
||||
}
|
||||
|
||||
void AppInteractive::cleanup() {
|
||||
mRenderer.destroy(mDevice);
|
||||
|
||||
void VulkanWindow::cleanup() {
|
||||
destroyCommandPool();
|
||||
destroySynchronizationObjects();
|
||||
|
||||
mSwapChain.destroySwapChain(mDevice);
|
||||
mSwapChain->destroySwapChain(mDevice);
|
||||
|
||||
vkDestroyDevice(mDevice, nullptr);
|
||||
vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
|
||||
|
|
@ -328,7 +313,7 @@ void AppInteractive::cleanup() {
|
|||
glfwTerminate();
|
||||
}
|
||||
|
||||
void AppInteractive::createCommandPool() {
|
||||
void VulkanWindow::createCommandPool() {
|
||||
VkCommandPoolCreateInfo createInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
|
|
@ -340,7 +325,7 @@ void AppInteractive::createCommandPool() {
|
|||
}
|
||||
}
|
||||
|
||||
void AppInteractive::createCommandBuffer() {
|
||||
void VulkanWindow::createCommandBuffer() {
|
||||
VkCommandBufferAllocateInfo allocateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = mCommandPool,
|
||||
|
|
@ -353,6 +338,6 @@ void AppInteractive::createCommandBuffer() {
|
|||
}
|
||||
}
|
||||
|
||||
void AppInteractive::destroyCommandPool() {
|
||||
void VulkanWindow::destroyCommandPool() {
|
||||
vkDestroyCommandPool(mDevice, mCommandPool, nullptr);
|
||||
}
|
||||
15
src/VulkanGraphics/public/VulkanInterface.hpp
Normal file
15
src/VulkanGraphics/public/VulkanInterface.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
struct RenderCreateInfo {
|
||||
VkDevice device;
|
||||
VkPhysicalDevice physicalDevice;
|
||||
VkExtent2D extent2D;
|
||||
VkFormat format;
|
||||
|
||||
VkCommandPool commandPool;
|
||||
VkQueue queue;
|
||||
|
||||
VkImageLayout finalImageLayout;
|
||||
};
|
||||
|
|
@ -1,39 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include "vulkan_utils.hpp"
|
||||
#include "VulkanUtils.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <functional>
|
||||
#include <cstring>
|
||||
|
||||
#include "renderer.hpp"
|
||||
#include "shader.hpp"
|
||||
|
||||
class AppOffscreen {
|
||||
class VulkanOffscreen {
|
||||
|
||||
public:
|
||||
AppOffscreen();
|
||||
VulkanOffscreen();
|
||||
~VulkanOffscreen();
|
||||
|
||||
void run();
|
||||
RenderCreateInfo getRenderInfo();
|
||||
void setRenderPass(VkRenderPass renderPass);
|
||||
|
||||
~AppOffscreen();
|
||||
struct FrameData {
|
||||
VkCommandBuffer commandBuffer;
|
||||
VkFramebuffer framebuffer;
|
||||
VkExtent2D extent2D;
|
||||
};
|
||||
|
||||
FrameData beginDrawFrame();
|
||||
void endDrawFrame(const FrameData& frame);
|
||||
|
||||
void saveFrame();
|
||||
|
||||
VkDevice getDevice() { return mDevice; }
|
||||
|
||||
private:
|
||||
void initDevice();
|
||||
|
||||
void initPipeline();
|
||||
|
||||
void initFramebuffer();
|
||||
void initFramebuffer(VkRenderPass renderPass);
|
||||
|
||||
void initStagingBuffer();
|
||||
|
||||
void draw();
|
||||
|
||||
void transitionImageLayout();
|
||||
|
||||
void readMemory();
|
||||
|
||||
void updateUniformBuffer() const;
|
||||
|
||||
void transferToHost();
|
||||
|
||||
void finalizeStagingBuffer();
|
||||
|
|
@ -70,7 +75,4 @@ private:
|
|||
|
||||
VkBuffer mStagingBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory mStagingBufferMemory = VK_NULL_HANDLE;
|
||||
|
||||
Renderer mRenderer;
|
||||
CustomShader mShader;
|
||||
};
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "VulkanInterface.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
|
|
@ -1,16 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include "vulkan_utils.hpp"
|
||||
#include "VulkanUtils.hpp"
|
||||
|
||||
#include "renderer.hpp"
|
||||
#include "swapchain.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
class AppInteractive {
|
||||
class SwapChain;
|
||||
|
||||
class VulkanWindow {
|
||||
public:
|
||||
void run();
|
||||
VulkanWindow();
|
||||
~VulkanWindow();
|
||||
|
||||
GLFWwindow* getWindow();
|
||||
VkDevice getDevice();
|
||||
RenderCreateInfo getRenderInfo();
|
||||
void setRenderPass(VkRenderPass renderPass);
|
||||
|
||||
struct DrawFrame{
|
||||
VkCommandBuffer commandBuffer;
|
||||
VkFramebuffer frameBuffer;
|
||||
VkExtent2D extent2D;
|
||||
uint32_t swapChainImageIndex;
|
||||
};
|
||||
|
||||
void pollEvents();
|
||||
void waitDevice();
|
||||
|
||||
DrawFrame startDrawFrame();
|
||||
void endDrawFrame(const DrawFrame& frame);
|
||||
|
||||
void scheduleWindowResize(int sizeX, int sizeY);
|
||||
|
||||
|
|
@ -19,8 +38,6 @@ private:
|
|||
|
||||
void initVulkan();
|
||||
|
||||
void mainLoop();
|
||||
|
||||
void createLogicalDevice(const std::vector<const char *> &deviceExtensions);
|
||||
|
||||
void getQueues();
|
||||
|
|
@ -31,10 +48,6 @@ private:
|
|||
|
||||
void createSynchronizationObjects();
|
||||
|
||||
void drawFrame();
|
||||
|
||||
void updateUniformBuffer() const;
|
||||
|
||||
void destroySynchronizationObjects();
|
||||
|
||||
void cleanup();
|
||||
|
|
@ -67,9 +80,10 @@ private:
|
|||
VkQueue mPresentQueue = VK_NULL_HANDLE;
|
||||
|
||||
VkSurfaceKHR mSurface = VK_NULL_HANDLE;
|
||||
SwapChain mSwapChain;
|
||||
SwapChain* mSwapChain = nullptr;
|
||||
|
||||
Renderer mRenderer;
|
||||
VkRenderPass mRenderPass = VK_NULL_HANDLE;
|
||||
// Renderer* mRenderer = nullptr;
|
||||
|
||||
VkSemaphore mSemaphoreImageAcquired = VK_NULL_HANDLE;
|
||||
VkSemaphore mSemaphoreFramebufferDrawn = VK_NULL_HANDLE;
|
||||
Loading…
Add table
Add a link
Reference in a new issue