Initial commit (should probably have done this earlier).

This commit is contained in:
2022-09-17 16:42:55 +02:00
parent 2774176fbd
commit 1d073c0256
25 changed files with 25344 additions and 0 deletions

39
source/common.hpp Normal file
View File

@@ -0,0 +1,39 @@
#pragma once
#if !defined(VK_CAPTURE_COMMON_HPP_INCLUDED)
#define VK_CAPTURE_COMMON_HPP_INCLUDED 1
#include <cstddef>
#include "vk_capture.h"
namespace vk_capture
{
//
// public defines
//
//
// public constants
//
//
// public types
//
//
// public functions
//
VkVariantMWN* allocVariant(std::size_t num);
void* allocData(std::size_t bytes, std::size_t alignment = 1);
template<typename T>
inline T* allocType(std::size_t count = 1) {
return static_cast<T*>(allocData(sizeof(T) * count, alignof(T)));
}
} // namespace vk_capture
#endif // !defined(VK_CAPTURE_COMMON_HPP_INCLUDED)

57
source/data_pool.cpp Normal file
View File

@@ -0,0 +1,57 @@
#include "data_pool.hpp"
#include <cassert>
namespace vk_capture
{
//
// internal defines
//
//
// internal constants
//
//
// internal types
//
//
// internal variables
//
//
// internal functions
//
//
// public functions
//
void* DataPool::allocate(std::size_t bytes, std::size_t alignment)
{
assert(bytes > 0 && bytes <= PAGE_SIZE);
assert(alignment > 0 && alignment <= alignof(std::max_align_t));
if (offset % alignment != 0) {
offset += alignment - (offset % alignment);
}
const std::size_t remainingOnPage = PAGE_SIZE - (offset % PAGE_SIZE);
if (remainingOnPage == PAGE_SIZE || remainingOnPage < bytes)
{
// next page
pages.push_back(std::make_unique<Page>());
offset = PAGE_SIZE * (pages.size() - 1);
}
const std::size_t page = offset / PAGE_SIZE;
const std::size_t localOffset = offset % PAGE_SIZE;
std::uint8_t* result = &(*pages[page])[localOffset];
offset += bytes;
assert(reinterpret_cast<std::uintptr_t>(result) % alignment == 0);
return result;
}
} // namespace vk_capture

50
source/data_pool.hpp Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
#if !defined(VK_CAPTURE_DATA_POOL_HPP_INCLUDED)
#define VK_CAPTURE_DATA_POOL_HPP_INCLUDED 1
#include <array>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <vector>
namespace vk_capture
{
//
// public defines
//
//
// public constants
//
//
// public types
//
struct DataPool
{
static constexpr std::size_t PAGE_SIZE = 4096 * 1024;
static_assert(PAGE_SIZE % alignof(std::max_align_t) == 0);
struct alignas(std::max_align_t) Page : std::array<std::uint8_t, PAGE_SIZE> {};
using page_ptr_t = std::unique_ptr<Page>;
std::vector<page_ptr_t> pages;
std::size_t offset = 0;
void* allocate(std::size_t bytes, std::size_t alignment = 1);
inline void reset() { offset = 0; }
};
//
// public functions
//
} // namespace vk_capture
#endif // !defined(VK_CAPTURE_DATA_POOL_HPP_INCLUDED)

39
source/dispatch_table.cpp Normal file
View File

@@ -0,0 +1,39 @@
#include "dispatch_table.hpp"
namespace vk_capture
{
//
// internal defines
//
//
// internal constants
//
//
// internal types
//
//
// internal variables
//
//
// internal functions
//
//
// public variables
//
// TODO: this won't work for multi-device setups, we'd need a hashmap of sort then
VkLayerInstanceDispatchTable g_instanceDispatchTable;
VkLayerDispatchTable g_dispatchTable;
//
// public functions
//
} // namespace sekiei

