Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 119-graphicspipeline-refactoring
  • 129-projekte-und-assets-auslagern
  • 132-denoising-module
  • 143-ar-vr-support-via-openxr
  • 43-multi-threading
  • 91-compute-first-network
  • 95-arm64-raspberry-pi-4-support
  • develop
  • master
  • optimizations
  • 0.1.0
  • 0.2.0
12 results

Target

Select target project
  • vulkan2021/vkcv-framework
1 result
Select Git revision
  • 119-graphicspipeline-refactoring
  • 129-projekte-und-assets-auslagern
  • 132-denoising-module
  • 143-ar-vr-support-via-openxr
  • 43-multi-threading
  • 91-compute-first-network
  • 95-arm64-raspberry-pi-4-support
  • develop
  • master
  • optimizations
  • 0.1.0
  • 0.2.0
12 results
Show changes
Commits on Source (17)
Showing
with 405 additions and 258 deletions
......@@ -50,10 +50,7 @@ set(vkcv_sources
${vkcv_include}/vkcv/QueueManager.hpp
${vkcv_source}/vkcv/QueueManager.cpp
${vkcv_source}/vkcv/Surface.hpp
${vkcv_source}/vkcv/Surface.cpp
${vkcv_source}/vkcv/ImageLayoutTransitions.hpp
${vkcv_source}/vkcv/ImageLayoutTransitions.cpp
......
......@@ -56,13 +56,12 @@ namespace vkcv
*
* @param context encapsulates various Vulkan objects
*/
Core(Context &&context, Window &window, SwapChain swapChain, std::vector<vk::ImageView> imageViews,
Core(Context &&context, Window &window, const SwapChain& swapChain, std::vector<vk::ImageView> imageViews,
const CommandResources& commandResources, const SyncResources& syncResources) noexcept;
// explicit destruction of default constructor
Core() = delete;
Result acquireSwapchainImage();
void destroyTemporaryFramebuffers();
Context m_Context;
......@@ -80,16 +79,12 @@ namespace vkcv
CommandResources m_CommandResources;
SyncResources m_SyncResources;
uint32_t m_currentSwapchainImageIndex;
std::vector<vk::Framebuffer> m_TemporaryFramebuffers;
ImageHandle m_DepthImage;
/**
* recreates the swapchain
* @param[in] width new window width
* @param[in] height new window hight
*/
static void recreateSwapchain(int width, int height);
std::function<void(int, int)> e_resizeHandle;
static std::vector<vk::ImageView> createImageViews( Context &context, SwapChain& swapChain);
public:
/**
......@@ -230,14 +225,12 @@ namespace vkcv
* @brief render a beautiful triangle
*/
void renderMesh(
const PassHandle renderpassHandle,
const PipelineHandle pipelineHandle,
const uint32_t width,
const uint32_t height,
const PassHandle &renderpassHandle,
const PipelineHandle &pipelineHandle,
const size_t pushConstantSize,
const void* pushConstantData,
const std::vector<VertexBufferBinding> &vertexBufferBindings,
const BufferHandle indexBuffer,
const BufferHandle &indexBuffer,
const size_t indexCount,
const vkcv::ResourcesHandle resourceHandle,
const size_t resourceDescriptorSetIndex);
......
......@@ -3,15 +3,32 @@
#include "Context.hpp"
#include "vkcv/Window.hpp"
namespace vkcv {
#include <atomic>
namespace vkcv
{
class SwapChain final {
private:
vk::SurfaceKHR m_surface;
vk::SwapchainKHR m_swapchain;
vk::SurfaceFormatKHR m_format;
struct Surface
{
vk::SurfaceKHR handle;
std::vector<vk::SurfaceFormatKHR> formats;
vk::SurfaceCapabilitiesKHR capabilities;
std::vector<vk::PresentModeKHR> presentModes;
};
Surface m_Surface;
uint32_t m_ImageCount;
vk::SwapchainKHR m_Swapchain;
vk::Format m_SwapchainFormat;
vk::ColorSpaceKHR m_SwapchainColorSpace;
vk::PresentModeKHR m_SwapchainPresentMode;
uint32_t m_SwapchainImageCount;
vk::Extent2D m_Extent;
std::atomic<bool> m_RecreationRequired;
/**
* Constructor of a SwapChain object
......@@ -21,11 +38,17 @@ namespace vkcv {
* @param swapchain to show images in the window
* @param format
*/
SwapChain(vk::SurfaceKHR surface, vk::SwapchainKHR swapchain, vk::SurfaceFormatKHR format, uint32_t imageCount);
// TODO:
SwapChain(const Surface &surface,
vk::SwapchainKHR swapchain,
vk::Format format,
vk::ColorSpaceKHR colorSpace,
vk::PresentModeKHR presentMode,
uint32_t imageCount,
vk::Extent2D extent) noexcept;
public:
SwapChain(const SwapChain &other) = default;
SwapChain(SwapChain &&other) = default;
SwapChain(const SwapChain& other);
/**
* @return The swapchain linked with the #SwapChain class
......@@ -39,13 +62,14 @@ namespace vkcv {
* @return current surface
*/
[[nodiscard]]
vk::SurfaceKHR getSurface();
vk::SurfaceKHR getSurface() const;
/**
* gets the current surface format
* @return gets the surface format
* gets the chosen swapchain format
* @return gets the chosen swapchain format
*/
[[nodiscard]]
vk::SurfaceFormatKHR getSurfaceFormat();
vk::Format getSwapchainFormat() const;
/**
* creates a swap chain object out of the given window and the given context
......@@ -53,7 +77,7 @@ namespace vkcv {
* @param context of the application
* @return returns an object of swapChain
*/
static SwapChain create(const Window &window, const Context &context, const vk::SurfaceKHR surface);
static SwapChain create(const Window &window, const Context &context);
/**
* Destructor of SwapChain
......@@ -64,6 +88,34 @@ namespace vkcv {
* @return number of images in swapchain
*/
uint32_t getImageCount();
};
/**
* TODO
*
* @return
*/
bool shouldUpdateSwapchain() const;
/**
* TODO
*
* context
* window
*/
void updateSwapchain(const Context &context, const Window &window);
/**
*
*/
void recreateSwapchain();
/**
* TODO
*
* @return
*/
[[nodiscard]]
const vk::Extent2D& getExtent() const;
};
}
......@@ -17,7 +17,6 @@ namespace vkcv {
private:
GLFWwindow *m_window;
/**
*
* @param GLFWwindow of the class
......
......@@ -63,7 +63,7 @@ namespace vkcv {
void changeFov(double fov);
void updateRatio(float ratio);
void updateRatio(int width, int height);
float getRatio() const;
......
......@@ -9,10 +9,11 @@ namespace vkcv{
class CameraManager{
private:
std::function<void(int, int, int, int)> m_keyHandle;
std::function<void(double, double)> m_mouseMoveHandle;
std::function<void(double, double)> m_mouseScrollHandle;
std::function<void(int, int, int)> m_mouseButtonHandle;
std::function<void(int, int, int, int)> e_keyHandle;
std::function<void(double, double)> e_mouseMoveHandle;
std::function<void(double, double)> e_mouseScrollHandle;
std::function<void(int, int, int)> e_mouseButtonHandle;
std::function<void(int, int)> e_resizeHandle;
Window &m_window;
Camera m_camera;
......@@ -29,6 +30,7 @@ namespace vkcv{
void scrollCallback( double offsetX, double offsetY);
void mouseMoveCallback( double offsetX, double offsetY);
void mouseButtonCallback(int button, int action, int mods);
void resizeCallback(int width, int height);
public:
CameraManager(Window &window, float width, float height, glm::vec3 up = glm::vec3(0.0f,-1.0f,0.0f), glm::vec3 position = glm::vec3(0.0f,0.0f,0.0f));
......
......@@ -82,8 +82,10 @@ namespace vkcv {
setFov(fov);
}
void Camera::updateRatio( float ratio){
m_ratio = ratio;
void Camera::updateRatio( int width, int height){
m_width = width;
m_height = height;
m_ratio = static_cast<float>(width)/glm::max(height, 1);
setPerspective( m_fov, m_ratio, m_near, m_far);
}
......
......@@ -15,10 +15,11 @@ namespace vkcv{
}
void CameraManager::bindCamera(){
m_keyHandle = m_window.e_key.add( [&](int key, int scancode, int action, int mods) { this->keyCallback(key, scancode, action, mods); });
m_mouseMoveHandle = m_window.e_mouseMove.add( [&]( double offsetX, double offsetY) {this->mouseMoveCallback( offsetX, offsetY);} );
m_mouseScrollHandle = m_window.e_mouseScroll.add([&](double offsetX, double offsetY) {this->scrollCallback( offsetX, offsetY);} );
m_mouseButtonHandle = m_window.e_mouseButton.add([&] (int button, int action, int mods) {this->mouseButtonCallback( button, action, mods);});
e_keyHandle = m_window.e_key.add( [&](int key, int scancode, int action, int mods) { this->keyCallback(key, scancode, action, mods); });
e_mouseMoveHandle = m_window.e_mouseMove.add( [&]( double offsetX, double offsetY) {this->mouseMoveCallback( offsetX, offsetY);} );
e_mouseScrollHandle = m_window.e_mouseScroll.add([&](double offsetX, double offsetY) {this->scrollCallback( offsetX, offsetY);} );
e_mouseButtonHandle = m_window.e_mouseButton.add([&] (int button, int action, int mods) {this->mouseButtonCallback( button, action, mods);});
e_resizeHandle = m_window.e_resize.add([&] (int width, int height) {this->resizeCallback( width, height);});
}
void CameraManager::mouseButtonCallback(int button, int action, int mods){
......@@ -75,6 +76,11 @@ namespace vkcv{
break;
}
}
void CameraManager::resizeCallback(int width, int height){
m_camera.updateRatio(width, height);
}
Camera &CameraManager::getCamera(){
return m_camera;
}
......
......@@ -8,16 +8,14 @@
int main(int argc, const char** argv) {
const char* applicationName = "First Mesh";
const int windowWidth = 800;
const int windowHeight = 600;
vkcv::Window window = vkcv::Window::create(
applicationName,
windowWidth,
windowHeight,
false
800,
600,
true
);
vkcv::CameraManager cameraManager(window, windowWidth, windowHeight);
vkcv::CameraManager cameraManager(window, static_cast<float>(window.getWidth()), static_cast<float>(window.getHeight()));
window.initEvents();
......@@ -43,7 +41,7 @@ int main(int argc, const char** argv) {
return 1;
}
assert(mesh.vertexGroups.size() > 0);
assert(!mesh.vertexGroups.empty());
auto vertexBuffer = core.createBuffer<uint8_t>(
vkcv::BufferType::VERTEX,
mesh.vertexGroups[0].vertexBuffer.data.size(),
......@@ -112,9 +110,9 @@ int main(int argc, const char** argv) {
//end of exemplary code
const vkcv::PipelineConfig trianglePipelineDefinition(
triangleShaderProgram,
windowWidth,
windowHeight,
triangleShaderProgram,
UINT32_MAX,
UINT32_MAX,
trianglePass,
mesh.vertexGroups[0].vertexBuffer.attributes,
{ core.getDescriptorSetLayout(set, 0) });
......@@ -148,8 +146,12 @@ int main(int argc, const char** argv) {
auto start = std::chrono::system_clock::now();
while (window.isWindowOpen()) {
vkcv::Window::pollEvents();
if(window.getHeight() == 0 || window.getWidth() == 0)
continue;
core.beginFrame();
window.pollEvents();
auto end = std::chrono::system_clock::now();
auto deltatime = end - start;
start = end;
......@@ -159,8 +161,6 @@ int main(int argc, const char** argv) {
core.renderMesh(
trianglePass,
trianglePipeline,
windowWidth,
windowHeight,
sizeof(mvp),
&mvp,
vertexBufferBindings,
......
......@@ -147,8 +147,6 @@ int main(int argc, const char** argv) {
core.renderMesh(
trianglePass,
trianglePipeline,
windowWidth,
windowHeight,
sizeof(mvp),
&mvp,
vertexBufferBindings,
......
......@@ -13,7 +13,6 @@
#include "SamplerManager.hpp"
#include "ImageManager.hpp"
#include "DescriptorManager.hpp"
#include "Surface.hpp"
#include "ImageLayoutTransitions.hpp"
namespace vkcv
......@@ -32,40 +31,11 @@ namespace vkcv
instanceExtensions,
deviceExtensions
);
const vk::SurfaceKHR surface = createSurface(
window.getWindow(),
context.getInstance(),
context.getPhysicalDevice()
);
SwapChain swapChain = SwapChain::create(window, context, surface);
SwapChain swapChain = SwapChain::create(window, context);
std::vector<vk::Image> swapChainImages = context.getDevice().getSwapchainImagesKHR(swapChain.getSwapchain());
std::vector<vk::ImageView> imageViews;
imageViews.reserve( swapChainImages.size() );
//here can be swizzled with vk::ComponentSwizzle if needed
vk::ComponentMapping componentMapping(
vk::ComponentSwizzle::eR,
vk::ComponentSwizzle::eG,
vk::ComponentSwizzle::eB,
vk::ComponentSwizzle::eA );
vk::ImageSubresourceRange subResourceRange( vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1 );
for ( auto image : swapChainImages )
{
vk::ImageViewCreateInfo imageViewCreateInfo(
vk::ImageViewCreateFlags(),
image,
vk::ImageViewType::e2D,
swapChain.getSurfaceFormat().format,
componentMapping,
subResourceRange
);
imageViews.push_back(context.getDevice().createImageView(imageViewCreateInfo));
}
imageViews = createImageViews( context, swapChain);
const auto& queueManager = context.getQueueManager();
......@@ -74,10 +44,6 @@ namespace vkcv
const auto commandResources = createCommandResources(context.getDevice(), queueFamilySet);
const auto defaultSyncResources = createSyncResources(context.getDevice());
window.e_resize.add([&](int width, int height){
recreateSwapchain(width,height);
});
return Core(std::move(context) , window, swapChain, imageViews, commandResources, defaultSyncResources);
}
......@@ -86,7 +52,7 @@ namespace vkcv
return m_Context;
}
Core::Core(Context &&context, Window &window , SwapChain swapChain, std::vector<vk::ImageView> imageViews,
Core::Core(Context &&context, Window &window, const SwapChain& swapChain, std::vector<vk::ImageView> imageViews,
const CommandResources& commandResources, const SyncResources& syncResources) noexcept :
m_Context(std::move(context)),
m_window(window),
......@@ -105,6 +71,10 @@ namespace vkcv
m_BufferManager->init();
m_ImageManager->m_core = this;
e_resizeHandle = window.e_resize.add( [&](int width, int height) {
m_swapchain.recreateSwapchain();
});
}
Core::~Core() noexcept {
......@@ -115,7 +85,6 @@ namespace vkcv
destroyCommandResources(m_Context.getDevice(), m_CommandResources);
destroySyncResources(m_Context.getDevice(), m_SyncResources);
destroyTemporaryFramebuffers();
m_Context.m_Device.destroySwapchainKHR(m_swapchain.getSwapchain());
m_Context.m_Instance.destroySurfaceKHR(m_swapchain.getSurface());
......@@ -144,6 +113,7 @@ namespace vkcv
);
if (acquireResult != vk::Result::eSuccess) {
std::cerr << vk::to_string(acquireResult) << std::endl;
return Result::ERROR;
}
......@@ -151,37 +121,33 @@ namespace vkcv
return Result::SUCCESS;
}
void Core::destroyTemporaryFramebuffers() {
for (const vk::Framebuffer f : m_TemporaryFramebuffers) {
m_Context.getDevice().destroyFramebuffer(f);
}
m_TemporaryFramebuffers.clear();
}
void Core::beginFrame() {
if (m_swapchain.shouldUpdateSwapchain()) {
m_Context.getDevice().waitIdle();
for (auto image : m_swapchainImageViews)
m_Context.m_Device.destroyImageView(image);
m_swapchain.updateSwapchain(m_Context, m_window);
m_swapchainImageViews = createImageViews(m_Context, m_swapchain);
}
if (acquireSwapchainImage() != Result::SUCCESS) {
return;
std::cerr << "Acquire failed!" << std::endl;
m_currentSwapchainImageIndex = std::numeric_limits<uint32_t>::max();
}
m_Context.getDevice().waitIdle(); // FIMXE: this is a sin against graphics programming, but its getting late - Alex
destroyTemporaryFramebuffers();
}
vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass& renderpass,
const int width, const int height, const std::vector<vk::ImageView>& attachments) {
const vk::FramebufferCreateFlags flags = {};
const vk::FramebufferCreateInfo createInfo(flags, renderpass, attachments.size(), attachments.data(), width, height, 1);
return device.createFramebuffer(createInfo);
m_Context.getDevice().waitIdle(); // TODO: this is a sin against graphics programming, but its getting late - Alex
}
void Core::renderMesh(
const PassHandle renderpassHandle,
const PipelineHandle pipelineHandle,
const uint32_t width,
const uint32_t height,
const size_t pushConstantSize,
const PassHandle &renderpassHandle,
const PipelineHandle &pipelineHandle,
const size_t pushConstantSize,
const void *pushConstantData,
const std::vector<VertexBufferBinding>& vertexBufferBindings,
const BufferHandle indexBuffer,
const BufferHandle &indexBuffer,
const size_t indexCount,
const vkcv::ResourcesHandle resourceHandle,
const size_t resourceDescriptorSetIndex
......@@ -190,6 +156,11 @@ namespace vkcv
if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
return;
}
const vk::Extent2D& extent = m_swapchain.getExtent();
const uint32_t width = extent.width;
const uint32_t height = extent.height;
const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle);
const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle);
......@@ -212,6 +183,7 @@ namespace vkcv
const vk::ImageView imageView = m_swapchainImageViews[m_currentSwapchainImageIndex];
const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle);
const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle);
const vkcv::PipelineConfig pipelineConfig = m_PipelineManager->getPipelineConfig(pipelineHandle);
const vk::Rect2D renderArea(vk::Offset2D(0, 0), vk::Extent2D(width, height));
const vk::Buffer vulkanIndexBuffer = m_BufferManager->getBuffer(indexBuffer);
......@@ -222,15 +194,25 @@ namespace vkcv
attachments.push_back(m_ImageManager->getVulkanImageView(m_DepthImage));
}
const vk::Framebuffer framebuffer = createFramebuffer(
m_Context.getDevice(),
renderpass,
width,
height,
attachments
);
m_TemporaryFramebuffers.push_back(framebuffer);
vk::Framebuffer framebuffer = nullptr;
const vk::FramebufferCreateInfo createInfo({},
renderpass,
static_cast<uint32_t>(attachments.size()),
attachments.data(),
width,
height,
1);
if(m_Context.m_Device.createFramebuffer(&createInfo, nullptr, &framebuffer) != vk::Result::eSuccess)
{
std::cout << "FAILED TO CREATE TEMPORARY FRAMEBUFFER!" << std::endl;
return;
}
vk::Viewport dynamicViewport(0.0f, 0.0f,
static_cast<float>(width), static_cast<float>(height),
0.0f, 1.0f);
vk::Rect2D dynamicScissor({0, 0}, {width, height});
auto &bufferManager = m_BufferManager;
......@@ -238,48 +220,61 @@ namespace vkcv
submitInfo.queueType = QueueType::Graphics;
submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
submitCommands(submitInfo, [&](const vk::CommandBuffer& cmdBuffer) {
std::vector<vk::ClearValue> clearValues;
for (const auto& attachment : passConfig.attachments) {
if (attachment.load_operation == AttachmentOperation::CLEAR) {
float clear = 0.0f;
if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
clear = 1.0f;
}
clearValues.emplace_back(std::array<float, 4>{
clear,
clear,
clear,
1.f
});
}
}
const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
const vk::SubpassContents subpassContents = {};
cmdBuffer.beginRenderPass(beginInfo, subpassContents, {});
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
std::vector<vk::ClearValue> clearValues;
for (const auto& attachment : passConfig.attachments) {
if (attachment.load_operation == AttachmentOperation::CLEAR) {
float clear = 0.0f;
if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) {
clear = 1.0f;
}
clearValues.emplace_back(std::array<float, 4>{
clear,
clear,
clear,
1.f
});
}
}
const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
const vk::SubpassContents subpassContents = {};
cmdBuffer.beginRenderPass(beginInfo, subpassContents, {});
cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
if(pipelineConfig.m_Height == UINT32_MAX && pipelineConfig.m_Width == UINT32_MAX)
{
cmdBuffer.setViewport(0, 1, &dynamicViewport);
cmdBuffer.setScissor(0, 1, &dynamicScissor);
}
for (uint32_t i = 0; i < vertexBufferBindings.size(); i++) {
const auto &vertexBinding = vertexBufferBindings[i];
const auto vertexBuffer = bufferManager->getBuffer(vertexBinding.buffer);
cmdBuffer.bindVertexBuffers(i, (vertexBuffer), (vertexBinding.offset));
}
if (resourceHandle) {
const vk::DescriptorSet descriptorSet = m_DescriptorManager->getDescriptorSet(resourceHandle, resourceDescriptorSetIndex);
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSet, nullptr);
}
cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size
cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData);
cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {});
cmdBuffer.endRenderPass();
};
auto finishFunction = [&]()
{
m_Context.m_Device.destroy(framebuffer);
};
for (uint32_t i = 0; i < vertexBufferBindings.size(); i++) {
const auto &vertexBinding = vertexBufferBindings[i];
const auto vertexBuffer = bufferManager->getBuffer(vertexBinding.buffer);
cmdBuffer.bindVertexBuffers(i, (vertexBuffer), (vertexBinding.offset));
}
if (resourceHandle) {
const vk::DescriptorSet descriptorSet = m_DescriptorManager->getDescriptorSet(resourceHandle, resourceDescriptorSetIndex);
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSet, nullptr);
}
cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16); //FIXME: choose proper size
cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData);
cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {});
cmdBuffer.endRenderPass();
}, nullptr);
submitCommands(submitInfo, submitFunction, finishFunction);
}
void Core::endFrame() {
......@@ -288,8 +283,7 @@ namespace vkcv
}
const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain());
const vk::Image presentImage = swapchainImages[m_currentSwapchainImageIndex];
const auto& queueManager = m_Context.getQueueManager();
std::array<vk::Semaphore, 2> waitSemaphores{
m_SyncResources.renderFinished,
......@@ -309,13 +303,8 @@ namespace vkcv
}
vk::Format Core::getSwapchainImageFormat() {
return m_swapchain.getSurfaceFormat().format;
return m_swapchain.getSwapchainFormat();
}
void Core::recreateSwapchain(int width, int height) {
/* boilerplate for #34 */
std::cout << "Resized to : " << width << " , " << height << std::endl;
}
void Core::submitCommands(const SubmitInfo &submitInfo, const RecordCommandFunction& record, const FinishCommandFunction& finish)
{
......@@ -369,4 +358,33 @@ namespace vkcv
vk::DescriptorSetLayout Core::getDescriptorSetLayout(ResourcesHandle handle, size_t setIndex) {
return m_DescriptorManager->getDescriptorSetLayout(handle, setIndex);
}
std::vector<vk::ImageView> Core::createImageViews( Context &context, SwapChain& swapChain){
std::vector<vk::ImageView> imageViews;
std::vector<vk::Image> swapChainImages = context.getDevice().getSwapchainImagesKHR(swapChain.getSwapchain());
imageViews.reserve( swapChainImages.size() );
//here can be swizzled with vk::ComponentSwizzle if needed
vk::ComponentMapping componentMapping(
vk::ComponentSwizzle::eR,
vk::ComponentSwizzle::eG,
vk::ComponentSwizzle::eB,
vk::ComponentSwizzle::eA );
vk::ImageSubresourceRange subResourceRange( vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1 );
for ( auto image : swapChainImages )
{
vk::ImageViewCreateInfo imageViewCreateInfo(
vk::ImageViewCreateFlags(),
image,
vk::ImageViewType::e2D,
swapChain.getSwapchainFormat(),
componentMapping,
subResourceRange
);
imageViews.push_back(context.getDevice().createImageView(imageViewCreateInfo));
}
return imageViews;
}
}
......@@ -5,7 +5,8 @@ namespace vkcv
PipelineManager::PipelineManager(vk::Device device) noexcept :
m_Device{device},
m_Pipelines{}
m_Pipelines{},
m_Configs{}
{}
PipelineManager::~PipelineManager() noexcept
......@@ -94,8 +95,8 @@ namespace vkcv
//FIXME: hoping that order is the same and compatible: add explicit mapping and validation
const VertexAttribute attribute = config.m_vertexAttributes[i];
vertexAttributeDescriptions.push_back({location, binding, vertexFormatToVulkanFormat(attachment.format), 0});
vertexBindingDescriptions.push_back(vk::VertexInputBindingDescription(
vertexAttributeDescriptions.emplace_back(location, binding, vertexFormatToVulkanFormat(attachment.format), 0);
vertexBindingDescriptions.emplace_back(vk::VertexInputBindingDescription(
binding,
attribute.stride + getFormatSize(attachment.format),
vk::VertexInputRate::eVertex));
......@@ -211,8 +212,19 @@ namespace vkcv
break;
}
}
// graphics pipeline create
std::vector<vk::DynamicState> dynamicStates = {};
if(config.m_Width == UINT32_MAX && config.m_Height == UINT32_MAX)
{
dynamicStates.push_back(vk::DynamicState::eViewport);
dynamicStates.push_back(vk::DynamicState::eScissor);
}
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo({},
static_cast<uint32_t>(dynamicStates.size()),
dynamicStates.data());
// graphics pipeline create
std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo };
const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
{},
......@@ -226,7 +238,7 @@ namespace vkcv
&pipelineMultisampleStateCreateInfo,
p_depthStencilCreateInfo,
&pipelineColorBlendStateCreateInfo,
nullptr,
&dynamicStateCreateInfo,
vkPipelineLayout,
pass,
0,
......@@ -247,6 +259,7 @@ namespace vkcv
const uint64_t id = m_Pipelines.size();
m_Pipelines.push_back({ vkPipeline, vkPipelineLayout });
m_Configs.push_back(config);
return PipelineHandle(id, [&](uint64_t id) { destroyPipelineById(id); });
}
......@@ -293,5 +306,11 @@ namespace vkcv
pipeline.m_layout = nullptr;
}
}
const PipelineConfig &PipelineManager::getPipelineConfig(const PipelineHandle &handle) const
{
const uint64_t id = handle.getId();
return m_Configs.at(id);
}
}
\ No newline at end of file
......@@ -18,6 +18,7 @@ namespace vkcv
vk::Device m_Device;
std::vector<Pipeline> m_Pipelines;
std::vector<PipelineConfig> m_Configs;
void destroyPipelineById(uint64_t id);
......@@ -36,7 +37,11 @@ namespace vkcv
[[nodiscard]]
vk::Pipeline getVkPipeline(const PipelineHandle &handle) const;
[[nodiscard]]
vk::PipelineLayout getVkPipelineLayout(const PipelineHandle &handle) const;
[[nodiscard]]
const PipelineConfig &getPipelineConfig(const PipelineHandle &handle) const;
};
}
#include "Surface.hpp"
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
namespace vkcv {
/**
* creates surface and checks availability
* @param window current window for the surface
* @param instance Vulkan-Instance
* @param physicalDevice Vulkan-PhysicalDevice
* @return created surface
*/
vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice) {
//create surface
VkSurfaceKHR surface;
if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) {
throw std::runtime_error("failed to create a window surface!");
}
vk::Bool32 surfaceSupport = false;
if (physicalDevice.getSurfaceSupportKHR(0, vk::SurfaceKHR(surface), &surfaceSupport) != vk::Result::eSuccess && surfaceSupport != true) {
throw std::runtime_error("surface is not supported by the device!");
}
return vk::SurfaceKHR(surface);
}
}
#pragma once
#include <vulkan/vulkan.hpp>
struct GLFWwindow;
namespace vkcv {
vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice);
}
\ No newline at end of file
#include <vkcv/SwapChain.hpp>
#include <utility>
namespace vkcv {
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
SwapChain::SwapChain(vk::SurfaceKHR surface, vk::SwapchainKHR swapchain, vk::SurfaceFormatKHR format, uint32_t imageCount)
: m_surface(surface), m_swapchain(swapchain), m_format( format), m_ImageCount(imageCount)
namespace vkcv
{
/**
* creates surface and checks availability
* @param window current window for the surface
* @param instance Vulkan-Instance
* @param physicalDevice Vulkan-PhysicalDevice
* @return created surface
*/
vk::SurfaceKHR createSurface(GLFWwindow* window, const vk::Instance& instance, const vk::PhysicalDevice& physicalDevice) {
//create surface
VkSurfaceKHR surface;
if (glfwCreateWindowSurface(VkInstance(instance), window, nullptr, &surface) != VK_SUCCESS) {
throw std::runtime_error("failed to create a window surface!");
}
vk::Bool32 surfaceSupport = false;
if (physicalDevice.getSurfaceSupportKHR(0, vk::SurfaceKHR(surface), &surfaceSupport) != vk::Result::eSuccess && surfaceSupport != true) {
throw std::runtime_error("surface is not supported by the device!");
}
return vk::SurfaceKHR(surface);
}
SwapChain::SwapChain(const Surface &surface,
vk::SwapchainKHR swapchain,
vk::Format format,
vk::ColorSpaceKHR colorSpace,
vk::PresentModeKHR presentMode,
uint32_t imageCount,
vk::Extent2D extent) noexcept :
m_Surface(surface),
m_Swapchain(swapchain),
m_SwapchainFormat(format),
m_SwapchainColorSpace(colorSpace),
m_SwapchainPresentMode(presentMode),
m_SwapchainImageCount(imageCount),
m_Extent(extent),
m_RecreationRequired(false)
{}
SwapChain::SwapChain(const SwapChain &other) :
m_Surface(other.m_Surface),
m_Swapchain(other.m_Swapchain),
m_SwapchainFormat(other.m_SwapchainFormat),
m_SwapchainColorSpace(other.m_SwapchainColorSpace),
m_SwapchainPresentMode(other.m_SwapchainPresentMode),
m_SwapchainImageCount(other.m_SwapchainImageCount),
m_Extent(other.m_Extent),
m_RecreationRequired(other.m_RecreationRequired.load())
{}
const vk::SwapchainKHR& SwapChain::getSwapchain() const {
return m_swapchain;
return m_Swapchain;
}
/**
* gets surface of the swapchain
* @return current surface
*/
vk::SurfaceKHR SwapChain::getSurface() {
return m_surface;
vk::SurfaceKHR SwapChain::getSurface() const {
return m_Surface.handle;
}
/**
* gets the surface of the swapchain
* @return chosen format
*/
vk::SurfaceFormatKHR SwapChain::getSurfaceFormat(){
return m_format;
vk::Format SwapChain::getSwapchainFormat() const{
return m_SwapchainFormat;
}
/**
......@@ -33,7 +74,7 @@ namespace vkcv {
* @param window of the current application
* @return chosen Extent for the surface
*/
vk::Extent2D chooseSwapExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window){
vk::Extent2D chooseExtent(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface, const Window &window){
vk::SurfaceCapabilitiesKHR surfaceCapabilities;
if(physicalDevice.getSurfaceCapabilitiesKHR(surface,&surfaceCapabilities) != vk::Result::eSuccess){
throw std::runtime_error("cannot get surface capabilities. There is an issue with the surface.");
......@@ -43,15 +84,10 @@ namespace vkcv {
static_cast<uint32_t>(window.getWidth()),
static_cast<uint32_t>(window.getHeight())
};
extent2D.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, extent2D.width));
extent2D.height = std::max(surfaceCapabilities.minImageExtent.height, std::min(surfaceCapabilities.maxImageExtent.height, extent2D.height));
if (extent2D.width > surfaceCapabilities.maxImageExtent.width ||
extent2D.width < surfaceCapabilities.minImageExtent.width ||
extent2D.height > surfaceCapabilities.maxImageExtent.height ||
extent2D.height < surfaceCapabilities.minImageExtent.height) {
std::printf("Surface size not matching. Resizing to allowed value.");
}
return extent2D;
}
......@@ -61,7 +97,7 @@ namespace vkcv {
* @param surface of the swapchain
* @return available Format
*/
vk::SurfaceFormatKHR chooseSwapSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
uint32_t formatCount;
physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, nullptr);
std::vector<vk::SurfaceFormatKHR> availableFormats(formatCount);
......@@ -126,23 +162,29 @@ namespace vkcv {
* @param context that keeps instance, physicalDevice and a device.
* @return swapchain
*/
SwapChain SwapChain::create(const Window &window, const Context &context, const vk::SurfaceKHR surface) {
SwapChain SwapChain::create(const Window &window, const Context &context) {
const vk::Instance& instance = context.getInstance();
const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice();
const vk::Device& device = context.getDevice();
vk::Extent2D extent2D = chooseSwapExtent(physicalDevice, surface, window);
vk::SurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(physicalDevice, surface);
vk::PresentModeKHR presentMode = choosePresentMode(physicalDevice, surface);
uint32_t imageCount = chooseImageCount(physicalDevice, surface);
Surface surface;
surface.handle = createSurface(window.getWindow(), instance, physicalDevice);
surface.formats = physicalDevice.getSurfaceFormatsKHR(surface.handle);
surface.capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.handle);
surface.presentModes = physicalDevice.getSurfacePresentModesKHR(surface.handle);
vk::Extent2D chosenExtent = chooseExtent(physicalDevice, surface.handle, window);
vk::SurfaceFormatKHR chosenSurfaceFormat = chooseSurfaceFormat(physicalDevice, surface.handle);
vk::PresentModeKHR chosenPresentMode = choosePresentMode(physicalDevice, surface.handle);
uint32_t chosenImageCount = chooseImageCount(physicalDevice, surface.handle);
vk::SwapchainCreateInfoKHR swapchainCreateInfo(
vk::SwapchainCreateFlagsKHR(), //flags
surface, // surface
imageCount, // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" -> 3 for Triple Buffering, else 2 for Double Buffering (should be the standard)
surfaceFormat.format, // imageFormat
surfaceFormat.colorSpace, // imageColorSpace
extent2D, // imageExtent
surface.handle, // surface
chosenImageCount, // minImageCount TODO: how many do we need for our application?? "must be less than or equal to the value returned in maxImageCount" -> 3 for Triple Buffering, else 2 for Double Buffering (should be the standard)
chosenSurfaceFormat.format, // imageFormat
chosenSurfaceFormat.colorSpace, // imageColorSpace
chosenExtent, // imageExtent
1, // imageArrayLayers TODO: should we only allow non-stereoscopic applications? yes -> 1, no -> ? "must be greater than 0, less or equal to maxImageArrayLayers"
vk::ImageUsageFlagBits::eColorAttachment, // imageUsage TODO: what attachments? only color? depth?
vk::SharingMode::eExclusive, // imageSharingMode TODO: which sharing mode? "VK_SHARING_MODE_EXCLUSIV access exclusive to a single queue family, better performance", "VK_SHARING_MODE_CONCURRENT access from multiple queues"
......@@ -150,22 +192,71 @@ namespace vkcv {
nullptr, // pQueueFamilyIndices, the pointer to an array of queue family indices having access to the images(s) of the swapchain when imageSharingMode is VK_SHARING_MODE_CONCURRENT
vk::SurfaceTransformFlagBitsKHR::eIdentity, // preTransform, transformations applied onto the image before display
vk::CompositeAlphaFlagBitsKHR::eOpaque, // compositeAlpha, TODO: how to handle transparent pixels? do we need transparency? If no -> opaque
presentMode, // presentMode
chosenPresentMode, // presentMode
true, // clipped
nullptr // oldSwapchain
);
vk::SwapchainKHR swapchain = device.createSwapchainKHR(swapchainCreateInfo);
return SwapChain(surface, swapchain, surfaceFormat, imageCount);
return SwapChain(surface,
swapchain,
chosenSurfaceFormat.format,
chosenSurfaceFormat.colorSpace,
chosenPresentMode,
chosenImageCount,
chosenExtent);
}
bool SwapChain::shouldUpdateSwapchain() const {
return m_RecreationRequired;
}
void SwapChain::updateSwapchain(const Context &context, const Window &window) {
if (!m_RecreationRequired.exchange(false))
return;
vk::SwapchainKHR oldSwapchain = m_Swapchain;
vk::Extent2D extent2D = chooseExtent(context.getPhysicalDevice(), m_Surface.handle, window);
vk::SwapchainCreateInfoKHR swapchainCreateInfo(
vk::SwapchainCreateFlagsKHR(),
m_Surface.handle,
m_SwapchainImageCount,
m_SwapchainFormat,
m_SwapchainColorSpace,
extent2D,
1,
vk::ImageUsageFlagBits::eColorAttachment,
vk::SharingMode::eExclusive,
0,
nullptr,
vk::SurfaceTransformFlagBitsKHR::eIdentity,
vk::CompositeAlphaFlagBitsKHR::eOpaque,
m_SwapchainPresentMode,
true,
oldSwapchain
);
m_Swapchain = context.getDevice().createSwapchainKHR(swapchainCreateInfo);
context.getDevice().destroySwapchainKHR(oldSwapchain);
m_Extent = extent2D;
}
void SwapChain::recreateSwapchain() {
m_RecreationRequired = true;
}
const vk::Extent2D& SwapChain::getExtent() const {
return m_Extent;
}
SwapChain::~SwapChain() {
// needs to be destroyed by creator
}
uint32_t SwapChain::getImageCount() {
return m_ImageCount;
return m_SwapchainImageCount;
}
}