blob: 045b28abbd1da85d28b50088bd9d9c4a39226941 [file] [log] [blame]
/*
* Copyright (c) 2015-2016, 2020-2025 The Khronos Group Inc.
* Copyright (c) 2015-2016, 2020-2025 Valve Corporation
* Copyright (c) 2015-2016, 2020-2025 LunarG, Inc.
* Copyright (C) 2025 Arm Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cassert>
#include <vector>
#include <optional>
#include "containers/span.h"
#include "containers/limits.h"
#include "generated/vk_function_pointers.h"
#include "utils/cast_utils.h"
#include "test_common.h"
namespace vkt {
class PhysicalDevice;
class Device;
class Queue;
class DeviceMemory;
class Fence;
class Semaphore;
class Event;
class QueryPool;
class Buffer;
class BufferView;
class Image;
class ImageView;
class DepthStencilView;
class PipelineCache;
class Pipeline;
class PipelineDelta;
class Sampler;
class DescriptorSetLayout;
class PipelineLayout;
class DescriptorSetPool;
class DescriptorSet;
class CommandBuffer;
class CommandPool;
class Swapchain;
class IndirectCommandsLayout;
class IndirectExecutionSet;
class Tensor;
std::vector<VkLayerProperties> GetGlobalLayers();
std::vector<VkExtensionProperties> GetGlobalExtensions();
std::vector<VkExtensionProperties> GetGlobalExtensions(const char *pLayerName);
namespace internal {
template <typename T>
class Handle {
public:
const T &handle() const noexcept { return handle_; }
T &handle() noexcept { return handle_; }
bool initialized() const noexcept { return (handle_ != T{}); }
operator T() const noexcept { return handle(); }
void SetName(VkDevice device, VkObjectType object_type, const char *name) {
VkDebugUtilsObjectNameInfoEXT name_info = vku::InitStructHelper();
name_info.objectType = object_type;
name_info.objectHandle = CastToUint64(handle_);
name_info.pObjectName = name;
vk::SetDebugUtilsObjectNameEXT(device, &name_info);
}
protected:
typedef T handle_type;
explicit Handle() noexcept : handle_{} {}
explicit Handle(T handle) noexcept : handle_(handle) {}
// handles are non-copyable
Handle(const Handle &) = delete;
Handle &operator=(const Handle &) = delete;
// handles can be moved out
Handle(Handle &&src) noexcept : handle_{src.handle_} { src.handle_ = {}; }
Handle &operator=(Handle &&src) noexcept {
handle_ = src.handle_;
src.handle_ = {};
return *this;
}
void init(T handle) noexcept {
assert(!initialized());
handle_ = handle;
}
protected:
T handle_;
};
template <typename T>
class NonDispHandle : public Handle<T> {
protected:
explicit NonDispHandle() noexcept : Handle<T>(), dev_handle_(VK_NULL_HANDLE) {}
explicit NonDispHandle(VkDevice dev, T handle) noexcept : Handle<T>(handle), dev_handle_(dev) {}
NonDispHandle(NonDispHandle &&src) noexcept : Handle<T>(std::move(src)) {
dev_handle_ = src.dev_handle_;
src.dev_handle_ = VK_NULL_HANDLE;
}
NonDispHandle &operator=(NonDispHandle &&src) noexcept {
Handle<T>::operator=(std::move(src));
dev_handle_ = src.dev_handle_;
src.dev_handle_ = VK_NULL_HANDLE;
return *this;
}
const VkDevice &device() const noexcept { return dev_handle_; }
void init(VkDevice dev, T handle) noexcept {
assert(!Handle<T>::initialized() && dev_handle_ == VK_NULL_HANDLE);
Handle<T>::init(handle);
dev_handle_ = dev;
}
void SetDevice(VkDevice device) { dev_handle_ = device; }
void Destroy() noexcept { dev_handle_ = VK_NULL_HANDLE; }
public:
void SetName(VkObjectType object_type, const char *name) { Handle<T>::SetName(dev_handle_, object_type, name); }
private:
VkDevice dev_handle_;
};
} // namespace internal
//
class Instance {
public:
Instance(const VkInstanceCreateInfo &info) { Init(info); }
void Init(const VkInstanceCreateInfo &info);
~Instance() noexcept { Destroy(); }
void Destroy() noexcept;
VkInstance Handle() const { return handle_; }
Instance(Instance &&src) noexcept : handle_{src.handle_} { src.handle_ = {}; }
Instance &operator=(Instance &&src) noexcept {
handle_ = src.handle_;
src.handle_ = {};
return *this;
}
private:
VkInstance handle_{};
};
class PhysicalDevice : public internal::Handle<VkPhysicalDevice> {
public:
explicit PhysicalDevice(VkPhysicalDevice phy)
: Handle(phy),
properties_(Properties()),
limits_(properties_.limits),
memory_properties_(MemoryProperties()),
queue_properties_(QueueProperties()) {}
void SetName(VkDevice device, const char *name) {
Handle<VkPhysicalDevice>::SetName(device, VK_OBJECT_TYPE_PHYSICAL_DEVICE, name);
}
VkPhysicalDeviceFeatures Features() const;
bool SetMemoryType(const uint32_t type_bits, VkMemoryAllocateInfo *info, const VkMemoryPropertyFlags properties,
const VkMemoryPropertyFlags forbid = 0, const VkMemoryHeapFlags heapFlags = 0) const;
// vkEnumerateDeviceExtensionProperties()
std::vector<VkExtensionProperties> Extensions(const char *pLayerName = nullptr) const;
// vkEnumerateLayers()
std::vector<VkLayerProperties> Layers() const;
const VkPhysicalDeviceProperties properties_;
const VkPhysicalDeviceLimits limits_;
const VkPhysicalDeviceMemoryProperties memory_properties_;
const std::vector<VkQueueFamilyProperties> queue_properties_;
private:
VkPhysicalDeviceProperties Properties() const;
std::vector<VkQueueFamilyProperties> QueueProperties() const;
VkPhysicalDeviceMemoryProperties MemoryProperties() const;
};
class QueueCreateInfoArray {
private:
std::vector<VkDeviceQueueCreateInfo> queue_info_;
std::vector<std::vector<float>> queue_priorities_;
public:
QueueCreateInfoArray(const std::vector<VkQueueFamilyProperties> &queue_props, bool all_queue_count = false);
size_t Size() const { return queue_info_.size(); }
const VkDeviceQueueCreateInfo *Data() const { return queue_info_.data(); }
};
class Device : public internal::Handle<VkDevice> {
public:
explicit Device(VkPhysicalDevice phy, const VkDeviceCreateInfo &info) : physical_device_(phy) { Init(info); }
explicit Device(VkPhysicalDevice phy, std::vector<const char *> &extension_names, VkPhysicalDeviceFeatures *features = nullptr,
void *create_device_pnext = nullptr, bool all_queue_count = false)
: physical_device_(phy) {
Init(extension_names, features, create_device_pnext, all_queue_count);
}
~Device() noexcept;
void Destroy() noexcept;
// vkCreateDevice()
void Init(const VkDeviceCreateInfo &info);
void Init(std::vector<const char *> &extensions, VkPhysicalDeviceFeatures *features = nullptr,
void *create_device_pnext = nullptr, bool all_queue_count = false); // all queues, all extensions, etc
void SetName(const char *name) { Handle<VkDevice>::SetName(handle_, VK_OBJECT_TYPE_DEVICE, name); }
const PhysicalDevice &Physical() const { return physical_device_; }
std::vector<const char *> GetEnabledExtensions() { return enabled_extensions_; }
bool IsEnabledExtension(const char *extension) const;
const VkPhysicalDeviceFeatures &GetFeatures() const { return features_; }
const std::vector<Queue *> &QueuesWithGraphicsCapability() const { return queues_[GRAPHICS]; }
const std::vector<Queue *> &QueuesWithComputeCapability() const { return queues_[COMPUTE]; }
const std::vector<Queue *> &QueuesWithTransferCapability() const { return queues_[TRANSFER]; }
const std::vector<Queue *> &QueuesWithSparseCapability() const { return queues_[SPARSE]; }
const std::vector<Queue *> &QueuesWithDataGraphCapability() const { return queues_[DATA_GRAPH]; }
using QueueFamilyQueues = std::vector<std::unique_ptr<Queue>>;
const QueueFamilyQueues &QueuesFromFamily(uint32_t queue_family) const;
// Queue family that has "with" capabilities and optionally without "without" capabilities.
std::optional<uint32_t> QueueFamily(VkQueueFlags with, VkQueueFlags without = 0) const;
// Queue family that does not have "without" capabilities
std::optional<uint32_t> QueueFamilyWithoutCapabilities(VkQueueFlags without) const;
Queue *QueueWithoutCapabilities(VkQueueFlags without) const;
// Dedicated compute queue family: has compute but no graphics
std::optional<uint32_t> ComputeOnlyQueueFamily() const;
Queue *ComputeOnlyQueue() const;
// Dedicated transfer queue family: has tranfer but no graphics/compute
std::optional<uint32_t> TransferOnlyQueueFamily() const;
Queue *TransferOnlyQueue() const;
// Compute or transfer
std::optional<uint32_t> NonGraphicsQueueFamily() const;
Queue *NonGraphicsQueue() const;
uint32_t graphics_queue_node_index_ = vvl::kNoIndex32;
const PhysicalDevice physical_device_;
struct Format {
VkFormat format;
VkImageTiling tiling;
VkFlags features;
};
VkFormatFeatureFlags2 FormatFeaturesLinear(VkFormat format) const;
VkFormatFeatureFlags2 FormatFeaturesOptimal(VkFormat format) const;
VkFormatFeatureFlags2 FormatFeaturesBuffer(VkFormat format) const;
// vkDeviceWaitIdle()
void Wait() const;
// vkWaitForFences()
VkResult Wait(const std::vector<const Fence *> &fences, bool wait_all, uint64_t timeout);
VkResult Wait(const Fence &fence) { return Wait(std::vector<const Fence *>(1, &fence), true, (uint64_t)-1); }
static VkWriteDescriptorSet WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, uint32_t count, const VkDescriptorImageInfo *image_info);
static VkWriteDescriptorSet WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, uint32_t count,
const VkDescriptorBufferInfo *buffer_info);
static VkWriteDescriptorSet WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, uint32_t count, const VkBufferView *buffer_views);
static VkWriteDescriptorSet WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, const std::vector<VkDescriptorImageInfo> &image_info);
static VkWriteDescriptorSet WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, const std::vector<VkDescriptorBufferInfo> &buffer_info);
static VkWriteDescriptorSet WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, const std::vector<VkBufferView> &buffer_views);
private:
enum QueueCapabilityIndex {
GRAPHICS = 0,
COMPUTE = 1,
TRANSFER = 2,
SPARSE = 3,
VIDEO_DECODE = 4,
VIDEO_ENCODE = 5,
DATA_GRAPH = 6,
QUEUE_CAPABILITY_COUNT = 7,
};
void InitQueues(const VkDeviceCreateInfo &info);
std::vector<const char *> enabled_extensions_;
VkPhysicalDeviceFeatures features_;
std::vector<QueueFamilyQueues> queue_families_;
std::vector<Queue *> queues_[QUEUE_CAPABILITY_COUNT];
};
class DeviceMemory : public internal::NonDispHandle<VkDeviceMemory> {
public:
DeviceMemory() = default;
DeviceMemory(const Device &dev, const VkMemoryAllocateInfo &info) { Init(dev, info); }
~DeviceMemory() noexcept;
void Destroy() noexcept;
DeviceMemory &operator=(DeviceMemory &&) = default;
// vkAllocateMemory()
// Fails the test when allocation is unsuccessful
void Init(const Device &dev, const VkMemoryAllocateInfo &info);
// Does not fail the test when allocation is unsuccessful and instead returns error code
VkResult TryInit(const Device &dev, const VkMemoryAllocateInfo &info);
void SetName(const char *name) { NonDispHandle<VkDeviceMemory>::SetName(VK_OBJECT_TYPE_DEVICE_MEMORY, name); }
// vkMapMemory()
const void *Map(VkFlags flags) const;
void *Map(VkFlags flags);
const void *Map() const { return Map(0); }
void *Map() { return Map(0); }
// vkUnmapMemory()
void Unmap() const;
static VkMemoryAllocateInfo GetResourceAllocInfo(const Device &dev, const VkMemoryRequirements &reqs,
VkMemoryPropertyFlags mem_props, void *alloc_info_pnext = nullptr);
private:
VkMemoryAllocateInfo memory_allocate_info_{};
};
class Fence : public internal::NonDispHandle<VkFence> {
public:
Fence() = default;
Fence(const Device &dev, const VkFenceCreateFlags flags = 0) { Init(dev, flags); }
Fence(const Device &dev, const VkFenceCreateInfo &info) { Init(dev, info); }
Fence(Fence &&rhs) noexcept : NonDispHandle(std::move(rhs)) {}
Fence &operator=(Fence &&) noexcept;
~Fence() noexcept;
void Destroy() noexcept;
// vkCreateFence()
void Init(const Device &dev, const VkFenceCreateInfo &info);
void Init(const Device &dev, const VkFenceCreateFlags flags = 0);
void SetName(const char *name) { NonDispHandle<VkFence>::SetName(VK_OBJECT_TYPE_FENCE, name); }
// vkGetFenceStatus()
VkResult GetStatus() const { return vk::GetFenceStatus(device(), handle()); }
VkResult Wait(uint64_t timeout) const;
VkResult Reset() const;
#ifdef VK_USE_PLATFORM_WIN32_KHR
VkResult ExportHandle(HANDLE &win32_handle, VkExternalFenceHandleTypeFlagBits handle_type);
VkResult ImportHandle(HANDLE win32_handle, VkExternalFenceHandleTypeFlagBits handle_type, VkFenceImportFlags flags = 0);
#endif
VkResult ExportHandle(int &fd_handle, VkExternalFenceHandleTypeFlagBits handle_type);
VkResult ImportHandle(int fd_handle, VkExternalFenceHandleTypeFlagBits handle_type, VkFenceImportFlags flags = 0);
};
inline const Fence no_fence;
class Semaphore : public internal::NonDispHandle<VkSemaphore> {
public:
Semaphore() = default;
Semaphore(const Device &dev, VkSemaphoreType type = VK_SEMAPHORE_TYPE_BINARY, uint64_t initial_value = 0);
Semaphore(const Device &dev, const VkSemaphoreCreateInfo &info) { Init(dev, info); }
Semaphore(Semaphore &&rhs) noexcept : NonDispHandle(std::move(rhs)) {}
Semaphore &operator=(Semaphore &&) noexcept;
~Semaphore() noexcept;
void Destroy() noexcept;
// vkCreateSemaphore()
void Init(const Device &dev, const VkSemaphoreCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkSemaphore>::SetName(VK_OBJECT_TYPE_SEMAPHORE, name); }
VkResult Wait(uint64_t value, uint64_t timeout);
VkResult WaitKHR(uint64_t value, uint64_t timeout);
VkResult Signal(uint64_t value);
VkResult SignalKHR(uint64_t value);
uint64_t GetCounterValue(bool use_khr = false) const;
#ifdef VK_USE_PLATFORM_WIN32_KHR
VkResult ExportHandle(HANDLE &win32_handle, VkExternalSemaphoreHandleTypeFlagBits handle_type);
VkResult ImportHandle(HANDLE win32_handle, VkExternalSemaphoreHandleTypeFlagBits handle_type, VkSemaphoreImportFlags flags = 0);
#endif
VkResult ExportHandle(int &fd_handle, VkExternalSemaphoreHandleTypeFlagBits handle_type);
VkResult ImportHandle(int fd_handle, VkExternalSemaphoreHandleTypeFlagBits handle_type, VkSemaphoreImportFlags flags = 0);
};
inline const Semaphore no_semaphore; // equivalent to vkt::Semaphore{}
class Event : public internal::NonDispHandle<VkEvent> {
public:
Event() = default;
Event(const Device &dev) { Init(dev, CreateInfo(0)); }
Event(const Device &dev, const VkEventCreateInfo &info) { Init(dev, info); }
~Event() noexcept;
void Destroy() noexcept;
// vkCreateEvent()
void Init(const Device &dev, const VkEventCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkEvent>::SetName(VK_OBJECT_TYPE_EVENT, name); }
// vkGetEventStatus()
// vkSetEvent()
// vkResetEvent()
VkResult GetStatus() const { return vk::GetEventStatus(device(), handle()); }
void Set();
void CmdSet(const CommandBuffer &cmd, VkPipelineStageFlags stage_mask);
void CmdReset(const CommandBuffer &cmd, VkPipelineStageFlags stage_mask);
void CmdWait(const CommandBuffer &cmd, VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
const std::vector<VkMemoryBarrier> &memory_barriers, const std::vector<VkBufferMemoryBarrier> &buffer_barriers,
const std::vector<VkImageMemoryBarrier> &image_barriers);
void Reset();
static VkEventCreateInfo CreateInfo(VkFlags flags);
};
struct Wait {
const Semaphore &semaphore;
VkPipelineStageFlags2 stage_mask;
explicit Wait(const Semaphore &semaphore, VkPipelineStageFlags2 stage_mask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)
: semaphore(semaphore), stage_mask(stage_mask) {}
};
struct Signal {
const Semaphore &semaphore;
VkPipelineStageFlags2 stage_mask;
explicit Signal(const Semaphore &semaphore, VkPipelineStageFlags2 stage_mask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)
: semaphore(semaphore), stage_mask(stage_mask) {}
};
struct TimelineWait {
const Semaphore &semaphore;
uint64_t value;
VkPipelineStageFlags2 stage_mask;
explicit TimelineWait(const Semaphore &semaphore, uint64_t value,
VkPipelineStageFlags2 stage_mask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)
: semaphore(semaphore), value(value), stage_mask(stage_mask) {}
};
struct TimelineSignal {
const Semaphore &semaphore;
uint64_t value;
VkPipelineStageFlags2 stage_mask;
explicit TimelineSignal(const Semaphore &semaphore, uint64_t value,
VkPipelineStageFlags2 stage_mask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT)
: semaphore(semaphore), value(value), stage_mask(stage_mask) {}
};
class Queue : public internal::Handle<VkQueue> {
public:
explicit Queue(VkQueue queue, uint32_t index) : Handle(queue), family_index(index) {}
void SetName(const Device &device, const char *name) { Handle<VkQueue>::SetName(device, VK_OBJECT_TYPE_QUEUE, name); }
// vkQueueSubmit()
VkResult Submit(const CommandBuffer &cmd, const Fence &fence = no_fence);
VkResult Submit(const std::vector<VkCommandBuffer> &cmds, const Fence &fence = no_fence);
VkResult Submit(const CommandBuffer &cmd, const Wait &wait, const Fence &fence = no_fence);
VkResult Submit(const CommandBuffer &cmd, const Signal &signal, const Fence &fence = no_fence);
VkResult Submit(const CommandBuffer &cmd, const Wait &wait, const Signal &signal, const Fence &fence = no_fence);
VkResult Submit(const CommandBuffer &cmd, const TimelineWait &wait, const Fence &fence = no_fence);
VkResult Submit(const CommandBuffer &cmd, const TimelineSignal &signal, const Fence &fence = no_fence);
VkResult Submit(const CommandBuffer &cmd, const TimelineWait &wait, const TimelineSignal &signal,
const Fence &fence = no_fence);
// vkQueueSubmit2()
VkResult Submit2(const CommandBuffer &cmd, const Fence &fence = no_fence, bool use_khr = false);
VkResult Submit2(const std::vector<VkCommandBuffer> &cmds, const Fence &fence = no_fence, bool use_khr = false);
VkResult Submit2(const CommandBuffer &cmd, const Wait &wait, const Fence &fence = no_fence, bool use_khr = false);
VkResult Submit2(const CommandBuffer &cmd, const Signal &signal, const Fence &fence = no_fence, bool use_khr = false);
VkResult Submit2(const CommandBuffer &cmd, const Wait &wait, const Signal &signal, const Fence &fence = no_fence,
bool use_khr = false);
VkResult Submit2(const CommandBuffer &cmd, const TimelineWait &wait, const Fence &fence = no_fence, bool use_khr = false);
VkResult Submit2(const CommandBuffer &cmd, const TimelineSignal &signal, const Fence &fence = no_fence, bool use_khr = false);
VkResult Submit2(const CommandBuffer &cmd, const TimelineWait &wait, const TimelineSignal &signal,
const Fence &fence = no_fence, bool use_khr = false);
VkResult Submit2(const CommandBuffer &cmd, const Wait &wait, const TimelineSignal &signal, const Fence &fence = no_fence);
VkResult Submit2(const CommandBuffer &cmd, const TimelineWait &wait, const Signal &signal, const Fence &fence = no_fence);
// vkQueuePresentKHR()
VkResult Present(const Swapchain &swapchain, uint32_t image_index, const Semaphore &wait_semaphore,
void *present_info_pnext = nullptr);
// vkQueueWaitIdle()
VkResult Wait();
// Common combo for most GPU-AV test
void SubmitAndWait(const CommandBuffer &cmd) {
Submit(cmd);
Wait();
}
const uint32_t family_index;
};
class QueryPool : public internal::NonDispHandle<VkQueryPool> {
public:
QueryPool() = default;
QueryPool(const Device &dev, const VkQueryPoolCreateInfo &info) { Init(dev, info); }
QueryPool(const Device &dev, VkQueryType query_type, uint32_t query_count) {
VkQueryPoolCreateInfo info = CreateInfo(query_type, query_count);
Init(dev, info);
}
~QueryPool() noexcept;
void Destroy() noexcept;
// vkCreateQueryPool()
void Init(const Device &dev, const VkQueryPoolCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkQueryPool>::SetName(VK_OBJECT_TYPE_QUERY_POOL, name); }
// vkGetQueryPoolResults()
VkResult Results(uint32_t first, uint32_t count, size_t size, void *data, size_t stride);
static VkQueryPoolCreateInfo CreateInfo(VkQueryType type, uint32_t slot_count, VkQueryPoolCreateFlags create_flags = 0);
};
struct NoMemT {};
static constexpr NoMemT no_mem{};
struct DeviceAddressT {};
static constexpr DeviceAddressT device_address{};
struct SetLayoutT {};
static constexpr SetLayoutT set_layout{};
class Buffer : public internal::NonDispHandle<VkBuffer> {
public:
explicit Buffer() : NonDispHandle(), create_info_(vku::InitStruct<decltype(create_info_)>()) {}
explicit Buffer(const Device &dev, const VkBufferCreateInfo &info, VkMemoryPropertyFlags mem_props = 0,
void *alloc_info_pnext = nullptr) {
Init(dev, info, mem_props, alloc_info_pnext);
}
explicit Buffer(const Device &dev, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags mem_props = 0,
void *alloc_info_pnext = nullptr) {
Init(dev, size, usage, mem_props, alloc_info_pnext);
}
explicit Buffer(const Device &dev, const VkBufferCreateInfo &info, NoMemT) { InitNoMemory(dev, info); }
// Various spots need a host visible buffer they can call GetBufferDeviceAddress on
explicit Buffer(const Device &dev, VkDeviceSize size, VkBufferUsageFlags usage, DeviceAddressT) {
usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; // always add
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
Init(dev, CreateInfo(size, usage), VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&allocate_flag_info);
}
explicit Buffer(const Device& dev, VkDeviceSize size, VkBufferUsageFlags2CreateInfo usage_ci, DeviceAddressT) {
usage_ci.usage |= VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT;
VkMemoryAllocateFlagsInfo allocate_flag_info = vku::InitStructHelper();
allocate_flag_info.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
Init(dev, CreateInfo(size, 0, {}, &usage_ci), VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
&allocate_flag_info);
}
explicit Buffer(const Device &dev, VkBufferUsageFlags usage, const void *data, size_t data_size,
const vvl::span<uint32_t> &queue_families = {}) {
InitHostVisibleWithData(dev, usage, data, data_size, queue_families);
}
Buffer(Buffer &&rhs) noexcept;
Buffer &operator=(Buffer &&rhs) noexcept;
~Buffer() noexcept;
void Destroy() noexcept;
// vkCreateBuffer()
void Init(const Device &dev, const VkBufferCreateInfo &info, VkMemoryPropertyFlags mem_props = 0,
void *alloc_info_pnext = nullptr);
void Init(const Device &dev, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags mem_props = 0,
void *alloc_info_pnext = nullptr, const vvl::span<uint32_t> &queue_families = {}) {
Init(dev, CreateInfo(size, usage, queue_families), mem_props, alloc_info_pnext);
}
void InitHostVisibleWithData(const Device &dev, VkBufferUsageFlags usage, const void *data, size_t data_size,
const vvl::span<uint32_t> &queue_families = {});
void InitNoMemory(const Device &dev, const VkBufferCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkBuffer>::SetName(VK_OBJECT_TYPE_BUFFER, name); }
// get the internal memory
const DeviceMemory &Memory() const { return internal_mem_; }
DeviceMemory &Memory() { return internal_mem_; }
// vkGetObjectMemoryRequirements()
VkMemoryRequirements MemoryRequirements() const;
// Allocate and bind memory
// The assumption that this object was created in no_mem configuration
void AllocateAndBindMemory(const Device &dev, VkMemoryPropertyFlags mem_props = 0, void *alloc_info_pnext = nullptr);
// Bind to existing memory object
void BindMemory(const DeviceMemory &mem, VkDeviceSize mem_offset);
const VkBufferCreateInfo &CreateInfo() const { return create_info_; }
static VkBufferCreateInfo CreateInfo(VkDeviceSize size, VkFlags usage, const vvl::span<uint32_t> &queue_families = {},
void *create_info_pnext = nullptr);
VkBufferMemoryBarrier BufferMemoryBarrier(VkFlags output_mask, VkFlags input_mask, VkDeviceSize offset,
VkDeviceSize size) const {
VkBufferMemoryBarrier barrier = vku::InitStructHelper();
barrier.buffer = handle();
barrier.srcAccessMask = output_mask;
barrier.dstAccessMask = input_mask;
barrier.offset = offset;
barrier.size = size;
if (create_info_.sharingMode == VK_SHARING_MODE_CONCURRENT) {
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
}
return barrier;
}
VkBufferMemoryBarrier2 BufferMemoryBarrier(VkPipelineStageFlags2KHR src_stage, VkPipelineStageFlags2KHR dst_stage,
VkAccessFlags2KHR src_access, VkAccessFlags2KHR dst_access, VkDeviceSize offset,
VkDeviceSize size) const {
VkBufferMemoryBarrier2 barrier = vku::InitStructHelper();
barrier.buffer = handle();
barrier.srcStageMask = src_stage;
barrier.dstStageMask = dst_stage;
barrier.srcAccessMask = src_access;
barrier.dstAccessMask = dst_access;
barrier.offset = offset;
barrier.size = size;
if (create_info_.sharingMode == VK_SHARING_MODE_CONCURRENT) {
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
}
return barrier;
}
[[nodiscard]] VkDeviceAddress Address() const;
private:
VkBufferCreateInfo create_info_;
DeviceMemory internal_mem_;
};
class BufferView : public internal::NonDispHandle<VkBufferView> {
public:
BufferView() = default;
BufferView(const Device &dev, const VkBufferViewCreateInfo &info) { Init(dev, info); }
BufferView(const Device &dev, VkBuffer buffer, VkFormat format, VkDeviceSize offset = 0, VkDeviceSize range = VK_WHOLE_SIZE) {
VkBufferViewCreateInfo buffer_view_ci = CreateInfo(buffer, format, offset, range);
Init(dev, buffer_view_ci);
}
~BufferView() noexcept;
void Destroy() noexcept;
// vkCreateBufferView()
void Init(const Device &dev, const VkBufferViewCreateInfo &info);
static VkBufferViewCreateInfo CreateInfo(VkBuffer buffer, VkFormat format, VkDeviceSize offset = 0,
VkDeviceSize range = VK_WHOLE_SIZE);
void SetName(const char *name) { NonDispHandle<VkBufferView>::SetName(VK_OBJECT_TYPE_BUFFER_VIEW, name); }
};
inline VkBufferViewCreateInfo BufferView::CreateInfo(VkBuffer buffer, VkFormat format, VkDeviceSize offset, VkDeviceSize range) {
VkBufferViewCreateInfo info = vku::InitStructHelper();
info.flags = VkFlags(0);
info.buffer = buffer;
info.format = format;
info.offset = offset;
info.range = range;
return info;
}
class Image : public internal::NonDispHandle<VkImage> {
public:
explicit Image() : NonDispHandle() {}
explicit Image(const Device &dev, const VkImageCreateInfo &info, VkMemoryPropertyFlags mem_props = 0,
void *alloc_info_pnext = nullptr);
explicit Image(const Device &dev, uint32_t width, uint32_t height, VkFormat format, VkImageUsageFlags usage);
explicit Image(const Device &dev, const VkImageCreateInfo &info, NoMemT);
explicit Image(const Device &dev, const VkImageCreateInfo &info, SetLayoutT);
Image(Image &&rhs) noexcept;
Image &operator=(Image &&rhs) noexcept;
~Image() noexcept;
void Destroy() noexcept;
void Init(const Device &dev, const VkImageCreateInfo &info, VkMemoryPropertyFlags mem_props = 0,
void *alloc_info_pnext = nullptr);
void Init(const Device &dev, uint32_t width, uint32_t height, uint32_t mip_levels, VkFormat format, VkImageUsageFlags usage);
void InitNoMemory(const Device &dev, const VkImageCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkImage>::SetName(VK_OBJECT_TYPE_IMAGE, name); }
static VkImageCreateInfo ImageCreateInfo2D(uint32_t width, uint32_t height, uint32_t mip_levels, uint32_t layers,
VkFormat format, VkImageUsageFlags usage,
VkImageTiling requested_tiling = VK_IMAGE_TILING_OPTIMAL,
const vvl::span<uint32_t> &queue_families = {});
static bool IsCompatible(const Device &dev, VkImageUsageFlags usages, VkFormatFeatureFlags2 features);
// get the internal memory
const DeviceMemory &Memory() const { return internal_mem_; }
DeviceMemory &Memory() { return internal_mem_; }
// vkGetObjectMemoryRequirements()
VkMemoryRequirements MemoryRequirements() const;
// Allocate and bind memory
// The assumption that this object was created in no_mem configuration
void AllocateAndBindMemory(const Device &dev, VkMemoryPropertyFlags mem_props = 0, void *alloc_info_pnext = nullptr);
// Bind to existing memory object
void BindMemory(const DeviceMemory &mem, VkDeviceSize mem_offset);
uint32_t Width() const { return create_info_.extent.width; }
uint32_t Height() const { return create_info_.extent.height; }
VkFormat Format() const { return create_info_.format; }
VkImageUsageFlags Usage() const { return create_info_.usage; }
VkImageMemoryBarrier ImageMemoryBarrier(VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout,
VkImageLayout new_layout, const VkImageSubresourceRange &range) const {
VkImageMemoryBarrier barrier = vku::InitStructHelper();
barrier.srcAccessMask = src_access;
barrier.dstAccessMask = dst_access;
barrier.oldLayout = old_layout;
barrier.newLayout = new_layout;
barrier.image = handle();
barrier.subresourceRange = range;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
return barrier;
}
void ImageMemoryBarrier(CommandBuffer &cmd, VkAccessFlags src_access, VkAccessFlags dst_access, VkImageLayout old_layout,
VkImageLayout new_layout, VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
const VkImageCreateInfo &CreateInfo() const { return create_info_; }
VkImageSubresourceRange SubresourceRange(VkImageAspectFlags aspect_mask) {
return VkImageSubresourceRange{aspect_mask, 0, create_info_.mipLevels, 0, create_info_.arrayLayers};
}
static VkImageAspectFlags AspectMask(VkFormat format);
// Performs image layout transition by specifying old layout as VK_IMAGE_LAYOUT_UNDEFINED (more precisely
// VkImageCreateInfo::initialLayout).
// Can be used for initial layout transition or when the previous layout is not important for testing purposes.
void SetLayout(CommandBuffer &cmd_buf, VkImageLayout image_layout);
// This overload does queue submit and waits for layout transition to finish.
void SetLayout(VkImageLayout image_layout);
// Performs layout transition from old to new layout.
void TransitionLayout(CommandBuffer &cmd_buf, VkImageLayout old_layout, VkImageLayout new_layout);
// This overload does queue submit and waits for layout transition to finish.
void TransitionLayout(VkImageLayout old_layout, VkImageLayout new_layout);
VkImageViewCreateInfo BasicViewCreatInfo(VkImageAspectFlags aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT) const;
ImageView CreateView(VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT, void *pNext = nullptr) const;
ImageView CreateView(VkImageViewType type, uint32_t baseMipLevel = 0, uint32_t levelCount = VK_REMAINING_MIP_LEVELS,
uint32_t baseArrayLayer = 0, uint32_t layerCount = VK_REMAINING_ARRAY_LAYERS,
VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT) const;
private:
// We need this to do ImageView and SetLayout actions
const Device *device_ = nullptr;
VkImageCreateInfo create_info_;
DeviceMemory internal_mem_;
};
class ImageView : public internal::NonDispHandle<VkImageView> {
public:
explicit ImageView() = default;
explicit ImageView(const Device &dev, const VkImageViewCreateInfo &info) { Init(dev, info); }
ImageView(ImageView &&rhs) noexcept : NonDispHandle(std::move(rhs)) {}
ImageView &operator=(ImageView &&src) noexcept {
this->~ImageView();
this->NonDispHandle::operator=(std::move(src));
return *this;
}
~ImageView() noexcept;
void Destroy() noexcept;
// vkCreateImageView()
void Init(const Device &dev, const VkImageViewCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkImageView>::SetName(VK_OBJECT_TYPE_IMAGE_VIEW, name); }
};
class AccelerationStructureNV : public internal::NonDispHandle<VkAccelerationStructureNV> {
public:
explicit AccelerationStructureNV(const Device &dev, const VkAccelerationStructureCreateInfoNV &info, bool init_memory = true) {
Init(dev, info, init_memory);
}
~AccelerationStructureNV() noexcept;
void Destroy() noexcept;
// vkCreateAccelerationStructureNV
void Init(const Device &dev, const VkAccelerationStructureCreateInfoNV &info, bool init_memory = true);
void SetName(const char *name) {
NonDispHandle<VkAccelerationStructureNV>::SetName(VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV, name);
}
// vkGetAccelerationStructureMemoryRequirementsNV()
VkMemoryRequirements2 MemoryRequirements() const;
VkMemoryRequirements2 BuildScratchMemoryRequirements() const;
uint64_t OpaqueHandle() const { return opaque_handle_; }
const VkAccelerationStructureInfoNV &Info() const { return info_; }
[[nodiscard]] Buffer CreateScratchBuffer(const Device &device, VkBufferCreateInfo *pCreateInfo = nullptr,
bool buffer_device_address = false) const;
private:
VkAccelerationStructureInfoNV info_;
DeviceMemory memory_;
uint64_t opaque_handle_;
};
class ShaderModule : public internal::NonDispHandle<VkShaderModule> {
public:
ShaderModule() = default;
ShaderModule(const Device &dev, const VkShaderModuleCreateInfo &info) { Init(dev, info); }
ShaderModule(ShaderModule &&rhs) noexcept : NonDispHandle(std::move(rhs)) {}
ShaderModule &operator=(ShaderModule &&rhs) noexcept;
~ShaderModule() noexcept;
void Destroy() noexcept;
// vkCreateShaderModule()
void Init(const Device &dev, const VkShaderModuleCreateInfo &info);
VkResult InitTry(const Device &dev, const VkShaderModuleCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkShaderModule>::SetName(VK_OBJECT_TYPE_SHADER_MODULE, name); }
static VkShaderModuleCreateInfo CreateInfo(size_t code_size, const uint32_t *code, VkFlags flags);
};
class Shader : public internal::NonDispHandle<VkShaderEXT> {
public:
Shader() = default;
Shader(const Device &dev, VkShaderEXT shader) { NonDispHandle::init(dev, shader); }
Shader(const Device &dev, const VkShaderCreateInfoEXT &info) { Init(dev, info); }
Shader(const Device &dev, const VkShaderStageFlagBits stage, const std::vector<uint32_t> &spv,
const VkDescriptorSetLayout *descriptorSetLayout = nullptr, const VkPushConstantRange *pushConstRange = nullptr);
Shader(const Device &dev, const VkShaderStageFlagBits stage, const char* code,
const VkDescriptorSetLayout *descriptorSetLayout = nullptr, const VkPushConstantRange *pushConstRange = nullptr);
Shader(const Device &dev, const VkShaderStageFlagBits stage, const std::vector<uint8_t> &binary,
const VkDescriptorSetLayout *descriptorSetLayout = nullptr, const VkPushConstantRange *pushConstRange = nullptr);
~Shader() noexcept;
void Destroy() noexcept;
// vkCreateShaderModule()
void Init(const Device &dev, const VkShaderCreateInfoEXT &info);
VkResult InitTry(const Device &dev, const VkShaderCreateInfoEXT &info);
void SetName(const char *name) { NonDispHandle<VkShaderEXT>::SetName(VK_OBJECT_TYPE_SHADER_EXT, name); }
};
class PipelineCache : public internal::NonDispHandle<VkPipelineCache> {
public:
PipelineCache() = default;
PipelineCache(const Device &dev, const VkPipelineCacheCreateInfo &info) { Init(dev, info); }
~PipelineCache() noexcept;
void Destroy() noexcept;
void Init(const Device &dev, const VkPipelineCacheCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkPipelineCache>::SetName(VK_OBJECT_TYPE_PIPELINE_CACHE, name); }
};
class Pipeline : public internal::NonDispHandle<VkPipeline> {
public:
Pipeline() = default;
Pipeline(const Device &dev, const VkGraphicsPipelineCreateInfo &info) { Init(dev, info); }
Pipeline(const Device &dev, const VkGraphicsPipelineCreateInfo &info, const VkPipeline basePipeline) {
Init(dev, info, basePipeline);
}
Pipeline(const Device &dev, const VkComputePipelineCreateInfo &info) { Init(dev, info); }
Pipeline(const Device &dev, const VkRayTracingPipelineCreateInfoKHR &info) { Init(dev, info); }
Pipeline(const Device &dev, const VkDataGraphPipelineCreateInfoARM &info) { Init(dev, info); }
~Pipeline() noexcept;
void Destroy() noexcept;
// vkCreateGraphicsPipeline()
void Init(const Device &dev, const VkGraphicsPipelineCreateInfo &info);
// vkCreateGraphicsPipelineDerivative()
void Init(const Device &dev, const VkGraphicsPipelineCreateInfo &info, const VkPipeline basePipeline);
// vkCreateComputePipeline()
void Init(const Device &dev, const VkComputePipelineCreateInfo &info);
// vkCreateRayTracingPipelinesKHR
void Init(const Device &dev, const VkRayTracingPipelineCreateInfoKHR &info);
// vkCreateRayTracingPipelinesKHR with deferredOperation
void InitDeferred(const Device &dev, const VkRayTracingPipelineCreateInfoKHR &info, VkDeferredOperationKHR deferred_op);
// vkCreateDataGraphPipelinesARM
void Init(const Device &dev, const VkDataGraphPipelineCreateInfoARM &info);
// vkLoadPipeline()
void Init(const Device &dev, size_t size, const void *data);
// vkLoadPipelineDerivative()
void Init(const Device &dev, size_t size, const void *data, VkPipeline basePipeline);
// vkCreateGraphicsPipeline with error return
VkResult InitTry(const Device &dev, const VkGraphicsPipelineCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkPipeline>::SetName(VK_OBJECT_TYPE_PIPELINE, name); }
};
class PipelineLayout : public internal::NonDispHandle<VkPipelineLayout> {
public:
PipelineLayout() noexcept : NonDispHandle() {}
PipelineLayout(const Device &dev, VkPipelineLayoutCreateInfo &info, const std::vector<const DescriptorSetLayout *> &layouts) {
Init(dev, info, layouts);
}
PipelineLayout(const Device &dev, VkPipelineLayoutCreateInfo &info) { Init(dev, info); }
PipelineLayout(const Device &dev, const std::vector<const DescriptorSetLayout *> &layouts = {},
const std::vector<VkPushConstantRange> &push_constant_ranges = {},
VkPipelineLayoutCreateFlags flags = static_cast<VkPipelineLayoutCreateFlags>(0)) {
VkPipelineLayoutCreateInfo info = vku::InitStructHelper();
info.flags = flags;
info.pushConstantRangeCount = static_cast<uint32_t>(push_constant_ranges.size());
info.pPushConstantRanges = push_constant_ranges.data();
Init(dev, info, layouts);
}
~PipelineLayout() noexcept;
void Destroy() noexcept;
// Move constructor for Visual Studio 2013
PipelineLayout(PipelineLayout &&src) noexcept : NonDispHandle(std::move(src)){};
PipelineLayout &operator=(PipelineLayout &&src) noexcept {
this->~PipelineLayout();
this->NonDispHandle::operator=(std::move(src));
return *this;
};
// vCreatePipelineLayout()
void Init(const Device &dev, VkPipelineLayoutCreateInfo &info, const std::vector<const DescriptorSetLayout *> &layouts);
void Init(const Device &dev, VkPipelineLayoutCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkPipelineLayout>::SetName(VK_OBJECT_TYPE_PIPELINE_LAYOUT, name); }
};
class Sampler : public internal::NonDispHandle<VkSampler> {
public:
Sampler() = default;
Sampler(const Device &dev, const VkSamplerCreateInfo &info) { Init(dev, info); }
~Sampler() noexcept;
void Destroy() noexcept;
// vkCreateSampler()
void Init(const Device &dev, const VkSamplerCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkSampler>::SetName(VK_OBJECT_TYPE_SAMPLER, name); }
};
class DescriptorSetLayout : public internal::NonDispHandle<VkDescriptorSetLayout> {
public:
DescriptorSetLayout() = default;
DescriptorSetLayout(const Device &dev, const VkDescriptorSetLayoutCreateInfo &info) { Init(dev, info); }
DescriptorSetLayout(const Device &dev, const std::vector<VkDescriptorSetLayoutBinding> &descriptor_set_bindings = {},
VkDescriptorSetLayoutCreateFlags flags = 0, void *pNext = nullptr) {
VkDescriptorSetLayoutCreateInfo info = vku::InitStructHelper(pNext);
info.flags = flags;
info.bindingCount = static_cast<uint32_t>(descriptor_set_bindings.size());
info.pBindings = descriptor_set_bindings.data();
Init(dev, info);
}
DescriptorSetLayout(const Device &dev, const VkDescriptorSetLayoutBinding &descriptor_set_binding,
VkDescriptorSetLayoutCreateFlags flags = 0, void *pNext = nullptr) {
VkDescriptorSetLayoutCreateInfo info = vku::InitStructHelper(pNext);
info.flags = flags;
info.bindingCount = 1;
info.pBindings = &descriptor_set_binding;
Init(dev, info);
}
~DescriptorSetLayout() noexcept;
void Destroy() noexcept;
DescriptorSetLayout(DescriptorSetLayout &&src) noexcept : NonDispHandle(std::move(src)){};
DescriptorSetLayout &operator=(DescriptorSetLayout &&src) noexcept {
Destroy();
this->NonDispHandle::operator=(std::move(src));
return *this;
}
// vkCreateDescriptorSetLayout()
void Init(const Device &dev, const VkDescriptorSetLayoutCreateInfo &info);
// vkGetDescriptorSetLayoutSizeEXT
VkDeviceSize GetDescriptorBufferSize() const;
// vkGetDescriptorSetLayoutBindingOffsetEXT
VkDeviceSize GetDescriptorBufferBindingOffset(uint32_t binding) const;
};
class DescriptorPool : public internal::NonDispHandle<VkDescriptorPool> {
public:
DescriptorPool() = default;
DescriptorPool(const Device &dev, const VkDescriptorPoolCreateInfo &info) { Init(dev, info); }
~DescriptorPool() noexcept;
void Destroy() noexcept;
// vkCreateDescriptorPool()
void Init(const Device &dev, const VkDescriptorPoolCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkDescriptorPool>::SetName(VK_OBJECT_TYPE_DESCRIPTOR_POOL, name); }
// vkResetDescriptorPool()
void Reset();
bool GetDynamicUsage() { return dynamic_usage_; }
template <typename PoolSizes>
static VkDescriptorPoolCreateInfo CreateInfo(VkDescriptorPoolCreateFlags flags, uint32_t max_sets, const PoolSizes &pool_sizes);
private:
// Track whether this pool's usage is VK_DESCRIPTOR_POOL_USAGE_DYNAMIC
bool dynamic_usage_;
};
template <typename PoolSizes>
inline VkDescriptorPoolCreateInfo DescriptorPool::CreateInfo(VkDescriptorPoolCreateFlags flags, uint32_t max_sets,
const PoolSizes &pool_sizes) {
VkDescriptorPoolCreateInfo info = vku::InitStructHelper();
info.flags = flags;
info.maxSets = max_sets;
info.poolSizeCount = pool_sizes.size();
info.pPoolSizes = (info.poolSizeCount) ? pool_sizes.data() : nullptr;
return info;
}
class DescriptorSet : public internal::NonDispHandle<VkDescriptorSet> {
public:
~DescriptorSet() noexcept;
void Destroy() noexcept;
explicit DescriptorSet() : NonDispHandle() {}
explicit DescriptorSet(const Device &dev, DescriptorPool *pool, VkDescriptorSet set) : NonDispHandle(dev, set) {
containing_pool_ = pool;
}
void SetName(const char *name) { NonDispHandle<VkDescriptorSet>::SetName(VK_OBJECT_TYPE_DESCRIPTOR_SET, name); }
private:
DescriptorPool *containing_pool_;
};
class DescriptorUpdateTemplate : public internal::NonDispHandle<VkDescriptorUpdateTemplate> {
public:
~DescriptorUpdateTemplate() noexcept;
void Destroy() noexcept;
explicit DescriptorUpdateTemplate() : NonDispHandle() {}
explicit DescriptorUpdateTemplate(const Device &dev, const VkDescriptorUpdateTemplateCreateInfo &info) { Init(dev, info); }
void Init(const Device &dev, const VkDescriptorUpdateTemplateCreateInfo &info);
void SetName(const char *name) {
NonDispHandle<VkDescriptorUpdateTemplate>::SetName(VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, name);
}
};
class CommandPool : public internal::NonDispHandle<VkCommandPool> {
public:
~CommandPool() noexcept;
void Destroy() noexcept;
explicit CommandPool() : NonDispHandle() {}
explicit CommandPool(const Device &dev, const VkCommandPoolCreateInfo &info) { Init(dev, info); }
explicit CommandPool(const Device &dev, uint32_t queue_family_index, VkCommandPoolCreateFlags flags = 0);
void Init(const Device &dev, const VkCommandPoolCreateInfo &info);
void Init(const Device &dev, uint32_t queue_family_index, VkCommandPoolCreateFlags flags = 0);
void SetName(const char *name) { NonDispHandle<VkCommandPool>::SetName(VK_OBJECT_TYPE_COMMAND_POOL, name); }
};
class CommandBuffer : public internal::Handle<VkCommandBuffer> {
public:
~CommandBuffer() noexcept;
void Destroy() noexcept;
explicit CommandBuffer() : Handle() {}
CommandBuffer(const Device &dev, const VkCommandBufferAllocateInfo &info) { Init(dev, info); }
CommandBuffer(const Device &dev, const CommandPool &pool, VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
Init(dev, pool, level);
}
CommandBuffer(CommandBuffer &&rhs) noexcept : Handle(std::move(rhs)) {
dev_handle_ = rhs.dev_handle_;
rhs.dev_handle_ = VK_NULL_HANDLE;
cmd_pool_ = rhs.cmd_pool_;
rhs.cmd_pool_ = VK_NULL_HANDLE;
}
// vkAllocateCommandBuffers()
void Init(const Device &dev, const VkCommandBufferAllocateInfo &info);
void Init(const Device &dev, const CommandPool &pool, VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY);
void SetName(const Device &device, const char *name) {
Handle<VkCommandBuffer>::SetName(device, VK_OBJECT_TYPE_COMMAND_BUFFER, name);
}
// vkBeginCommandBuffer()
void Begin(const VkCommandBufferBeginInfo *info);
void Begin(VkCommandBufferUsageFlags flags);
void Begin() { Begin(0u); }
// vkEndCommandBuffer()
// vkResetCommandBuffer()
void End();
void Reset(VkCommandBufferResetFlags flags);
void Reset() { Reset(VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); }
static VkCommandBufferAllocateInfo CreateInfo(VkCommandPool const &pool);
void BeginRenderPass(const VkRenderPassBeginInfo &info, VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE);
void BeginRenderPass(VkRenderPass rp, VkFramebuffer fb, uint32_t render_area_width = 1, uint32_t render_area_height = 1,
uint32_t clear_count = 0, const VkClearValue *clear_values = nullptr);
void NextSubpass(VkSubpassContents contents = VK_SUBPASS_CONTENTS_INLINE);
void EndRenderPass();
void BeginRendering(const VkRenderingInfo &renderingInfo);
void BeginRenderingColor(const VkImageView imageView, VkRect2D render_area);
void EndRendering();
void BindShaders(const vkt::Shader &vert_shader, const vkt::Shader &frag_shader);
void BindShaders(const vkt::Shader &vert_shader, const vkt::Shader &geom_shader, const vkt::Shader &frag_shader);
void BindShaders(const vkt::Shader &vert_shader, const vkt::Shader &tesc_shader, const vkt::Shader &tese_shader,
const vkt::Shader &frag_shader);
void BindShaders(const vkt::Shader &vert_shader, const vkt::Shader &tesc_shader, const vkt::Shader &tese_shader,
const vkt::Shader &geom_shader, const vkt::Shader &frag_shader);
void BindCompShader(const vkt::Shader &comp_shader);
void BindMeshShaders(const vkt::Shader &mesh_shader, const vkt::Shader &frag_shader);
void BindMeshShaders(const vkt::Shader &task_shader, const vkt::Shader &mesh_shader, const vkt::Shader &frag_shader);
void BeginVideoCoding(const VkVideoBeginCodingInfoKHR &beginInfo);
void ControlVideoCoding(const VkVideoCodingControlInfoKHR &controlInfo);
void DecodeVideo(const VkVideoDecodeInfoKHR &decodeInfo);
void EncodeVideo(const VkVideoEncodeInfoKHR &encodeInfo);
void EndVideoCoding(const VkVideoEndCodingInfoKHR &endInfo);
void SetEvent(Event &event, VkPipelineStageFlags stageMask) { event.CmdSet(*this, stageMask); }
void ResetEvent(Event &event, VkPipelineStageFlags stageMask) { event.CmdReset(*this, stageMask); }
void WaitEvents(uint32_t eventCount, const VkEvent *pEvents, VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask, uint32_t memoryBarrierCount, const VkMemoryBarrier *pMemoryBarriers,
uint32_t bufferMemoryBarrierCount, const VkBufferMemoryBarrier *pBufferMemoryBarriers,
uint32_t imageMemoryBarrierCount, const VkImageMemoryBarrier *pImageMemoryBarriers) {
vk::CmdWaitEvents(handle(), eventCount, pEvents, srcStageMask, dstStageMask, memoryBarrierCount, pMemoryBarriers,
bufferMemoryBarrierCount, pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
}
void Copy(const Buffer &src, const Buffer &dst);
void ExecuteCommands(const CommandBuffer &secondary);
void Barrier(const VkMemoryBarrier2 &barrier, VkDependencyFlags dependency_flags = 0);
void Barrier(const VkBufferMemoryBarrier2 &buffer_barrier, VkDependencyFlags dependency_flags = 0);
void Barrier(const VkImageMemoryBarrier2 &image_barrier, VkDependencyFlags dependency_flags = 0);
void Barrier(const VkDependencyInfo &dep_info);
void BarrierKHR(const VkMemoryBarrier2 &barrier, VkDependencyFlags dependency_flags = 0);
void BarrierKHR(const VkBufferMemoryBarrier2 &buffer_barrier, VkDependencyFlags dependency_flags = 0);
void BarrierKHR(const VkImageMemoryBarrier2 &image_barrier, VkDependencyFlags dependency_flags = 0);
void BarrierKHR(const VkDependencyInfo &dep_info);
void FullMemoryBarrier();
private:
VkDevice dev_handle_;
VkCommandPool cmd_pool_;
};
// shortcut to vkt::CommandBuffer{}. Useful in submit helpers: queue->submit(vkt::no_cmd, ...)
inline const CommandBuffer no_cmd;
class RenderPass : public internal::NonDispHandle<VkRenderPass> {
public:
RenderPass() = default;
// vkCreateRenderPass()
RenderPass(const Device &dev, const VkRenderPassCreateInfo &info) { Init(dev, info); }
// vkCreateRenderPass2()
RenderPass(const Device &dev, const VkRenderPassCreateInfo2 &info) { Init(dev, info); }
~RenderPass() noexcept;
void Destroy() noexcept;
// vkCreateRenderPass()
void Init(const Device &dev, const VkRenderPassCreateInfo &info);
// vkCreateRenderPass2()
void Init(const Device &dev, const VkRenderPassCreateInfo2 &info);
void SetName(const char *name) { NonDispHandle<VkRenderPass>::SetName(VK_OBJECT_TYPE_RENDER_PASS, name); }
};
class Framebuffer : public internal::NonDispHandle<VkFramebuffer> {
public:
Framebuffer() = default;
Framebuffer(const Device &dev, const VkFramebufferCreateInfo &info) { Init(dev, info); }
// The most common case, anything outside of this should create there own VkFramebufferCreateInfo
Framebuffer(const Device &dev, VkRenderPass rp, uint32_t attchment_count, const VkImageView *attchments, uint32_t width = 32,
uint32_t height = 32) {
VkFramebufferCreateInfo info = vku::InitStructHelper();
info.renderPass = rp;
info.attachmentCount = attchment_count;
info.pAttachments = attchments;
info.width = width;
info.height = height;
info.layers = 1;
Init(dev, info);
}
~Framebuffer() noexcept;
void Destroy() noexcept;
// vkCreateFramebuffer()
void Init(const Device &dev, const VkFramebufferCreateInfo &info);
void SetName(const char *name) { NonDispHandle<VkFramebuffer>::SetName(VK_OBJECT_TYPE_FRAMEBUFFER, name); }
};
class SamplerYcbcrConversion : public internal::NonDispHandle<VkSamplerYcbcrConversion> {
public:
SamplerYcbcrConversion() = default;
SamplerYcbcrConversion(const Device &dev, VkFormat format) { Init(dev, DefaultConversionInfo(format)); }
SamplerYcbcrConversion(const Device &dev, const VkSamplerYcbcrConversionCreateInfo &info) { Init(dev, info); }
~SamplerYcbcrConversion() noexcept;
void Destroy() noexcept;
void Init(const Device &dev, const VkSamplerYcbcrConversionCreateInfo &info);
void SetName(const char *name) {
NonDispHandle<VkSamplerYcbcrConversion>::SetName(VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, name);
}
VkSamplerYcbcrConversionInfo ConversionInfo();
static VkSamplerYcbcrConversionCreateInfo DefaultConversionInfo(VkFormat format);
};
inline VkBufferCreateInfo Buffer::CreateInfo(VkDeviceSize size, VkFlags usage, const vvl::span<uint32_t> &queue_families,
void *create_info_pnext) {
VkBufferCreateInfo info = vku::InitStructHelper(create_info_pnext);
info.size = size;
info.usage = usage;
if (queue_families.size() > 1) {
info.sharingMode = VK_SHARING_MODE_CONCURRENT;
info.queueFamilyIndexCount = static_cast<uint32_t>(queue_families.size());
info.pQueueFamilyIndices = queue_families.data();
}
return info;
}
class Tensor : public internal::NonDispHandle<VkTensorARM> {
public:
explicit Tensor();
explicit Tensor(const Device &dev, const bool is_copy_tensor = false);
explicit Tensor(const Device &dev, const VkTensorDescriptionARM &desc);
explicit Tensor(const Device &dev, const VkTensorCreateInfoARM &info);
~Tensor() noexcept;
void Destroy() noexcept;
// vkCreateTensor()
void InitNoMem(const Device &dev, const VkTensorCreateInfoARM &info);
const VkMemoryRequirements2 &GetMemoryReqs();
void BindToMem(VkFlags required_flags = 0, VkFlags forbidden_flags = 0);
VkFormat Format() const { return description_.format; }
uint32_t DimensionCount() const { return description_.dimensionCount; }
const VkTensorDescriptionARM &Description() const { return description_; }
private:
const Device *device_ = nullptr;
VkTensorCreateInfoARM create_info_;
VkTensorDescriptionARM description_;
VkTensorMemoryRequirementsInfoARM mem_req_info_;
VkMemoryRequirements2 mem_reqs_;
std::vector<int64_t> dimensions_;
std::vector<int64_t> strides_;
vkt::DeviceMemory memory_;
};
class TensorView : public internal::NonDispHandle<VkTensorViewARM> {
public:
TensorView() = default;
explicit TensorView(const Device &dev, const VkTensorViewCreateInfoARM &info);
~TensorView() noexcept;
void Destroy() noexcept;
// vkCreateTensorViewARM
void Init(const Device &dev, const VkTensorViewCreateInfoARM &info);
private:
const Device *device_ = nullptr;
VkTensorViewCreateInfoARM create_info_;
};
class DataGraphPipelineSession : public internal::NonDispHandle<VkDataGraphPipelineSessionARM> {
public:
explicit DataGraphPipelineSession(const Device &dev, const VkDataGraphPipelineSessionCreateInfoARM &info);
~DataGraphPipelineSession() noexcept;
void Destroy() noexcept;
// CreateDataGraphPipelineSessionARM
void Init(const Device &dev);
void GetMemoryReqs();
void AllocSessionMem(std::vector<vkt::DeviceMemory> &device_mem, bool is_protected = false, size_t scale_factor = 1,
int32_t size_modifier = 0);
size_t BindPointsCount() const { return bind_point_reqs_.size(); }
const std::vector<VkDataGraphPipelineSessionBindPointRequirementARM> &BindPointReqs() const { return bind_point_reqs_; }
const std::vector<VkMemoryRequirements2> &MemReqs() const { return mem_reqs_; }
private:
const Device *device_ = nullptr;
VkDataGraphPipelineSessionCreateInfoARM create_info_;
std::vector<VkDataGraphPipelineSessionBindPointRequirementARM> bind_point_reqs_;
std::vector<VkMemoryRequirements2> mem_reqs_;
};
inline VkEventCreateInfo Event::CreateInfo(VkFlags flags) {
VkEventCreateInfo info = vku::InitStructHelper();
info.flags = flags;
return info;
}
inline VkQueryPoolCreateInfo QueryPool::CreateInfo(VkQueryType type, uint32_t slot_count, VkQueryPoolCreateFlags create_flags) {
VkQueryPoolCreateInfo info = vku::InitStructHelper();
info.flags = create_flags;
info.queryType = type;
info.queryCount = slot_count;
return info;
}
inline VkShaderModuleCreateInfo ShaderModule::CreateInfo(size_t code_size, const uint32_t *code, VkFlags flags) {
VkShaderModuleCreateInfo info = vku::InitStructHelper();
info.codeSize = code_size;
info.pCode = code;
info.flags = flags;
return info;
}
inline VkWriteDescriptorSet Device::WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, uint32_t count,
const VkDescriptorImageInfo *image_info) {
VkWriteDescriptorSet write = vku::InitStructHelper();
write.dstSet = set;
write.dstBinding = binding;
write.dstArrayElement = array_element;
write.descriptorCount = count;
write.descriptorType = type;
write.pImageInfo = image_info;
return write;
}
inline VkWriteDescriptorSet Device::WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, uint32_t count,
const VkDescriptorBufferInfo *buffer_info) {
VkWriteDescriptorSet write = vku::InitStructHelper();
write.dstSet = set;
write.dstBinding = binding;
write.dstArrayElement = array_element;
write.descriptorCount = count;
write.descriptorType = type;
write.pBufferInfo = buffer_info;
return write;
}
inline VkWriteDescriptorSet Device::WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, uint32_t count, const VkBufferView *buffer_views) {
VkWriteDescriptorSet write = vku::InitStructHelper();
write.dstSet = set;
write.dstBinding = binding;
write.dstArrayElement = array_element;
write.descriptorCount = count;
write.descriptorType = type;
write.pTexelBufferView = buffer_views;
return write;
}
inline VkWriteDescriptorSet Device::WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type,
const std::vector<VkDescriptorImageInfo> &image_info) {
return WriteDescriptorSet(set, binding, array_element, type, static_cast<uint32_t>(image_info.size()), &image_info[0]);
}
inline VkWriteDescriptorSet Device::WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type,
const std::vector<VkDescriptorBufferInfo> &buffer_info) {
return WriteDescriptorSet(set, binding, array_element, type, static_cast<uint32_t>(buffer_info.size()), &buffer_info[0]);
}
inline VkWriteDescriptorSet Device::WriteDescriptorSet(const DescriptorSet &set, uint32_t binding, uint32_t array_element,
VkDescriptorType type, const std::vector<VkBufferView> &buffer_views) {
return WriteDescriptorSet(set, binding, array_element, type, static_cast<uint32_t>(buffer_views.size()), &buffer_views[0]);
}
class Swapchain : public internal::NonDispHandle<VkSwapchainKHR> {
public:
explicit Swapchain() = default;
explicit Swapchain(const Device &dev, const VkSwapchainCreateInfoKHR &info) { Init(dev, info); }
Swapchain(Swapchain &&rhs) noexcept : NonDispHandle(std::move(rhs)) {}
Swapchain &operator=(Swapchain &&) = default;
~Swapchain() noexcept;
void Destroy() noexcept;
void Init(const Device &dev, const VkSwapchainCreateInfoKHR &info);
void SetName(const char *name) { NonDispHandle<VkSwapchainKHR>::SetName(VK_OBJECT_TYPE_SWAPCHAIN_KHR, name); }
uint32_t GetImageCount() const;
std::vector<VkImage> GetImages() const;
uint32_t AcquireNextImage(const Semaphore &image_acquired, uint64_t timeout, VkResult *result = nullptr);
uint32_t AcquireNextImage(const Fence &image_acquired, uint64_t timeout, VkResult *result = nullptr);
};
class IndirectCommandsLayout : public internal::NonDispHandle<VkIndirectCommandsLayoutEXT> {
public:
~IndirectCommandsLayout() noexcept;
void Destroy() noexcept;
explicit IndirectCommandsLayout() : NonDispHandle() {}
explicit IndirectCommandsLayout(const Device &dev, const VkIndirectCommandsLayoutCreateInfoEXT &info) { Init(dev, info); }
void Init(const Device &dev, const VkIndirectCommandsLayoutCreateInfoEXT &info);
};
class IndirectExecutionSet : public internal::NonDispHandle<VkIndirectExecutionSetEXT> {
public:
~IndirectExecutionSet() noexcept;
void Destroy() noexcept;
explicit IndirectExecutionSet() : NonDispHandle() {}
explicit IndirectExecutionSet(const Device &dev, const VkIndirectExecutionSetCreateInfoEXT &info) { Init(dev, info); }
explicit IndirectExecutionSet(const Device &dev, VkPipeline init_pipeline, uint32_t max_pipelines);
explicit IndirectExecutionSet(const Device &dev, const VkIndirectExecutionSetShaderInfoEXT &shader_info);
void Init(const Device &dev, const VkIndirectExecutionSetCreateInfoEXT &info);
};
class Surface {
public:
Surface() : instance_(VK_NULL_HANDLE), handle_(VK_NULL_HANDLE) {}
#if defined(VK_USE_PLATFORM_WIN32_KHR)
VkResult Init(VkInstance, const VkWin32SurfaceCreateInfoKHR &);
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
VkResult Init(VkInstance, const VkMetalSurfaceCreateInfoEXT &);
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
VkResult Init(VkInstance, const VkAndroidSurfaceCreateInfoKHR &);
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
VkResult Init(VkInstance, const VkXlibSurfaceCreateInfoKHR &);
#endif
#if defined(VK_USE_PLATFORM_XCB_KHR)
VkResult Init(VkInstance, const VkXcbSurfaceCreateInfoKHR &);
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
VkResult Init(VkInstance, const VkWaylandSurfaceCreateInfoKHR &);
#endif
~Surface() noexcept { Destroy(); }
void Destroy() noexcept {
if (handle_ != VK_NULL_HANDLE) {
vk::DestroySurfaceKHR(instance_, handle_, nullptr);
handle_ = VK_NULL_HANDLE;
}
}
VkSurfaceKHR Handle() const { return handle_; }
operator VkSurfaceKHR() const { return handle_; }
Surface(Surface &&src) noexcept : instance_{src.instance_}, handle_{src.handle_} {
src.instance_ = {};
src.handle_ = {};
}
Surface &operator=(Surface &&src) noexcept {
instance_ = src.instance_;
src.instance_ = {};
handle_ = src.handle_;
src.handle_ = {};
return *this;
}
// This is ONLY for tests that need a way test destroying an instance and leak the Surface object (and calling
// vkDestroySurfaceKHR will be invalid)
void DestroyExplicitly() {
handle_ = VK_NULL_HANDLE;
instance_ = VK_NULL_HANDLE;
}
private:
VkInstance instance_ = VK_NULL_HANDLE;
VkSurfaceKHR handle_ = VK_NULL_HANDLE;
};
const VkAllocationCallbacks *DefaultAllocator();
} // namespace vkt