38
source/dispatch_table.hpp Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#if !defined(VK_CAPTURE_DISPATCH_TABLE_HPP_INCLUDED)
#define VK_CAPTURE_DISPATCH_TABLE_HPP_INCLUDED 1
#include <vulkan/vk_dispatch_table_helper.h>
namespace vk_capture
{
//
// public defines
//
//
// public constants
//
//
// public types
//
//
// public variables
//
// TODO: this won't work for multi-device setups, we'd need a hashmap of sort then
extern VkLayerInstanceDispatchTable g_instanceDispatchTable;
extern VkLayerDispatchTable g_dispatchTable;
//
// public functions
//
} // namespace vk_capture
#endif // !defined(VK_CAPTURE_DISPATCH_TABLE_HPP_INCLUDED)

3518
source/functions.cpp Normal file

File diff suppressed because it is too large Load Diff

14
source/functions.hpp Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#if !defined(VK_CAPTURE_FUNCTIONS_HPP_INCLUDED)
#define VK_CAPTURE_FUNCTIONS_HPP_INCLUDED 1
#include <vulkan/vulkan.h>
namespace vk_capture
{
PFN_vkVoidFunction getWrappedFunctionPtr(const char* pName);
} // namespace vk_capture
#endif // VK_CAPTURE_FUNCTIONS_HPP_INCLUDED

164
source/layer.cpp Normal file
View File

@@ -0,0 +1,164 @@
#include <cstdio>
#include <cstring>
#include <vulkan/vulkan.hpp>
#include <vulkan/vk_layer.h>
#include "dispatch_table.hpp"
#include "functions.hpp"
#include "record_list.hpp"
#include "vk_capture.h"
namespace vk_capture
{
inline constexpr std::uint32_t LOADER_LAYER_VERSION = 2;
PFN_vkVoidFunction getLayerFunctionPtr(const char* pName);
VkResult vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance)
{
const VkLayerInstanceCreateInfo* layerCreateInfo = static_cast<const VkLayerInstanceCreateInfo*>(pCreateInfo->pNext);
// step through the chain of pNext until we get to the link info
while(layerCreateInfo && (layerCreateInfo->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO ||
layerCreateInfo->function != VK_LAYER_LINK_INFO))
{
layerCreateInfo = static_cast<const VkLayerInstanceCreateInfo*>(layerCreateInfo->pNext);
}
if(layerCreateInfo == nullptr)
{
// No loader instance create info
return VK_ERROR_INITIALIZATION_FAILED;
}
PFN_vkGetInstanceProcAddr gpa = layerCreateInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr;
// move chain on for next layer
const_cast<VkLayerInstanceCreateInfo*>(layerCreateInfo)->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext;
PFN_vkCreateInstance createFunc = reinterpret_cast<PFN_vkCreateInstance>(gpa(VK_NULL_HANDLE, "vkCreateInstance"));
VkResult ret = createFunc(pCreateInfo, pAllocator, pInstance);
if (ret != VK_SUCCESS)
{
return ret;
}
// fetch our own dispatch table for the functions we need, into the next layer
layer_init_instance_dispatch_table(*pInstance, &vk_capture::g_instanceDispatchTable, gpa);
return VK_SUCCESS;
}
VkResult vkCreateDevice(
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice)
{
const VkLayerDeviceCreateInfo* layerCreateInfo = static_cast<const VkLayerDeviceCreateInfo*>(pCreateInfo->pNext);
// step through the chain of pNext until we get to the link info
while(layerCreateInfo && (layerCreateInfo->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO ||
layerCreateInfo->function != VK_LAYER_LINK_INFO))
{
layerCreateInfo = static_cast<const VkLayerDeviceCreateInfo*>(layerCreateInfo->pNext);
}
if(layerCreateInfo == nullptr)
{
// No loader instance create info
return VK_ERROR_INITIALIZATION_FAILED;
}
PFN_vkGetInstanceProcAddr gipa = layerCreateInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr;
PFN_vkGetDeviceProcAddr gdpa = layerCreateInfo->u.pLayerInfo->pfnNextGetDeviceProcAddr;
// move chain on for next layer
const_cast<VkLayerDeviceCreateInfo*>(layerCreateInfo)->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext;
PFN_vkCreateDevice createFunc = (PFN_vkCreateDevice)gipa(VK_NULL_HANDLE, "vkCreateDevice");
VkResult ret = createFunc(physicalDevice, pCreateInfo, pAllocator, pDevice);
if (ret != VK_SUCCESS)
{
return ret;
}
layer_init_device_dispatch_table(*pDevice, &vk_capture::g_dispatchTable, gdpa);
return VK_SUCCESS;
}
PFN_vkVoidFunction vkGetDeviceProcAddr(VkDevice device, const char* pName)
{
PFN_vkVoidFunction ptr = getLayerFunctionPtr(pName);
if (ptr) {
return ptr;
}
else {
return g_dispatchTable.GetDeviceProcAddr(device, pName);
}
}
PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance instance, const char* pName)
{
PFN_vkVoidFunction ptr = getLayerFunctionPtr(pName);
if (ptr) {
return ptr;
}
else {
return g_instanceDispatchTable.GetInstanceProcAddr(instance, pName);
}
}
PFN_vkVoidFunction getLayerFunctionPtr(const char* pName)
{
if (std::strcmp(pName, "vkCreateInstance") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vk_capture::vkCreateInstance);
}
else if (std::strcmp(pName, "vkCreateDevice") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vk_capture::vkCreateDevice);
}
else if (std::strcmp(pName, "vkGetInstanceProcAddr") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vk_capture::vkGetInstanceProcAddr);
}
if (std::strcmp(pName, "vkGetDeviceProcAddr") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vkGetDeviceProcAddr);
}
else if (std::strcmp(pName, "vkAllocateRecordListMWN") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vkAllocateRecordListMWN);
}
else if (std::strcmp(pName, "vkFreeRecordListMWN") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vkFreeRecordListMWN);
}
else if (std::strcmp(pName, "vkBeginRecordingMWN") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vkBeginRecordingMWN);
}
else if (std::strcmp(pName, "vkEndRecordingMWN") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vkEndRecordingMWN);
}
else if (std::strcmp(pName, "vkGetRecordListItemsMWN") == 0) {
return reinterpret_cast<PFN_vkVoidFunction>(&vkGetRecordListItemsMWN);
}
else {
return getWrappedFunctionPtr(pName);
}
}
} // namespace vk_capture
extern "C"
{
VK_LAYER_EXPORT VkResult VKAPI_CALL vk_capture_vkNegotiateLoaderLayerInterfaceVersion(VkNegotiateLayerInterface* pVersionStruct)
{
if (pVersionStruct->loaderLayerInterfaceVersion < vk_capture::LOADER_LAYER_VERSION) {
return VK_ERROR_INITIALIZATION_FAILED;
}
pVersionStruct->sType = LAYER_NEGOTIATE_INTERFACE_STRUCT;
pVersionStruct->pNext = nullptr;
pVersionStruct->loaderLayerInterfaceVersion = vk_capture::LOADER_LAYER_VERSION;
pVersionStruct->pfnGetInstanceProcAddr = &vk_capture::vkGetInstanceProcAddr;
pVersionStruct->pfnGetDeviceProcAddr = &vk_capture::vkGetDeviceProcAddr;
pVersionStruct->pfnGetPhysicalDeviceProcAddr = nullptr;
return VK_SUCCESS;
}
} // extern "C"

