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
#include "vkcv/Handles.hpp" #include "vkcv/Handles.hpp"
#include <iostream>
namespace vkcv { namespace vkcv {
Handle::Handle() : Handle::Handle() :
...@@ -11,7 +13,7 @@ namespace vkcv { ...@@ -11,7 +13,7 @@ namespace vkcv {
{} {}
Handle::~Handle() { Handle::~Handle() {
if ((m_rc) && (--(*m_rc) == 0)) { if ((m_rc) && (*m_rc > 0) && (--(*m_rc) == 0)) {
if (m_destroy) { if (m_destroy) {
m_destroy(m_id); m_destroy(m_id);
} }
...@@ -82,9 +84,9 @@ namespace vkcv { ...@@ -82,9 +84,9 @@ namespace vkcv {
std::ostream& operator << (std::ostream& out, const Handle& handle) { std::ostream& operator << (std::ostream& out, const Handle& handle) {
if (handle) { if (handle) {
return out << "[Handle: " << handle.getId() << ":" << handle.getRC() << "]"; return out << "[" << typeid(handle).name() << ": " << handle.getId() << ":" << handle.getRC() << "]";
} else { } else {
return out << "[Handle: none]"; return out << "[" << typeid(handle).name() << ": none]";
} }
} }
......
...@@ -56,7 +56,7 @@ namespace vkcv{ ...@@ -56,7 +56,7 @@ namespace vkcv{
m_manager->switchImageLayoutImmediate(m_handle, newLayout); m_manager->switchImageLayoutImmediate(m_handle, newLayout);
} }
vkcv::ImageHandle Image::getHandle() const { const vkcv::ImageHandle& Image::getHandle() const {
return m_handle; return m_handle;
} }
...@@ -64,7 +64,7 @@ namespace vkcv{ ...@@ -64,7 +64,7 @@ namespace vkcv{
return m_manager->getImageMipCount(m_handle); return m_manager->getImageMipCount(m_handle);
} }
void Image::fill(void *data, size_t size) { void Image::fill(const void *data, size_t size) {
m_manager->fillImage(m_handle, data, size); m_manager->fillImage(m_handle, data, size);
} }
......
...@@ -12,26 +12,6 @@ ...@@ -12,26 +12,6 @@
namespace vkcv { namespace vkcv {
ImageManager::Image::Image(
vk::Image handle,
vk::DeviceMemory memory,
std::vector<vk::ImageView> views,
uint32_t width,
uint32_t height,
uint32_t depth,
vk::Format format,
uint32_t layers)
:
m_handle(handle),
m_memory(memory),
m_viewPerMip(views),
m_width(width),
m_height(height),
m_depth(depth),
m_format(format),
m_layers(layers)
{}
/** /**
* @brief searches memory type index for image allocation, combines requirements of image and application * @brief searches memory type index for image allocation, combines requirements of image and application
* @param physicalMemoryProperties Memory Properties of physical device * @param physicalMemoryProperties Memory Properties of physical device
...@@ -67,7 +47,8 @@ namespace vkcv { ...@@ -67,7 +47,8 @@ namespace vkcv {
for (uint64_t id = 0; id < m_images.size(); id++) { for (uint64_t id = 0; id < m_images.size(); id++) {
destroyImageById(id); destroyImageById(id);
} }
for (const auto swapchainImage : m_swapchainImages) {
for (const auto& swapchainImage : m_swapchainImages) {
for (const auto view : swapchainImage.m_viewPerMip) { for (const auto view : swapchainImage.m_viewPerMip) {
m_core->getContext().getDevice().destroy(view); m_core->getContext().getDevice().destroy(view);
} }
...@@ -123,7 +104,7 @@ namespace vkcv { ...@@ -123,7 +104,7 @@ namespace vkcv {
imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment; imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment;
} }
const vk::Device& device = m_core->getContext().getDevice(); const vma::Allocator& allocator = m_core->getContext().getAllocator();
vk::ImageType imageType = vk::ImageType::e3D; vk::ImageType imageType = vk::ImageType::e3D;
vk::ImageViewType imageViewType = vk::ImageViewType::e3D; vk::ImageViewType imageViewType = vk::ImageViewType::e3D;
...@@ -157,7 +138,7 @@ namespace vkcv { ...@@ -157,7 +138,7 @@ namespace vkcv {
vk::SampleCountFlagBits sampleCountFlag = msaaToVkSampleCountFlag(msaa); vk::SampleCountFlagBits sampleCountFlag = msaaToVkSampleCountFlag(msaa);
const vk::ImageCreateInfo imageCreateInfo( const vk::ImageCreateInfo imageCreateInfo (
createFlags, createFlags,
imageType, imageType,
format, format,
...@@ -171,21 +152,22 @@ namespace vkcv { ...@@ -171,21 +152,22 @@ namespace vkcv {
{}, {},
vk::ImageLayout::eUndefined vk::ImageLayout::eUndefined
); );
vk::Image image = device.createImage(imageCreateInfo);
const vk::MemoryRequirements requirements = device.getImageMemoryRequirements(image); auto imageAllocation = allocator.createImage(
imageCreateInfo,
vk::MemoryPropertyFlags memoryTypeFlags = vk::MemoryPropertyFlagBits::eDeviceLocal; vma::AllocationCreateInfo(
vma::AllocationCreateFlags(),
const uint32_t memoryTypeIndex = searchImageMemoryType( vma::MemoryUsage::eGpuOnly,
physicalDevice.getMemoryProperties(), vk::MemoryPropertyFlagBits::eDeviceLocal,
requirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eDeviceLocal,
memoryTypeFlags 0,
vma::Pool(),
nullptr
)
); );
vk::DeviceMemory memory = device.allocateMemory(vk::MemoryAllocateInfo(requirements.size, memoryTypeIndex)); vk::Image image = imageAllocation.first;
device.bindImageMemory(image, memory, 0); vma::Allocation allocation = imageAllocation.second;
vk::ImageAspectFlags aspectFlags; vk::ImageAspectFlags aspectFlags;
...@@ -195,8 +177,10 @@ namespace vkcv { ...@@ -195,8 +177,10 @@ namespace vkcv {
aspectFlags = vk::ImageAspectFlagBits::eColor; aspectFlags = vk::ImageAspectFlagBits::eColor;
} }
const vk::Device& device = m_core->getContext().getDevice();
std::vector<vk::ImageView> views; std::vector<vk::ImageView> views;
for (int mip = 0; mip < mipCount; mip++) { for (uint32_t mip = 0; mip < mipCount; mip++) {
const vk::ImageViewCreateInfo imageViewCreateInfo( const vk::ImageViewCreateInfo imageViewCreateInfo(
{}, {},
image, image,
...@@ -221,11 +205,11 @@ namespace vkcv { ...@@ -221,11 +205,11 @@ namespace vkcv {
} }
const uint64_t id = m_images.size(); const uint64_t id = m_images.size();
m_images.push_back(Image(image, memory, views, width, height, depth, format, arrayLayers)); m_images.push_back({ image, allocation, views, width, height, depth, format, arrayLayers, vk::ImageLayout::eUndefined });
return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); }); return ImageHandle(id, [&](uint64_t id) { destroyImageById(id); });
} }
ImageHandle ImageManager::createSwapchainImage() { ImageHandle ImageManager::createSwapchainImage() const {
return ImageHandle::createSwapchainImageHandle(); return ImageHandle::createSwapchainImageHandle();
} }
...@@ -261,10 +245,16 @@ namespace vkcv { ...@@ -261,10 +245,16 @@ namespace vkcv {
auto& image = m_images[id]; auto& image = m_images[id];
return image.m_memory; const vma::Allocator& allocator = m_core->getContext().getAllocator();
auto info = allocator.getAllocationInfo(
image.m_allocation
);
return info.deviceMemory;
} }
vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, const size_t mipLevel) const { vk::ImageView ImageManager::getVulkanImageView(const ImageHandle &handle, size_t mipLevel) const {
if (handle.isSwapchainImage()) { if (handle.isSwapchainImage()) {
return m_swapchainImages[m_currentSwapchainInputImage].m_viewPerMip[0]; return m_swapchainImages[m_currentSwapchainInputImage].m_viewPerMip[0];
...@@ -369,7 +359,7 @@ namespace vkcv { ...@@ -369,7 +359,7 @@ namespace vkcv {
} }
} }
void ImageManager::fillImage(const ImageHandle& handle, void* data, size_t size) void ImageManager::fillImage(const ImageHandle& handle, const void* data, size_t size)
{ {
const uint64_t id = handle.getId(); const uint64_t id = handle.getId();
...@@ -397,7 +387,7 @@ namespace vkcv { ...@@ -397,7 +387,7 @@ namespace vkcv {
const size_t max_size = std::min(size, image_size); const size_t max_size = std::min(size, image_size);
BufferHandle bufferHandle = m_bufferManager.createBuffer( BufferHandle bufferHandle = m_bufferManager.createBuffer(
BufferType::STAGING, max_size, BufferMemoryType::HOST_VISIBLE BufferType::STAGING, max_size, BufferMemoryType::HOST_VISIBLE, false
); );
m_bufferManager.fillBuffer(bufferHandle, data, max_size, 0); m_bufferManager.fillBuffer(bufferHandle, data, max_size, 0);
...@@ -504,9 +494,6 @@ namespace vkcv { ...@@ -504,9 +494,6 @@ namespace vkcv {
} }
void ImageManager::generateImageMipChainImmediate(const ImageHandle& handle) { void ImageManager::generateImageMipChainImmediate(const ImageHandle& handle) {
const auto& device = m_core->getContext().getDevice();
SubmitInfo submitInfo; SubmitInfo submitInfo;
submitInfo.queueType = QueueType::Graphics; submitInfo.queueType = QueueType::Graphics;
...@@ -628,15 +615,14 @@ namespace vkcv { ...@@ -628,15 +615,14 @@ namespace vkcv {
view = nullptr; view = nullptr;
} }
} }
if (image.m_memory) { const vma::Allocator& allocator = m_core->getContext().getAllocator();
device.freeMemory(image.m_memory);
image.m_memory = nullptr;
}
if (image.m_handle) { if (image.m_handle) {
device.destroyImage(image.m_handle); allocator.destroyImage(image.m_handle, image.m_allocation);
image.m_handle = nullptr; image.m_handle = nullptr;
image.m_allocation = nullptr;
} }
} }
...@@ -655,7 +641,6 @@ namespace vkcv { ...@@ -655,7 +641,6 @@ namespace vkcv {
uint32_t ImageManager::getImageMipCount(const ImageHandle& handle) const { uint32_t ImageManager::getImageMipCount(const ImageHandle& handle) const {
const uint64_t id = handle.getId(); const uint64_t id = handle.getId();
const bool isSwapchainFormat = handle.isSwapchainImage();
if (handle.isSwapchainImage()) { if (handle.isSwapchainImage()) {
return 1; return 1;
...@@ -673,11 +658,11 @@ namespace vkcv { ...@@ -673,11 +658,11 @@ namespace vkcv {
m_currentSwapchainInputImage = index; m_currentSwapchainInputImage = index;
} }
void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views, void ImageManager::setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views,
uint32_t width, uint32_t height, vk::Format format) { uint32_t width, uint32_t height, vk::Format format) {
// destroy old views // destroy old views
for (auto image : m_swapchainImages) { for (const auto& image : m_swapchainImages) {
for (const auto& view : image.m_viewPerMip) { for (const auto& view : image.m_viewPerMip) {
m_core->getContext().getDevice().destroyImageView(view); m_core->getContext().getDevice().destroyImageView(view);
} }
...@@ -685,8 +670,18 @@ namespace vkcv { ...@@ -685,8 +670,18 @@ namespace vkcv {
assert(images.size() == views.size()); assert(images.size() == views.size());
m_swapchainImages.clear(); m_swapchainImages.clear();
for (int i = 0; i < images.size(); i++) { for (size_t i = 0; i < images.size(); i++) {
m_swapchainImages.push_back(Image(images[i], nullptr, { views[i] }, width, height, 1, format, 1)); m_swapchainImages.push_back({
images[i],
nullptr,
{ views[i] },
width,
height,
1,
format,
1,
vk::ImageLayout::eUndefined
});
} }
} }
......
...@@ -6,12 +6,15 @@ ...@@ -6,12 +6,15 @@
*/ */
#include <vector> #include <vector>
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <vk_mem_alloc.hpp>
#include "vkcv/BufferManager.hpp" #include "vkcv/BufferManager.hpp"
#include "vkcv/Handles.hpp" #include "vkcv/Handles.hpp"
#include "vkcv/ImageConfig.hpp" #include "vkcv/ImageConfig.hpp"
namespace vkcv { namespace vkcv {
bool isDepthImageFormat(vk::Format format);
class ImageManager class ImageManager
{ {
...@@ -20,28 +23,16 @@ namespace vkcv { ...@@ -20,28 +23,16 @@ namespace vkcv {
struct Image struct Image
{ {
vk::Image m_handle; vk::Image m_handle;
vk::DeviceMemory m_memory; vma::Allocation m_allocation;
std::vector<vk::ImageView> m_viewPerMip; std::vector<vk::ImageView> m_viewPerMip;
uint32_t m_width = 0; uint32_t m_width;
uint32_t m_height = 0; uint32_t m_height;
uint32_t m_depth = 0; uint32_t m_depth;
vk::Format m_format; vk::Format m_format;
uint32_t m_layers = 1; uint32_t m_layers;
vk::ImageLayout m_layout = vk::ImageLayout::eUndefined; vk::ImageLayout m_layout;
private: private:
// struct is public so utility functions can access members, but only ImageManager can create Image
friend ImageManager; friend ImageManager;
Image(
vk::Image handle,
vk::DeviceMemory memory,
std::vector<vk::ImageView> views,
uint32_t width,
uint32_t height,
uint32_t depth,
vk::Format format,
uint32_t layers);
Image();
}; };
private: private:
...@@ -52,7 +43,7 @@ namespace vkcv { ...@@ -52,7 +43,7 @@ namespace vkcv {
std::vector<Image> m_swapchainImages; std::vector<Image> m_swapchainImages;
int m_currentSwapchainInputImage; int m_currentSwapchainInputImage;
ImageManager(BufferManager& bufferManager) noexcept; explicit ImageManager(BufferManager& bufferManager) noexcept;
/** /**
* Destroys and deallocates image represented by a given * Destroys and deallocates image represented by a given
...@@ -82,7 +73,8 @@ namespace vkcv { ...@@ -82,7 +73,8 @@ namespace vkcv {
bool supportColorAttachment, bool supportColorAttachment,
Multisampling msaa); Multisampling msaa);
ImageHandle createSwapchainImage(); [[nodiscard]]
ImageHandle createSwapchainImage() const;
[[nodiscard]] [[nodiscard]]
vk::Image getVulkanImage(const ImageHandle& handle) const; vk::Image getVulkanImage(const ImageHandle& handle) const;
...@@ -91,7 +83,7 @@ namespace vkcv { ...@@ -91,7 +83,7 @@ namespace vkcv {
vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle& handle) const; vk::DeviceMemory getVulkanDeviceMemory(const ImageHandle& handle) const;
[[nodiscard]] [[nodiscard]]
vk::ImageView getVulkanImageView(const ImageHandle& handle, const size_t mipLevel = 0) const; vk::ImageView getVulkanImageView(const ImageHandle& handle, size_t mipLevel = 0) const;
void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout); void switchImageLayoutImmediate(const ImageHandle& handle, vk::ImageLayout newLayout);
void recordImageLayoutTransition( void recordImageLayoutTransition(
...@@ -103,7 +95,7 @@ namespace vkcv { ...@@ -103,7 +95,7 @@ namespace vkcv {
const ImageHandle& handle, const ImageHandle& handle,
vk::CommandBuffer cmdBuffer); vk::CommandBuffer cmdBuffer);
void fillImage(const ImageHandle& handle, void* data, size_t size); void fillImage(const ImageHandle& handle, const void* data, size_t size);
void generateImageMipChainImmediate(const ImageHandle& handle); void generateImageMipChainImmediate(const ImageHandle& handle);
void recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, const ImageHandle& handle); void recordImageMipChainGenerationToCmdStream(const vkcv::CommandStreamHandle& cmdStream, const ImageHandle& handle);
void recordMSAAResolve(vk::CommandBuffer cmdBuffer, ImageHandle src, ImageHandle dst); void recordMSAAResolve(vk::CommandBuffer cmdBuffer, ImageHandle src, ImageHandle dst);
...@@ -124,8 +116,9 @@ namespace vkcv { ...@@ -124,8 +116,9 @@ namespace vkcv {
uint32_t getImageMipCount(const ImageHandle& handle) const; uint32_t getImageMipCount(const ImageHandle& handle) const;
void setCurrentSwapchainImageIndex(int index); void setCurrentSwapchainImageIndex(int index);
void setSwapchainImages(const std::vector<vk::Image>& images, std::vector<vk::ImageView> views,
uint32_t width, uint32_t height, vk::Format format); void setSwapchainImages(const std::vector<vk::Image>& images, const std::vector<vk::ImageView>& views,
uint32_t width, uint32_t height, vk::Format format);
}; };
} }
\ No newline at end of file
...@@ -44,95 +44,190 @@ namespace vkcv ...@@ -44,95 +44,190 @@ namespace vkcv
vk::PrimitiveTopology primitiveTopologyToVulkanPrimitiveTopology(const PrimitiveTopology topology) { vk::PrimitiveTopology primitiveTopologyToVulkanPrimitiveTopology(const PrimitiveTopology topology) {
switch (topology) { switch (topology) {
case(PrimitiveTopology::PointList): return vk::PrimitiveTopology::ePointList; case(PrimitiveTopology::PointList): return vk::PrimitiveTopology::ePointList;
case(PrimitiveTopology::LineList): return vk::PrimitiveTopology::eLineList; case(PrimitiveTopology::LineList): return vk::PrimitiveTopology::eLineList;
case(PrimitiveTopology::TriangleList): return vk::PrimitiveTopology::eTriangleList; case(PrimitiveTopology::TriangleList): return vk::PrimitiveTopology::eTriangleList;
default: std::cout << "Error: Unknown primitive topology type" << std::endl; return vk::PrimitiveTopology::eTriangleList; default: std::cout << "Error: Unknown primitive topology type" << std::endl; return vk::PrimitiveTopology::eTriangleList;
} }
} }
vk::CompareOp depthTestToVkCompareOp(DepthTest depthTest) { vk::CompareOp depthTestToVkCompareOp(DepthTest depthTest) {
switch (depthTest) { switch (depthTest) {
case(DepthTest::None): return vk::CompareOp::eAlways; case(DepthTest::None): return vk::CompareOp::eAlways;
case(DepthTest::Less): return vk::CompareOp::eLess; case(DepthTest::Less): return vk::CompareOp::eLess;
case(DepthTest::LessEqual): return vk::CompareOp::eLessOrEqual; case(DepthTest::LessEqual): return vk::CompareOp::eLessOrEqual;
case(DepthTest::Greater): return vk::CompareOp::eGreater; case(DepthTest::Greater): return vk::CompareOp::eGreater;
case(DepthTest::GreatherEqual): return vk::CompareOp::eGreaterOrEqual; case(DepthTest::GreatherEqual): return vk::CompareOp::eGreaterOrEqual;
case(DepthTest::Equal): return vk::CompareOp::eEqual; case(DepthTest::Equal): return vk::CompareOp::eEqual;
default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown depth test enum"); return vk::CompareOp::eAlways; default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown depth test enum"); return vk::CompareOp::eAlways;
} }
} }
vk::ShaderStageFlagBits shaderStageToVkShaderStage(vkcv::ShaderStage stage) {
switch (stage) {
case vkcv::ShaderStage::VERTEX: return vk::ShaderStageFlagBits::eVertex;
case vkcv::ShaderStage::FRAGMENT: return vk::ShaderStageFlagBits::eFragment;
case vkcv::ShaderStage::GEOMETRY: return vk::ShaderStageFlagBits::eGeometry;
case vkcv::ShaderStage::TESS_CONTROL: return vk::ShaderStageFlagBits::eTessellationControl;
case vkcv::ShaderStage::TESS_EVAL: return vk::ShaderStageFlagBits::eTessellationEvaluation;
case vkcv::ShaderStage::COMPUTE: return vk::ShaderStageFlagBits::eCompute;
case vkcv::ShaderStage::TASK: return vk::ShaderStageFlagBits::eTaskNV;
case vkcv::ShaderStage::MESH: return vk::ShaderStageFlagBits::eMeshNV;
default: vkcv_log(vkcv::LogLevel::ERROR, "Unknown shader stage"); return vk::ShaderStageFlagBits::eAll;
}
}
bool createPipelineShaderStageCreateInfo(
const vkcv::ShaderProgram& shaderProgram,
ShaderStage stage,
vk::Device device,
vk::PipelineShaderStageCreateInfo* outCreateInfo) {
assert(outCreateInfo);
std::vector<char> code = shaderProgram.getShader(stage).shaderCode;
vk::ShaderModuleCreateInfo vertexModuleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data()));
vk::ShaderModule shaderModule;
if (device.createShaderModule(&vertexModuleInfo, nullptr, &shaderModule) != vk::Result::eSuccess)
return false;
const static auto entryName = "main";
*outCreateInfo = vk::PipelineShaderStageCreateInfo(
{},
shaderStageToVkShaderStage(stage),
shaderModule,
entryName,
nullptr);
return true;
}
PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager) PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager)
{ {
const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle); const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle);
const bool existsTaskShader = config.m_ShaderProgram.existsShader(ShaderStage::TASK);
const bool existsMeshShader = config.m_ShaderProgram.existsShader(ShaderStage::MESH);
const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX); const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX);
const bool validGeometryStages = existsVertexShader || (existsTaskShader && existsMeshShader);
const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT); const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT);
if (!(existsVertexShader && existsFragmentShader)) if (!validGeometryStages)
{ {
vkcv_log(LogLevel::ERROR, "Requires vertex and fragment shader code"); vkcv_log(LogLevel::ERROR, "Requires vertex or task and mesh shader");
return PipelineHandle(); return PipelineHandle();
} }
if (!existsFragmentShader) {
// vertex shader stage vkcv_log(LogLevel::ERROR, "Requires fragment shader code");
std::vector<char> vertexCode = config.m_ShaderProgram.getShader(ShaderStage::VERTEX).shaderCode;
vk::ShaderModuleCreateInfo vertexModuleInfo({}, vertexCode.size(), reinterpret_cast<uint32_t*>(vertexCode.data()));
vk::ShaderModule vertexModule{};
if (m_Device.createShaderModule(&vertexModuleInfo, nullptr, &vertexModule) != vk::Result::eSuccess)
return PipelineHandle(); return PipelineHandle();
}
vk::PipelineShaderStageCreateInfo pipelineVertexShaderStageInfo( std::vector<vk::PipelineShaderStageCreateInfo> shaderStages;
{}, auto destroyShaderModules = [&shaderStages, this] {
vk::ShaderStageFlagBits::eVertex, for (auto stage : shaderStages) {
vertexModule, m_Device.destroyShaderModule(stage.module);
"main", }
nullptr shaderStages.clear();
); };
if (existsVertexShader) {
vk::PipelineShaderStageCreateInfo createInfo;
const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::VERTEX,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
}
if (existsTaskShader) {
vk::PipelineShaderStageCreateInfo createInfo;
const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::TASK,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
}
if (existsMeshShader) {
vk::PipelineShaderStageCreateInfo createInfo;
const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::MESH,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
}
// fragment shader stage // fragment shader stage
std::vector<char> fragCode = config.m_ShaderProgram.getShader(ShaderStage::FRAGMENT).shaderCode;
vk::ShaderModuleCreateInfo fragmentModuleInfo({}, fragCode.size(), reinterpret_cast<uint32_t*>(fragCode.data()));
vk::ShaderModule fragmentModule{};
if (m_Device.createShaderModule(&fragmentModuleInfo, nullptr, &fragmentModule) != vk::Result::eSuccess)
{ {
m_Device.destroy(vertexModule); vk::PipelineShaderStageCreateInfo createInfo;
return PipelineHandle(); const bool success = createPipelineShaderStageCreateInfo(
config.m_ShaderProgram,
vkcv::ShaderStage::FRAGMENT,
m_Device,
&createInfo);
if (success) {
shaderStages.push_back(createInfo);
}
else {
destroyShaderModules();
return PipelineHandle();
}
} }
vk::PipelineShaderStageCreateInfo pipelineFragmentShaderStageInfo(
{},
vk::ShaderStageFlagBits::eFragment,
fragmentModule,
"main",
nullptr
);
// vertex input state // vertex input state
// Fill up VertexInputBindingDescription and VertexInputAttributeDescription Containers // Fill up VertexInputBindingDescription and VertexInputAttributeDescription Containers
std::vector<vk::VertexInputAttributeDescription> vertexAttributeDescriptions; std::vector<vk::VertexInputAttributeDescription> vertexAttributeDescriptions;
std::vector<vk::VertexInputBindingDescription> vertexBindingDescriptions; std::vector<vk::VertexInputBindingDescription> vertexBindingDescriptions;
const VertexLayout &layout = config.m_VertexLayout; if (existsVertexShader) {
const VertexLayout& layout = config.m_VertexLayout;
// iterate over the layout's specified, mutually exclusive buffer bindings that make up a vertex buffer
for (const auto &vertexBinding : layout.vertexBindings) // iterate over the layout's specified, mutually exclusive buffer bindings that make up a vertex buffer
{ for (const auto& vertexBinding : layout.vertexBindings)
vertexBindingDescriptions.emplace_back(vertexBinding.bindingLocation, {
vertexBinding.stride, vertexBindingDescriptions.emplace_back(vertexBinding.bindingLocation,
vk::VertexInputRate::eVertex); vertexBinding.stride,
vk::VertexInputRate::eVertex);
// iterate over the bindings' specified, mutually exclusive vertex input attachments that make up a vertex
for(const auto &vertexAttachment: vertexBinding.vertexAttachments) // iterate over the bindings' specified, mutually exclusive vertex input attachments that make up a vertex
{ for (const auto& vertexAttachment : vertexBinding.vertexAttachments)
vertexAttributeDescriptions.emplace_back(vertexAttachment.inputLocation, {
vertexBinding.bindingLocation, vertexAttributeDescriptions.emplace_back(vertexAttachment.inputLocation,
vertexFormatToVulkanFormat(vertexAttachment.format), vertexBinding.bindingLocation,
vertexAttachment.offset % vertexBinding.stride); vertexFormatToVulkanFormat(vertexAttachment.format),
vertexAttachment.offset % vertexBinding.stride);
}
}
} }
}
// Handover Containers to PipelineVertexInputStateCreateIngo Struct // Handover Containers to PipelineVertexInputStateCreateIngo Struct
vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo( vk::PipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo(
...@@ -240,8 +335,7 @@ namespace vkcv ...@@ -240,8 +335,7 @@ namespace vkcv
vk::PipelineLayout vkPipelineLayout{}; vk::PipelineLayout vkPipelineLayout{};
if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess) if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess)
{ {
m_Device.destroy(vertexModule); destroyShaderModules();
m_Device.destroy(fragmentModule);
return PipelineHandle(); return PipelineHandle();
} }
...@@ -276,25 +370,28 @@ namespace vkcv ...@@ -276,25 +370,28 @@ namespace vkcv
dynamicStates.push_back(vk::DynamicState::eScissor); dynamicStates.push_back(vk::DynamicState::eScissor);
} }
vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo({}, vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo(
static_cast<uint32_t>(dynamicStates.size()), {},
dynamicStates.data()); static_cast<uint32_t>(dynamicStates.size()),
dynamicStates.data());
// graphics pipeline create
std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo }; const bool existsGeometryShader = config.m_ShaderProgram.existsShader(vkcv::ShaderStage::GEOMETRY);
if (existsGeometryShader) {
const char *geometryShaderName = "main"; // outside of if to make sure it stays in scope vk::PipelineShaderStageCreateInfo createInfo;
vk::ShaderModule geometryModule; const bool success = createPipelineShaderStageCreateInfo(
if (config.m_ShaderProgram.existsShader(ShaderStage::GEOMETRY)) { config.m_ShaderProgram,
const vkcv::Shader geometryShader = config.m_ShaderProgram.getShader(ShaderStage::GEOMETRY); vkcv::ShaderStage::GEOMETRY,
const auto& geometryCode = geometryShader.shaderCode; m_Device,
const vk::ShaderModuleCreateInfo geometryModuleInfo({}, geometryCode.size(), reinterpret_cast<const uint32_t*>(geometryCode.data())); &createInfo);
if (m_Device.createShaderModule(&geometryModuleInfo, nullptr, &geometryModule) != vk::Result::eSuccess) {
return PipelineHandle(); if (success) {
} shaderStages.push_back(createInfo);
vk::PipelineShaderStageCreateInfo geometryStage({}, vk::ShaderStageFlagBits::eGeometry, geometryModule, geometryShaderName); }
shaderStages.push_back(geometryStage); else {
} destroyShaderModules();
return PipelineHandle();
}
}
const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo( const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo(
{}, {},
...@@ -319,20 +416,11 @@ namespace vkcv ...@@ -319,20 +416,11 @@ namespace vkcv
vk::Pipeline vkPipeline{}; vk::Pipeline vkPipeline{};
if (m_Device.createGraphicsPipelines(nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &vkPipeline) != vk::Result::eSuccess) if (m_Device.createGraphicsPipelines(nullptr, 1, &graphicsPipelineCreateInfo, nullptr, &vkPipeline) != vk::Result::eSuccess)
{ {
m_Device.destroy(vertexModule); destroyShaderModules();
m_Device.destroy(fragmentModule);
if (geometryModule) {
m_Device.destroy(geometryModule);
}
m_Device.destroy();
return PipelineHandle(); return PipelineHandle();
} }
m_Device.destroy(vertexModule); destroyShaderModules();
m_Device.destroy(fragmentModule);
if (geometryModule) {
m_Device.destroy(geometryModule);
}
const uint64_t id = m_Pipelines.size(); const uint64_t id = m_Pipelines.size();
m_Pipelines.push_back({ vkPipeline, vkPipelineLayout, config }); m_Pipelines.push_back({ vkPipeline, vkPipelineLayout, config });
...@@ -457,4 +545,4 @@ namespace vkcv ...@@ -457,4 +545,4 @@ namespace vkcv
vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data())); vk::ShaderModuleCreateInfo moduleInfo({}, code.size(), reinterpret_cast<uint32_t*>(code.data()));
return m_Device.createShaderModule(&moduleInfo, nullptr, &module); return m_Device.createShaderModule(&moduleInfo, nullptr, &module);
} }
} }
\ No newline at end of file
...@@ -27,8 +27,8 @@ namespace vkcv { ...@@ -27,8 +27,8 @@ namespace vkcv {
* @throws std::runtime_error If the requested queues from @p queueFlags are not creatable due to insufficient availability. * @throws std::runtime_error If the requested queues from @p queueFlags are not creatable due to insufficient availability.
*/ */
void QueueManager::queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice, void QueueManager::queueCreateInfosQueueHandles(vk::PhysicalDevice &physicalDevice,
std::vector<float> &queuePriorities, const std::vector<float> &queuePriorities,
std::vector<vk::QueueFlagBits> &queueFlags, const std::vector<vk::QueueFlagBits> &queueFlags,
std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos, std::vector<vk::DeviceQueueCreateInfo> &queueCreateInfos,
std::vector<std::pair<int, int>> &queuePairsGraphics, std::vector<std::pair<int, int>> &queuePairsGraphics,
std::vector<std::pair<int, int>> &queuePairsCompute, std::vector<std::pair<int, int>> &queuePairsCompute,
...@@ -51,7 +51,7 @@ namespace vkcv { ...@@ -51,7 +51,7 @@ namespace vkcv {
} }
//resort flags with heighest priority before allocating the queues //resort flags with heighest priority before allocating the queues
std::vector<vk::QueueFlagBits> newFlags; std::vector<vk::QueueFlagBits> newFlags;
for(int i = 0; i < prios.size(); i++) { for(size_t i = 0; i < prios.size(); i++) {
auto minElem = std::min_element(prios.begin(), prios.end()); auto minElem = std::min_element(prios.begin(), prios.end());
int index = minElem - prios.begin(); int index = minElem - prios.begin();
newFlags.push_back(queueFlags[index]); newFlags.push_back(queueFlags[index]);
...@@ -79,7 +79,7 @@ namespace vkcv { ...@@ -79,7 +79,7 @@ namespace vkcv {
switch (qFlag) { switch (qFlag) {
case vk::QueueFlagBits::eGraphics: case vk::QueueFlagBits::eGraphics:
found = false; found = false;
for (int i = 0; i < queueFamilyStatus.size() && !found; i++) { for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) {
if (queueFamilyStatus[i][0] > 0) { if (queueFamilyStatus[i][0] > 0) {
queuePairsGraphics.push_back(std::pair(i, initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0])); queuePairsGraphics.push_back(std::pair(i, initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]));
queueFamilyStatus[i][0]--; queueFamilyStatus[i][0]--;
...@@ -89,7 +89,7 @@ namespace vkcv { ...@@ -89,7 +89,7 @@ namespace vkcv {
} }
} }
if (!found) { if (!found) {
for (int i = 0; i < queueFamilyStatus.size() && !found; i++) { for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) {
if (initialQueueFamilyStatus[i][0] > 0) { if (initialQueueFamilyStatus[i][0] > 0) {
queuePairsGraphics.push_back(std::pair(i, 0)); queuePairsGraphics.push_back(std::pair(i, 0));
found = true; found = true;
...@@ -101,7 +101,7 @@ namespace vkcv { ...@@ -101,7 +101,7 @@ namespace vkcv {
break; break;
case vk::QueueFlagBits::eCompute: case vk::QueueFlagBits::eCompute:
found = false; found = false;
for (int i = 0; i < queueFamilyStatus.size() && !found; i++) { for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) {
if (queueFamilyStatus[i][1] > 0) { if (queueFamilyStatus[i][1] > 0) {
queuePairsCompute.push_back(std::pair(i, initialQueueFamilyStatus[i][1] - queueFamilyStatus[i][1])); queuePairsCompute.push_back(std::pair(i, initialQueueFamilyStatus[i][1] - queueFamilyStatus[i][1]));
queueFamilyStatus[i][0]--; queueFamilyStatus[i][0]--;
...@@ -111,7 +111,7 @@ namespace vkcv { ...@@ -111,7 +111,7 @@ namespace vkcv {
} }
} }
if (!found) { if (!found) {
for (int i = 0; i < queueFamilyStatus.size() && !found; i++) { for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) {
if (initialQueueFamilyStatus[i][1] > 0) { if (initialQueueFamilyStatus[i][1] > 0) {
queuePairsCompute.push_back(std::pair(i, 0)); queuePairsCompute.push_back(std::pair(i, 0));
found = true; found = true;
...@@ -123,7 +123,7 @@ namespace vkcv { ...@@ -123,7 +123,7 @@ namespace vkcv {
break; break;
case vk::QueueFlagBits::eTransfer: case vk::QueueFlagBits::eTransfer:
found = false; found = false;
for (int i = 0; i < queueFamilyStatus.size() && !found; i++) { for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) {
if (queueFamilyStatus[i][2] > 0) { if (queueFamilyStatus[i][2] > 0) {
queuePairsTransfer.push_back(std::pair(i, initialQueueFamilyStatus[i][2] - queueFamilyStatus[i][2])); queuePairsTransfer.push_back(std::pair(i, initialQueueFamilyStatus[i][2] - queueFamilyStatus[i][2]));
queueFamilyStatus[i][0]--; queueFamilyStatus[i][0]--;
...@@ -133,7 +133,7 @@ namespace vkcv { ...@@ -133,7 +133,7 @@ namespace vkcv {
} }
} }
if (!found) { if (!found) {
for (int i = 0; i < queueFamilyStatus.size() && !found; i++) { for (size_t i = 0; i < queueFamilyStatus.size() && !found; i++) {
if (initialQueueFamilyStatus[i][2] > 0) { if (initialQueueFamilyStatus[i][2] > 0) {
queuePairsTransfer.push_back(std::pair(i, 0)); queuePairsTransfer.push_back(std::pair(i, 0));
found = true; found = true;
...@@ -149,7 +149,7 @@ namespace vkcv { ...@@ -149,7 +149,7 @@ namespace vkcv {
} }
// create all requested queues // create all requested queues
for (int i = 0; i < qFamilyProperties.size(); i++) { for (size_t i = 0; i < qFamilyProperties.size(); i++) {
uint32_t create = std::abs(initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]); uint32_t create = std::abs(initialQueueFamilyStatus[i][0] - queueFamilyStatus[i][0]);
if (create > 0) { if (create > 0) {
vk::DeviceQueueCreateInfo qCreateInfo( vk::DeviceQueueCreateInfo qCreateInfo(
......
...@@ -17,7 +17,8 @@ namespace vkcv { ...@@ -17,7 +17,8 @@ namespace vkcv {
SamplerHandle SamplerManager::createSampler(SamplerFilterType magFilter, SamplerHandle SamplerManager::createSampler(SamplerFilterType magFilter,
SamplerFilterType minFilter, SamplerFilterType minFilter,
SamplerMipmapMode mipmapMode, SamplerMipmapMode mipmapMode,
SamplerAddressMode addressMode) { SamplerAddressMode addressMode,
float mipLodBias) {
vk::Filter vkMagFilter; vk::Filter vkMagFilter;
vk::Filter vkMinFilter; vk::Filter vkMinFilter;
vk::SamplerMipmapMode vkMipmapMode; vk::SamplerMipmapMode vkMipmapMode;
...@@ -81,13 +82,13 @@ namespace vkcv { ...@@ -81,13 +82,13 @@ namespace vkcv {
vkAddressMode, vkAddressMode,
vkAddressMode, vkAddressMode,
vkAddressMode, vkAddressMode,
0.0f, mipLodBias,
false, false,
16.0f, 16.0f,
false, false,
vk::CompareOp::eAlways, vk::CompareOp::eAlways,
0.0f, -1000.0f,
16.0f, 1000.0f,
vk::BorderColor::eIntOpaqueBlack, vk::BorderColor::eIntOpaqueBlack,
false false
); );
......
...@@ -32,7 +32,8 @@ namespace vkcv { ...@@ -32,7 +32,8 @@ namespace vkcv {
SamplerHandle createSampler(SamplerFilterType magFilter, SamplerHandle createSampler(SamplerFilterType magFilter,
SamplerFilterType minFilter, SamplerFilterType minFilter,
SamplerMipmapMode mipmapMode, SamplerMipmapMode mipmapMode,
SamplerAddressMode addressMode); SamplerAddressMode addressMode,
float mipLodBias);
[[nodiscard]] [[nodiscard]]
vk::Sampler getVulkanSampler(const SamplerHandle& handle) const; vk::Sampler getVulkanSampler(const SamplerHandle& handle) const;
......
...@@ -100,18 +100,14 @@ namespace vkcv ...@@ -100,18 +100,14 @@ namespace vkcv
* @return available Format * @return available Format
*/ */
vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { vk::SurfaceFormatKHR chooseSurfaceFormat(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
uint32_t formatCount; std::vector<vk::SurfaceFormatKHR> availableFormats = physicalDevice.getSurfaceFormatsKHR(surface);
physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, nullptr);
std::vector<vk::SurfaceFormatKHR> availableFormats(formatCount);
if (physicalDevice.getSurfaceFormatsKHR(surface, &formatCount, &availableFormats[0]) != vk::Result::eSuccess) {
throw std::runtime_error("Failed to get surface formats");
}
for (const auto& availableFormat : availableFormats) { for (const auto& availableFormat : availableFormats) {
if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { if (availableFormat.format == vk::Format::eB8G8R8A8Unorm && availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) {
return availableFormat; return availableFormat;
} }
} }
return availableFormats[0]; return availableFormats[0];
} }
...@@ -122,12 +118,7 @@ namespace vkcv ...@@ -122,12 +118,7 @@ namespace vkcv
* @return available PresentationMode * @return available PresentationMode
*/ */
vk::PresentModeKHR choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { vk::PresentModeKHR choosePresentMode(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
uint32_t modeCount; std::vector<vk::PresentModeKHR> availablePresentModes = physicalDevice.getSurfacePresentModesKHR(surface);
physicalDevice.getSurfacePresentModesKHR( surface, &modeCount, nullptr );
std::vector<vk::PresentModeKHR> availablePresentModes(modeCount);
if (physicalDevice.getSurfacePresentModesKHR(surface, &modeCount, &availablePresentModes[0]) != vk::Result::eSuccess) {
throw std::runtime_error("Failed to get presentation modes");
}
for (const auto& availablePresentMode : availablePresentModes) { for (const auto& availablePresentMode : availablePresentModes) {
if (availablePresentMode == vk::PresentModeKHR::eMailbox) { if (availablePresentMode == vk::PresentModeKHR::eMailbox) {
...@@ -145,12 +136,11 @@ namespace vkcv ...@@ -145,12 +136,11 @@ namespace vkcv
* @return available ImageCount * @return available ImageCount
*/ */
uint32_t chooseImageCount(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) { uint32_t chooseImageCount(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface) {
vk::SurfaceCapabilitiesKHR surfaceCapabilities; vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface);
if(physicalDevice.getSurfaceCapabilitiesKHR(surface, &surfaceCapabilities) != vk::Result::eSuccess){
throw std::runtime_error("cannot get surface capabilities. There is an issue with the surface."); // minImageCount should always be at least 2; set to 3 for triple buffering
} uint32_t imageCount = surfaceCapabilities.minImageCount + 1;
uint32_t imageCount = surfaceCapabilities.minImageCount + 1; // minImageCount should always be at least 2; set to 3 for triple buffering
// check if requested image count is supported // check if requested image count is supported
if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) { if (surfaceCapabilities.maxImageCount > 0 && imageCount > surfaceCapabilities.maxImageCount) {
imageCount = surfaceCapabilities.maxImageCount; imageCount = surfaceCapabilities.maxImageCount;
...@@ -215,8 +205,9 @@ namespace vkcv ...@@ -215,8 +205,9 @@ namespace vkcv
} }
void Swapchain::updateSwapchain(const Context &context, const Window &window) { void Swapchain::updateSwapchain(const Context &context, const Window &window) {
if (!m_RecreationRequired.exchange(false)) if (!m_RecreationRequired.exchange(false)) {
return; return;
}
vk::SwapchainKHR oldSwapchain = m_Swapchain; vk::SwapchainKHR oldSwapchain = m_Swapchain;
vk::Extent2D extent2D = chooseExtent(context.getPhysicalDevice(), m_Surface.handle, window); vk::Extent2D extent2D = chooseExtent(context.getPhysicalDevice(), m_Surface.handle, window);
......
...@@ -4,7 +4,10 @@ ...@@ -4,7 +4,10 @@
* @brief Window class to handle a basic rendering surface and input * @brief Window class to handle a basic rendering surface and input
*/ */
#include <thread>
#include <vector>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "vkcv/Window.hpp" #include "vkcv/Window.hpp"
namespace vkcv { namespace vkcv {
...@@ -78,12 +81,17 @@ namespace vkcv { ...@@ -78,12 +81,17 @@ namespace vkcv {
window->e_key.unlock(); window->e_key.unlock();
window->e_char.unlock(); window->e_char.unlock();
window->e_gamepad.unlock(); window->e_gamepad.unlock();
} }
glfwPollEvents();
glfwPollEvents(); // fixes subtle mouse stutter, which is made visible by motion blur
// FIXME: proper solution
for (int gamepadIndex = GLFW_JOYSTICK_1; gamepadIndex <= GLFW_JOYSTICK_LAST; gamepadIndex++) { // probably caused by main thread locking events before glfw callbacks are executed
if (glfwJoystickPresent(gamepadIndex)) { std::this_thread::sleep_for(std::chrono::milliseconds(1));
for (int gamepadIndex = GLFW_JOYSTICK_1; gamepadIndex <= GLFW_JOYSTICK_LAST; gamepadIndex++) {
if (glfwJoystickPresent(gamepadIndex)) {
onGamepadEvent(gamepadIndex); onGamepadEvent(gamepadIndex);
} }
} }
...@@ -150,11 +158,15 @@ namespace vkcv { ...@@ -150,11 +158,15 @@ namespace vkcv {
} }
void Window::onGamepadEvent(int gamepadIndex) { void Window::onGamepadEvent(int gamepadIndex) {
int activeWindowIndex = std::find_if(s_Windows.begin(), size_t activeWindowIndex = std::find_if(
s_Windows.end(), s_Windows.begin(),
[](GLFWwindow* window){return glfwGetWindowAttrib(window, GLFW_FOCUSED);}) s_Windows.end(),
- s_Windows.begin(); [](GLFWwindow* window){return glfwGetWindowAttrib(window, GLFW_FOCUSED);}
activeWindowIndex *= (activeWindowIndex < s_Windows.size()); // fixes index getting out of bounds (e.g. if there is no focused window) ) - s_Windows.begin();
// fixes index getting out of bounds (e.g. if there is no focused window)
activeWindowIndex *= (activeWindowIndex < s_Windows.size());
auto window = static_cast<Window *>(glfwGetWindowUserPointer(s_Windows[activeWindowIndex])); auto window = static_cast<Window *>(glfwGetWindowUserPointer(s_Windows[activeWindowIndex]));
if (window != nullptr) { if (window != nullptr) {
......