Skip to content

Commit

Permalink
Merge pull request #17
Browse files Browse the repository at this point in the history
* Enable Vulkan-Hpp's standard library module usage when VKU_USE_STD_MO…

* Added convenience method DescriptorSet::getWriteOne. (Calling getWrit…

* Added Image::getMipViewCreateInfos (method that creates the vector of…

* WIP: fix CI.

* WIP: fix CI.
  • Loading branch information
stripe2933 authored Aug 23, 2024
1 parent 4710a0b commit d0544f3
Show file tree
Hide file tree
Showing 7 changed files with 355 additions and 3 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ target_link_libraries(vku PUBLIC
$<$<BOOL:${VKU_USE_SHADERC}>:Vulkan::shaderc_combined>
)
target_compile_definitions(vku PUBLIC
$<$<BOOL:${VKU_USE_STD_MODULE}>:VKU_USE_STD_MODULE>
$<$<BOOL:${VKU_USE_STD_MODULE}>:VKU_USE_STD_MODULE VULKAN_HPP_ENABLE_STD_MODULE>
$<$<BOOL:${VKU_USE_SHADERC}>:VKU_USE_SHADERC>
$<$<BOOL:${MSVC}>:VULKAN_HPP_NO_SMART_HANDLE VK_NO_PROTOTYPES> # See https://github.com/KhronosGroup/Vulkan-Hpp/blob/main/README.md#c20-named-module for the details.
$<$<PLATFORM_ID:Darwin>:VK_ENABLE_BETA_EXTENSIONS> # For VK_KHR_portability_subset availability.
Expand Down
21 changes: 21 additions & 0 deletions interface/descriptors/DescriptorSet.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@ namespace vku {
return attachInfo(VULKAN_HPP_NAMESPACE::WriteDescriptorSet { *this, Binding, 0, {}, get<Binding>(Layout::bindingTypes) }, descriptorInfos);
}

/**
* Convenience method for calling <tt>getWrite<Binding></tt> with single lifetime-bounded descriptor info object.
* @tparam Binding Binding index to get the write descriptor.
* @param descriptorInfo Descriptor info to write. This is either <tt>vk::DescriptorBufferInfo</tt>,
* <tt>vk::DescriptorImageInfo</tt> or <tt>vk::BufferView</tt>, based on your descriptor type predefined by <tt>DescriptorSetLayout</tt>.
* @return <tt>vk::WriteDescriptorSet</tt> with given info.
* @example
* @code
* struct Layout : vku::DescriptorSetLayout<vk::DescriptorType::eStorageBuffer> { ... } layout;
*
* auto [descriptorSet] = vku::allocateDescriptorSets(*device, *descriptorPool, std::tie(layout));
* device.updateDescriptorSets({
* descriptorSet.getWriteOne<0>({ buffer, 0, vk::WholeSize }), // argument type infered as vk::DescriptorBufferInfo at the compile time.
* }, {});
* @endcode
*/
template <std::uint32_t Binding>
[[nodiscard]] auto getWriteOne(const WriteDescriptorInfo_t<get<Binding>(Layout::bindingTypes)> &descriptorInfo [[clang::lifetimebound]]) const noexcept -> VULKAN_HPP_NAMESPACE::WriteDescriptorSet {
return getWrite<Binding>(descriptorInfo);
}

template <concepts::derived_from_value_specialization_of<DescriptorSetLayout>... Layouts>
friend auto allocateDescriptorSets(VULKAN_HPP_NAMESPACE::Device, VULKAN_HPP_NAMESPACE::DescriptorPool, std::tuple<const Layouts&...>) -> std::tuple<DescriptorSet<Layouts>...>;

Expand Down
28 changes: 27 additions & 1 deletion interface/images/Image.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ module;
#include <cassert>
#ifndef VKU_USE_STD_MODULE
#include <cstdint>
#include <bit>
#include <algorithm>
#include <bit>
#include <ranges>
#include <vector>
#endif

#include <vulkan/vulkan_hpp_macros.hpp>
Expand Down Expand Up @@ -70,6 +72,30 @@ namespace vku {
*/
[[nodiscard]] auto getViewCreateInfo(const VULKAN_HPP_NAMESPACE::ImageSubresourceRange &subresourceRange, VULKAN_HPP_NAMESPACE::ImageViewType type = VULKAN_HPP_NAMESPACE::ImageViewType::e2D) const noexcept -> VULKAN_HPP_NAMESPACE::ImageViewCreateInfo;

/**
* Get <tt>vk::ImageViewCreateInfo</tt> structs for all mip levels with the specified \p type. Aspect flags are
* inferred from the image format.
* @param type Image view type (default=<tt>vk::ImageViewType::e2D<tt>).
* @return Vector of <tt>vk::ImageViewCreateInfo</tt> structs for all mip levels.
* @note
* See <tt>inferAspectFlags(vk::Format)</tt> for aspect flags inference rule.<br>
* It internally calls <tt>inferAspectFlags(vk::Format)</tt> and <tt>getViewCreateInfo(const vk::ImageSubresourceRange&, vk::ImageViewType)</tt>.
*/
[[nodiscard]] auto getMipViewCreateInfos(VULKAN_HPP_NAMESPACE::ImageViewType type = VULKAN_HPP_NAMESPACE::ImageViewType::e2D) const NOEXCEPT_IF_RELEASE -> std::vector<VULKAN_HPP_NAMESPACE::ImageViewCreateInfo> {
return std::views::iota(0U, mipLevels)
| std::views::transform([&, aspectFlags = inferAspectFlags(format)](std::uint32_t level) {
return VULKAN_HPP_NAMESPACE::ImageViewCreateInfo {
{},
image,
type,
format,
{},
{ aspectFlags, level, 1, 0, VULKAN_HPP_NAMESPACE::RemainingArrayLayers }
};
})
| std::ranges::to<std::vector>();
}

/**
* Get the extent of the specified mip level.
* @param mipLevel Mip level, starts from zero, which must be less than <tt>maxMipLevels(extent)</tt>.
Expand Down
7 changes: 7 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@ add_executable(execute_hierarchical_commands execute_hierarchical_commands.cpp)
target_link_libraries(execute_hierarchical_commands PRIVATE vku::vku)
add_test(NAME execute_hierarchical_commands COMMAND execute_hierarchical_commands)

add_executable(get_mip_view_create_infos get_mip_view_create_infos.cpp)
target_link_libraries(get_mip_view_create_infos PRIVATE vku::vku)
target_compile_definitions(get_mip_view_create_infos PRIVATE
COMPILED_SHADER_DIR="${CMAKE_CURRENT_SOURCE_DIR}/shaders/get_mip_view_create_infos"
)
add_test(NAME get_mip_view_create_infos COMMAND get_mip_view_create_infos)

add_subdirectory(triangle)
add_subdirectory(msaa-triangle)
4 changes: 3 additions & 1 deletion test/execute_hierarchical_commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
#include <cstdint>
#include <algorithm>
#include <array>
#include <format>
#include <iterator>
#include <ranges>
#include <span>
#include <stdexcept>
#include <tuple>
#include <vector>
#ifdef _MSC_VER
#include <format>
#endif
#endif

#include <vulkan/vulkan_hpp_macros.hpp>
Expand Down
258 changes: 258 additions & 0 deletions test/get_mip_view_create_infos.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
#include <cassert>
#ifndef VKU_USE_STD_MODULE
#include <cstdint>
#include <algorithm>
#include <array>
#include <functional>
#include <ranges>
#include <span>
#include <tuple>
#include <vector>
#ifdef _MSC_VER
#include <format>
#endif
#endif

#include <vulkan/vulkan_hpp_macros.hpp>

#ifdef VKU_USE_STD_MODULE
import std;
#endif
import vku;

#if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
#endif

struct QueueFamilies {
std::uint32_t compute;

explicit QueueFamilies(vk::PhysicalDevice physicalDevice)
: compute { vku::getComputeQueueFamily(physicalDevice.getQueueFamilyProperties()).value() } { }
};

struct Queues {
vk::Queue compute;

Queues(vk::Device device, const QueueFamilies &queueFamilies)
: compute { device.getQueue(queueFamilies.compute, 0) } { }

[[nodiscard]] static auto getCreateInfos(vk::PhysicalDevice, const QueueFamilies &queueFamilies) noexcept
#ifdef _MSC_VER
-> vku::RefHolder<std::array<vk::DeviceQueueCreateInfo, 1>, std::array<float, 1>>
#endif
{
return vku::RefHolder {
[&](std::span<const float> priorities) {
return std::array {
vk::DeviceQueueCreateInfo {
{},
queueFamilies.compute,
priorities,
},
};
},
std::array { 1.f },
};
}
};

struct Gpu : vku::Gpu<QueueFamilies, Queues> {
explicit Gpu(const vk::raii::Instance &instance [[clang::lifetimebound]])
: vku::Gpu<QueueFamilies, Queues> { instance, vku::Gpu<QueueFamilies, Queues>::Config {
.verbose = true,
.deviceExtensions = {
vk::EXTDescriptorIndexingExtensionName,
#if __APPLE__
vk::KHRPortabilitySubsetExtensionName,
#endif
},
.devicePNexts = std::tuple {
vk::PhysicalDeviceDescriptorIndexingFeatures{}
.setRuntimeDescriptorArray(true),
},
.apiVersion = vk::makeApiVersion(0, 1, 1, 0),
} } { }
};

struct ColorCheckComputer {
struct DescriptorSetLayout : vku::DescriptorSetLayout<vk::DescriptorType::eSampledImage, vk::DescriptorType::eStorageBuffer> {
explicit DescriptorSetLayout(const vk::raii::Device &device [[clang::lifetimebound]], std::uint32_t mipLevels)
: vku::DescriptorSetLayout<vk::DescriptorType::eSampledImage, vk::DescriptorType::eStorageBuffer> {
device, vk::DescriptorSetLayoutCreateInfo {
{},
vku::unsafeProxy({
vk::DescriptorSetLayoutBinding { 0, vk::DescriptorType::eSampledImage, mipLevels, vk::ShaderStageFlagBits::eCompute },
vk::DescriptorSetLayoutBinding { 1, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute },
}),
}
} { }
};

struct PushConstant {
std::array<float, 4> color;
std::uint32_t mipLevel;
};

DescriptorSetLayout descriptorSetLayout;
vk::raii::PipelineLayout pipelineLayout;
vk::raii::Pipeline pipeline;

explicit ColorCheckComputer(const vk::raii::Device &device [[clang::lifetimebound]], std::uint32_t mipLevels)
: descriptorSetLayout { device, mipLevels }
, pipelineLayout { device, vk::PipelineLayoutCreateInfo {
{},
*descriptorSetLayout,
vku::unsafeProxy(vk::PushConstantRange {
vk::ShaderStageFlagBits::eCompute,
0, sizeof(PushConstant),
}),
} }
, pipeline { device, nullptr, vk::ComputePipelineCreateInfo {
{},
createPipelineStages(device, vku::Shader { COMPILED_SHADER_DIR "/color_check.comp.spv", vk::ShaderStageFlagBits::eCompute }).get()[0],
*pipelineLayout,
} } { }
};

int main() {
#if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1
VULKAN_HPP_DEFAULT_DISPATCHER.init();
#endif

const vk::raii::Context context;
const vk::raii::Instance instance { context, vk::InstanceCreateInfo {
#if __APPLE__
vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR,
#else
{},
#endif
vku::unsafeAddress(vk::ApplicationInfo {
"vku_test_get_mip_view_create_infos", 0,
{}, 0,
vk::makeApiVersion(0, 1, 1, 0),
}),
{},
#if __APPLE__
vku::unsafeProxy({
vk::KHRPortabilityEnumerationExtensionName,
}),
#endif
} };
const Gpu gpu { instance };

constexpr std::array colors {
vk::ClearColorValue { 0.f, 0.f, 0.f, 1.f }, // Black
vk::ClearColorValue { 1.f, 0.f, 0.f, 1.f }, // Red
vk::ClearColorValue { 0.f, 1.f, 0.f, 1.f }, // Green
vk::ClearColorValue { 0.f, 0.f, 1.f, 1.f }, // Blue
vk::ClearColorValue { 1.f, 1.f, 0.f, 1.f }, // Yellow
vk::ClearColorValue { 0.f, 1.f, 1.f, 1.f }, // Cyan
vk::ClearColorValue { 1.f, 0.f, 1.f, 1.f }, // Magenta
vk::ClearColorValue { 1.f, 1.f, 1.f, 1.f }, // White
};

const vku::AllocatedImage image { gpu.allocator, vk::ImageCreateInfo {
{},
vk::ImageType::e2D,
vk::Format::eR8G8B8A8Unorm,
vk::Extent3D { 128, 128, 1 },
colors.size(), 1,
vk::SampleCountFlagBits::e1,
vk::ImageTiling::eOptimal,
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
} };
const std::vector imageViews
// --------------------
// MAIN CODE TO TEST!
// --------------------
= image.getMipViewCreateInfos()
| std::views::transform([&](const vk::ImageViewCreateInfo &createInfo) {
return vk::raii::ImageView { gpu.device, createInfo };
})
| std::ranges::to<std::vector>();

const vku::MappedBuffer buffer {
gpu.allocator,
std::from_range, std::vector(image.mipLevels, vk::True),
vk::BufferUsageFlagBits::eStorageBuffer,
};

const ColorCheckComputer colorCheckComputer { gpu.device, image.mipLevels };

const vk::raii::DescriptorPool descriptorPool { gpu.device, vk::DescriptorPoolCreateInfo {
{},
1,
vku::unsafeProxy({
vk::DescriptorPoolSize { vk::DescriptorType::eSampledImage, image.mipLevels },
vk::DescriptorPoolSize { vk::DescriptorType::eStorageBuffer, 1 },
}),
} };
const auto [descriptorSet] = vku::allocateDescriptorSets(*gpu.device, *descriptorPool, std::tie(colorCheckComputer.descriptorSetLayout));
gpu.device.updateDescriptorSets({
descriptorSet.getWrite<0>(vku::unsafeProxy(imageViews | std::views::transform([](const auto &imageView) {
return vk::DescriptorImageInfo { {}, *imageView, vk::ImageLayout::eShaderReadOnlyOptimal };
}) | std::ranges::to<std::vector>())),
descriptorSet.getWriteOne<1>({ buffer, 0, vk::WholeSize }),
}, {});

const vk::raii::CommandPool computeCommandPool { gpu.device, vk::CommandPoolCreateInfo {
{},
gpu.queueFamilies.compute,
} };

vku::executeSingleCommand(*gpu.device, *computeCommandPool, gpu.queues.compute, [&](vk::CommandBuffer cb) {
// Change image layout to TransferDstOptimal.
cb.pipelineBarrier(
vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer,
{}, {}, {},
vk::ImageMemoryBarrier {
{}, vk::AccessFlagBits::eTransferWrite,
{}, vk::ImageLayout::eTransferDstOptimal,
vk::QueueFamilyIgnored, vk::QueueFamilyIgnored,
image, vku::fullSubresourceRange(),
});

// Fill image mipmaps with colors for each level, respectively.
for (std::uint32_t level = 0; const vk::ClearColorValue &color : colors) {
cb.clearColorImage(
image, vk::ImageLayout::eTransferDstOptimal,
color, vk::ImageSubresourceRange { vk::ImageAspectFlagBits::eColor, level, 1, 0, 1 });

++level;
}

// Change image layout to ShaderReadOnlyOptimal after clearing.
cb.pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eComputeShader,
{}, {}, {},
vk::ImageMemoryBarrier {
vk::AccessFlagBits::eTransferWrite, vk::AccessFlagBits::eShaderRead,
vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal,
vk::QueueFamilyIgnored, vk::QueueFamilyIgnored,
image, vku::fullSubresourceRange(),
});

// Execute ColorCheckComputer for every mip levels.
cb.bindPipeline(vk::PipelineBindPoint::eCompute, *colorCheckComputer.pipeline);
cb.bindDescriptorSets(vk::PipelineBindPoint::eCompute, *colorCheckComputer.pipelineLayout, 0, descriptorSet, {});
for (std::uint32_t level = 0; const vk::ClearColorValue &color : colors) {
cb.pushConstants<ColorCheckComputer::PushConstant>(*colorCheckComputer.pipelineLayout, vk::ShaderStageFlagBits::eCompute, 0, ColorCheckComputer::PushConstant {
color.float32,
level,
});

const vk::Extent2D mipExtent = image.mipExtent(level);
constexpr auto divCeil = [](std::uint32_t num, std::uint32_t denom) noexcept {
return num / denom + (num % denom != 0);
};
cb.dispatch(divCeil(mipExtent.width, 16U), divCeil(mipExtent.height, 16U), 1);

++level;
}
});
gpu.queues.compute.waitIdle();

// Check if all booleans in the buffer remain vk::True.
assert(std::ranges::all_of(buffer.asRange<const vk::Bool32>(), std::identity{}) && "Color mismatch!");
}
Loading

0 comments on commit d0544f3

Please sign in to comment.