94
source/record_list.cpp Normal file
View File

@@ -0,0 +1,94 @@
#include "record_list.hpp"
#include <cassert>
#include <cstdint>
namespace vk_capture
{
//
// internal defines
//
//
// internal constants
//
//
// internal types
//
//
// internal variables
//
//
// internal functions
//
//
// public variables
//
VkRecordListMWN g_activeRecordList = nullptr; // TODO: per device and or per thread?
//
// public functions
//
VkResult vkAllocateRecordListMWN(VkDevice /* device */, const VkRecordListAllocateInfoMWN* pAllocInfo, VkRecordListMWN* pRecordList)
{
(void) pAllocInfo;
VkRecordListMWN result = new VkRecordListMWN_T(); // TODO: use Vulkan allocators
if (result == nullptr) {
return VK_ERROR_OUT_OF_HOST_MEMORY;
}
*pRecordList = result;
return VK_SUCCESS;
}
void vkFreeRecordListMWN(VkDevice /* device */, VkRecordListMWN recordList)
{
assert(recordList != g_activeRecordList);
delete recordList; // TODO: allocators
}
VkResult vkBeginRecordingMWN(VkDevice /* device */, const VkRecordInfoMWN* pRecordInfo)
{
assert(g_activeRecordList == nullptr);
assert(pRecordInfo && pRecordInfo->recordList);
g_activeRecordList = pRecordInfo->recordList;
return VK_SUCCESS;
}
void vkEndRecordingMWN(VkDevice /* device */)
{
assert(g_activeRecordList != nullptr);
g_activeRecordList = nullptr;
}
VkResult vkGetRecordListItemsMWN(VkDevice /* device */, VkRecordListMWN recordList, uint32_t* pItemCount, VkRecordListItemMWN** pItems)
{
assert(pItemCount);
assert(pItems);
*pItemCount = static_cast<std::uint32_t>(recordList->items.size());
*pItems = recordList->items.data();
return VK_SUCCESS;
}
VkVariantMWN* allocVariant(std::size_t num)
{
assert(g_activeRecordList);
return g_activeRecordList->values.allocate(num);
}
void* allocData(std::size_t bytes, std::size_t alignment)
{
assert(g_activeRecordList);
return g_activeRecordList->data.allocate(bytes, alignment);
}
} // namespace vk_capture

