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

Target

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