87
source/record_list.hpp Normal file
View File

@@ -0,0 +1,87 @@
#pragma once
#if !defined(VK_CAPTURE_RECORD_LIST_HPP_INCLUDED)
#define VK_CAPTURE_RECORD_LIST_HPP_INCLUDED 1
#include <cstdint>
#include <vector>
#include "data_pool.hpp"
#include "variant_pool.hpp"
#include "vk_capture.h"
#include "vk_function_ids.h"
typedef struct VkRecordListMWN_T {
std::vector<VkRecordListItemMWN> items; // TODO: use Vulkan allocators
vk_capture::VariantPool values;
vk_capture::DataPool data;
} VkRecordListMWN_T;
namespace vk_capture
{
//
// public defines
//
//
// public constants
//
//
// public types
//
//
// public variables
//
extern VkRecordListMWN g_activeRecordList;
//
// public functions
//
VkResult vkAllocateRecordListMWN(VkDevice device, const VkRecordListAllocateInfoMWN* pAllocInfo, VkRecordListMWN* pRecordList);
void vkFreeRecordListMWN(VkDevice device, VkRecordListMWN recordList);
VkResult vkBeginRecordingMWN(VkDevice device, const VkRecordInfoMWN* pRecordInfo);
void vkEndRecordingMWN(VkDevice device);
VkResult vkGetRecordListItemsMWN(VkDevice device, VkRecordListMWN recordList, uint32_t* pItemCount, VkRecordListItemMWN** pItems);
template<typename TResult, typename... TArgs>
void recordFunction(VkFunctionMWN function, const TResult& result, const TArgs&... args)
{
(void) result;
if (!g_activeRecordList) {
return;
}
VkRecordListItemMWN& item = g_activeRecordList->items.emplace_back();
item.function = function;
item.numParameters = static_cast<std::uint32_t>(sizeof...(TArgs));
item.pParameterValues = g_activeRecordList->values.allocate(sizeof...(TArgs));
variantWrap(result, item.returnValue);
VkVariantMWN* variant = item.pParameterValues;
(variantWrap(args, *(variant++)), ...);
}
template<typename... TArgs>
void recordVoidFunction(VkFunctionMWN function, const TArgs&... args)
{
if (!g_activeRecordList) {
return;
}
VkRecordListItemMWN& item = g_activeRecordList->items.emplace_back();
item.function = function;
item.numParameters = static_cast<std::uint32_t>(sizeof...(TArgs));
item.pParameterValues = g_activeRecordList->values.allocate(sizeof...(TArgs));
item.returnValue.type = VK_VARIANT_TYPE_NONE_MWN;
VkVariantMWN* variant = item.pParameterValues;
(variantWrap(args, *(variant++)), ...);
}
} // namespace vk_capture
#endif // !defined(VK_CAPTURE_RECORD_LIST_HPP_INCLUDED)

50
source/variant_pool.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include "variant_pool.hpp"
#include <cassert>
namespace vk_capture
{
//
// internal defines
//
//
// internal constants
//
//
// internal types
//
//
// internal variables
//
//
// internal functions
//
//
// public functions
//
VkVariantMWN* VariantPool::allocate(std::size_t num)
{
assert(num > 0 && num <= PAGE_SIZE);
const std::size_t remainingOnPage = PAGE_SIZE - (nextIndex % PAGE_SIZE);
if (remainingOnPage == PAGE_SIZE || remainingOnPage < num)
{
// next page
pages.push_back(std::make_unique<page_t>());
nextIndex = PAGE_SIZE * (pages.size() - 1);
}
const std::size_t page = nextIndex / PAGE_SIZE;
const std::size_t localIndex = nextIndex % PAGE_SIZE;
VkVariantMWN* result = &(*pages[page])[localIndex];
nextIndex += num;
return result;
}
} // namespace v

146
source/variant_pool.hpp Normal file
View File

@@ -0,0 +1,146 @@
#pragma once
#if !defined(VK_CAPTURE_VARIANT_POOL_HPP_INCLUDED)
#define VK_CAPTURE_VARIANT_POOL_HPP_INCLUDED 1
#include <array>
#include <cstddef>
#include <memory>
#include <vector>
#include "common.hpp"
#include "variant_wrap.hpp"
#include "vk_capture.h"
namespace vk_capture
{
//
// public defines
//
//
// public constants
//
//
// public types
//
struct VariantPool
{
static constexpr std::size_t PAGE_SIZE = 1024;
using page_t = std::array<VkVariantMWN, PAGE_SIZE>;
using page_ptr_t = std::unique_ptr<page_t>;
std::vector<page_ptr_t> pages;
std::size_t nextIndex = 0;
VkVariantMWN* allocate(std::size_t num = 1);
inline void reset() { nextIndex = 0; }
};
//
// public functions
//
template<typename TValue>
inline void variantWrap(const TValue& /* value */, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_UNKNOWN_MWN;
}
inline void variantWrap(bool value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_BOOL_MWN;
outVariant.uintValue = value;
}
inline void variantWrap(std::uint8_t value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_UINT8_MWN;
outVariant.uintValue = value;
}
inline void variantWrap(std::int8_t value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_INT8_MWN;
outVariant.intValue = value;
}
inline void variantWrap(std::uint16_t value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_UINT16_MWN;
outVariant.uintValue = value;
}
inline void variantWrap(std::int16_t value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_INT16_MWN;
outVariant.intValue = value;
}
inline void variantWrap(std::uint32_t value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_UINT32_MWN;
outVariant.uintValue = value;
}
inline void variantWrap(std::int32_t value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_INT32_MWN;
outVariant.intValue = value;
}
inline void variantWrap(std::uint64_t value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_UINT64_MWN;
outVariant.uintValue = value;
}
inline void variantWrap(std::int64_t value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_INT64_MWN;
outVariant.intValue = value;
}
inline void variantWrap(const void* value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_VOID_POINTER_MWN;
outVariant.voidPointerValue = value;
}
template<typename TPointed>
inline void variantWrap(const TPointed* value, VkVariantMWN& outVariant);
template<typename TEle, std::size_t count>
inline void variantWrap(const TEle (&value)[count], VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_ARRAY_MWN;
outVariant.arrayValue.numElements = count;
outVariant.arrayValue.elements = allocVariant(count);
for (std::size_t idx = 0; idx < count; ++idx) {
variantWrap(value[idx], outVariant.arrayValue.elements[idx]);
}
}
template<typename TPointed>
inline void variantWrap(const TPointed* value, VkVariantMWN& outVariant)
{
outVariant.type = VK_VARIANT_TYPE_POINTER_MWN;
if (value != nullptr)
{
outVariant.pointerValue = allocVariant(1);
variantWrap(*value, *outVariant.pointerValue);
}
else
{
// TODO: now the type is missing ...
outVariant.pointerValue = nullptr;
}
}
} // namespace vk_capture
#endif // !defined(VK_CAPTURE_VARIANT_POOL_HPP_INCLUDED)

19673
source/variant_wrap.hpp Normal file

File diff suppressed because it is too large Load Diff