graphics-hook: Handle VK_KHR_imageless_framebuffer

Applications that use this Vulkan extension would have image usage
mismatches because we add VK_IMAGE_USAGE_TRANSFER_SRC_BIT to
VkSwapchainCreateInfoKHR::imageUsage, so make the same modification to
VkFramebufferAttachmentImageInfo::usage.
This commit is contained in:
jpark37
2023-03-24 15:17:43 -07:00
committed by Jim
parent 1a05097304
commit feae65c472
3 changed files with 439 additions and 6 deletions
+1 -1
View File
@@ -13,7 +13,7 @@
#define HOOK_VER_MAJOR 1
#define HOOK_VER_MINOR 8
#define HOOK_VER_PATCH 0
#define HOOK_VER_PATCH 1
#ifndef STRINGIFY
#define STRINGIFY(s) #s
@@ -66,6 +66,18 @@ struct vk_queue_data {
uint32_t frame_count;
};
struct vk_swap_view_data {
struct vk_obj_node node;
};
#define OBS_COLOR_ATTACHMENT_LIMIT 8
struct vk_framebuffer_data {
struct vk_obj_node node;
VkFramebuffer alternates[1 << OBS_COLOR_ATTACHMENT_LIMIT];
uint32_t color_attachment_mask;
};
struct vk_frame_data {
VkCommandPool cmd_pool;
VkCommandBuffer cmd_buffer;
@@ -103,6 +115,8 @@ struct vk_data {
struct vk_swap_data *cur_swap;
struct vk_obj_list queues;
struct vk_obj_list swap_views;
struct vk_obj_list framebuffers;
VkExternalMemoryProperties external_mem_props;
@@ -247,6 +261,13 @@ static struct vk_data *get_device_data_by_queue(VkQueue queue)
(uint64_t)GET_LDT(queue));
}
static struct vk_data *
get_device_data_by_command_buffer(VkCommandBuffer commandBuffer)
{
return (struct vk_data *)get_obj_data(&devices,
(uint64_t)GET_LDT(commandBuffer));
}
static struct vk_data *remove_device_data(VkDevice device)
{
return (struct vk_data *)remove_obj_data(&devices,
@@ -285,11 +306,6 @@ static struct vk_queue_data *get_queue_data(struct vk_data *data, VkQueue queue)
(uint64_t)queue);
}
static VkQueue get_queue_key(const struct vk_queue_data *queue_data)
{
return (VkQueue)(uintptr_t)queue_data->node.obj;
}
static void remove_free_queue_all(struct vk_data *data,
const VkAllocationCallbacks *ac)
{
@@ -321,6 +337,73 @@ static void queue_walk_end(struct vk_data *data)
/* ------------------------------------------------------------------------- */
static struct vk_swap_view_data *
add_swap_view_data(struct vk_data *data, VkImageView imageView,
const VkAllocationCallbacks *ac)
{
struct vk_swap_view_data *const swap_view_data =
vk_alloc(ac, sizeof(struct vk_swap_view_data),
_Alignof(struct vk_swap_view_data),
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
add_obj_data(&data->swap_views, (uint64_t)imageView, swap_view_data);
return swap_view_data;
}
static struct vk_swap_view_data *get_swap_view_data(struct vk_data *data,
VkImageView imageView)
{
return (struct vk_swap_view_data *)get_obj_data(&data->swap_views,
(uint64_t)imageView);
}
static void remove_free_swap_view_data(struct vk_data *data,
VkImageView imageView,
const VkAllocationCallbacks *ac)
{
struct vk_swap_data *const swap_view_data =
(struct vk_swap_data *)remove_obj_data(&data->swap_views,
(uint64_t)imageView);
vk_free(ac, swap_view_data);
}
/* ------------------------------------------------------------------------- */
static struct vk_framebuffer_data *
add_framebuffer_data(struct vk_data *data, VkFramebuffer framebuffer,
const VkAllocationCallbacks *ac)
{
struct vk_framebuffer_data *const framebuffer_data =
vk_alloc(ac, sizeof(struct vk_framebuffer_data),
_Alignof(struct vk_framebuffer_data),
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
add_obj_data(&data->framebuffers, (uint64_t)framebuffer,
framebuffer_data);
for (size_t i = 0; i < _countof(framebuffer_data->alternates); ++i) {
framebuffer_data->alternates[i] = VK_NULL_HANDLE;
}
framebuffer_data->color_attachment_mask = 0;
return framebuffer_data;
}
static struct vk_framebuffer_data *
get_framebuffer_data(struct vk_data *data, VkFramebuffer framebuffer)
{
return (struct vk_framebuffer_data *)get_obj_data(
&data->framebuffers, (uint64_t)framebuffer);
}
static void remove_free_framebuffer_data(struct vk_data *data,
VkFramebuffer framebuffer,
const VkAllocationCallbacks *ac)
{
struct vk_swap_data *const framebuffer_data =
(struct vk_swap_data *)remove_obj_data(&data->swaps,
(uint64_t)framebuffer);
vk_free(ac, framebuffer_data);
}
/* ------------------------------------------------------------------------- */
static struct vk_swap_data *alloc_swap_data(const VkAllocationCallbacks *ac)
{
struct vk_swap_data *const swap_data = vk_alloc(
@@ -1468,6 +1551,8 @@ static VkResult VKAPI_CALL OBS_CreateDevice(VkPhysicalDevice phy_device,
return VK_ERROR_OUT_OF_HOST_MEMORY;
init_obj_list(&data->queues);
init_obj_list(&data->swap_views);
init_obj_list(&data->framebuffers);
/* -------------------------------------------------------- */
/* create device and initialize hook data */
@@ -1502,6 +1587,10 @@ static VkResult VKAPI_CALL OBS_CreateDevice(VkPhysicalDevice phy_device,
funcs_found = false; \
} \
} while (false)
#define GETADDR_OPTIONAL(x) \
do { \
dfuncs->x = (void *)gdpa(device, "vk" #x); \
} while (false)
GETADDR(GetDeviceProcAddr);
GETADDR(DestroyDevice);
@@ -1531,6 +1620,14 @@ static VkResult VKAPI_CALL OBS_CreateDevice(VkPhysicalDevice phy_device,
GETADDR(DestroyFence);
GETADDR(WaitForFences);
GETADDR(ResetFences);
GETADDR(CreateImageView);
GETADDR(DestroyImageView);
GETADDR(CreateFramebuffer);
GETADDR(DestroyFramebuffer);
GETADDR(CmdBeginRenderPass);
GETADDR_OPTIONAL(CmdBeginRenderPass2KHR);
GETADDR_OPTIONAL(CmdBeginRenderPass2);
#undef GETADDR_OPTIONAL
#undef GETADDR
if (!funcs_found) {
@@ -1725,6 +1822,328 @@ OBS_CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *cinfo,
return VK_SUCCESS;
}
static VkResult VKAPI_CALL
OBS_CreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkImageView *pView)
{
struct vk_data *const data = get_device_data(device);
const PFN_vkCreateImageView func = data->funcs.CreateImageView;
VkResult result = func(device, pCreateInfo, pAllocator, pView);
if (data->valid && (result == VK_SUCCESS)) {
struct vk_swap_data *swap = swap_walk_begin(data);
while (swap) {
bool match = false;
for (uint32_t i = 0, count = swap->image_count;
i < count; ++i) {
match = swap->swap_images[i] ==
pCreateInfo->image;
if (match)
break;
}
if (match) {
add_swap_view_data(data, *pView, pAllocator);
break;
}
swap = swap_walk_next(swap);
}
swap_walk_end(data);
}
return result;
}
static void VKAPI_CALL
OBS_DestroyImageView(VkDevice device, VkImageView imageView,
const VkAllocationCallbacks *pAllocator)
{
struct vk_data *const data = get_device_data(device);
if (data->valid && (imageView != VK_NULL_HANDLE)) {
struct vk_swap_view_data *swap_view_data =
get_swap_view_data(data, imageView);
if (swap_view_data)
remove_free_swap_view_data(data, imageView, pAllocator);
}
data->funcs.DestroyImageView(device, imageView, pAllocator);
}
static void generate_framebuffer_variants(
PFN_vkCreateFramebuffer func, VkDevice device,
const VkFramebufferCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
struct vk_framebuffer_data *framebuffer_data,
const VkFramebufferAttachmentsCreateInfo *pAttachmentsCreateInfo,
uint32_t colorCount)
{
const uint32_t variantCount = 1 << colorCount;
for (uint32_t colorMask = 0; colorMask < variantCount; ++colorMask) {
VkImageUsageFlags pPreviousUsage[OBS_COLOR_ATTACHMENT_LIMIT];
uint32_t colorIndex = 0;
for (uint32_t infoIndex = 0,
count = pAttachmentsCreateInfo
->attachmentImageInfoCount;
infoIndex < count; ++infoIndex) {
const VkFramebufferAttachmentImageInfo *const pInfo =
&pAttachmentsCreateInfo
->pAttachmentImageInfos[infoIndex];
const VkImageUsageFlags usage = pInfo->usage;
if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
pPreviousUsage[colorIndex] = usage;
if (colorMask & (1 << colorIndex)) {
((VkFramebufferAttachmentImageInfo *)
pInfo)
->usage |=
VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
++colorIndex;
if (colorIndex == OBS_COLOR_ATTACHMENT_LIMIT)
break;
}
}
VkFramebuffer framebuffer;
const VkResult result =
func(device, pCreateInfo, pAllocator, &framebuffer);
if (result == VK_SUCCESS)
framebuffer_data->alternates[colorMask] = framebuffer;
colorIndex = 0;
for (uint32_t infoIndex = 0,
count = pAttachmentsCreateInfo
->attachmentImageInfoCount;
infoIndex < count; ++infoIndex) {
const VkFramebufferAttachmentImageInfo *const pInfo =
&pAttachmentsCreateInfo
->pAttachmentImageInfos[infoIndex];
if (pInfo->usage &
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
if (colorMask & (1 << colorIndex)) {
((VkFramebufferAttachmentImageInfo *)
pInfo)
->usage =
pPreviousUsage[colorIndex];
}
++colorIndex;
if (colorIndex == OBS_COLOR_ATTACHMENT_LIMIT)
break;
}
}
}
}
static VkResult VKAPI_CALL OBS_CreateFramebuffer(
VkDevice device, const VkFramebufferCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer)
{
struct vk_data *const data = get_device_data(device);
const PFN_vkCreateFramebuffer func = data->funcs.CreateFramebuffer;
VkResult result = func(device, pCreateInfo, pAllocator, pFramebuffer);
if (data->valid && (result == VK_SUCCESS) &&
(pCreateInfo->flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT)) {
struct vk_framebuffer_data *const framebuffer_data =
add_framebuffer_data(data, *pFramebuffer, pAllocator);
const void *pCurrent = pCreateInfo->pNext;
while (pCurrent) {
VkBaseInStructure baseIn;
memcpy(&baseIn, pCurrent, sizeof(baseIn));
if (baseIn.sType ==
VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO) {
uint32_t attachmentMask = 0;
uint32_t colorCount = 0;
const VkFramebufferAttachmentsCreateInfo *const
pAttachmentsCreateInfo = pCurrent;
for (uint32_t
infoIndex = 0,
count = min(
sizeof(attachmentMask) * 8,
pAttachmentsCreateInfo
->attachmentImageInfoCount);
infoIndex < count; ++infoIndex) {
if (pAttachmentsCreateInfo
->pAttachmentImageInfos
[infoIndex]
.usage &
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
attachmentMask |= 1
<< infoIndex;
++colorCount;
if (colorCount ==
OBS_COLOR_ATTACHMENT_LIMIT)
break;
}
}
generate_framebuffer_variants(
func, device, pCreateInfo, pAllocator,
framebuffer_data,
pAttachmentsCreateInfo, colorCount);
framebuffer_data->color_attachment_mask =
attachmentMask;
break;
}
pCurrent = baseIn.pNext;
}
}
return result;
}
static void VKAPI_CALL
OBS_DestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer,
const VkAllocationCallbacks *pAllocator)
{
struct vk_data *const data = get_device_data(device);
struct vk_device_funcs *const funcs = &data->funcs;
if (data->valid && (framebuffer != VK_NULL_HANDLE)) {
struct vk_framebuffer_data *framebuffer_data =
get_framebuffer_data(data, framebuffer);
if (framebuffer_data) {
for (size_t i = 0;
i < _countof(framebuffer_data->alternates); ++i) {
if (framebuffer_data->alternates[i] !=
VK_NULL_HANDLE) {
funcs->DestroyFramebuffer(
device,
framebuffer_data->alternates[i],
pAllocator);
framebuffer_data->alternates[i] =
VK_NULL_HANDLE;
}
}
remove_free_framebuffer_data(data, framebuffer,
pAllocator);
}
}
funcs->DestroyFramebuffer(device, framebuffer, pAllocator);
}
static const VkRenderPassBeginInfo *
process_render_pass_begin_info(const VkRenderPassBeginInfo *pRenderPassBegin,
VkRenderPassBeginInfo *pAlternateBegin,
struct vk_data *data)
{
const void *pCurrent = pRenderPassBegin->pNext;
while (pCurrent) {
VkBaseInStructure baseIn;
memcpy(&baseIn, pCurrent, sizeof(baseIn));
if (baseIn.sType ==
VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO) {
struct vk_framebuffer_data *const framebuffer_data =
get_framebuffer_data(
data, pRenderPassBegin->framebuffer);
if (framebuffer_data) {
const VkRenderPassAttachmentBeginInfo
*const pAttachmentInfo = pCurrent;
uint32_t swapMask = 0;
uint32_t colorIndex = 0;
for (uint32_t infoIndex = 0,
count = pAttachmentInfo
->attachmentCount;
infoIndex < count; ++infoIndex) {
if (framebuffer_data
->color_attachment_mask &
(1 << infoIndex)) {
if (get_swap_view_data(
data,
pAttachmentInfo->pAttachments
[infoIndex])) {
swapMask |=
1 << colorIndex;
}
++colorIndex;
if (colorIndex ==
OBS_COLOR_ATTACHMENT_LIMIT)
break;
}
}
if (swapMask > 0) {
VkFramebuffer alternate =
framebuffer_data
->alternates[swapMask];
if (alternate != VK_NULL_HANDLE) {
*pAlternateBegin =
*pRenderPassBegin;
pAlternateBegin->framebuffer =
framebuffer_data->alternates
[swapMask];
pRenderPassBegin =
pAlternateBegin;
}
}
}
break;
}
pCurrent = baseIn.pNext;
}
return pRenderPassBegin;
}
static void VKAPI_CALL
OBS_CmdBeginRenderPass(VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo *pRenderPassBegin,
VkSubpassContents contents)
{
struct vk_data *const data =
get_device_data_by_command_buffer(commandBuffer);
if (data->valid) {
VkRenderPassBeginInfo alternateBegin;
pRenderPassBegin = process_render_pass_begin_info(
pRenderPassBegin, &alternateBegin, data);
}
data->funcs.CmdBeginRenderPass(commandBuffer, pRenderPassBegin,
contents);
}
static void VKAPI_CALL
OBS_CmdBeginRenderPass2KHR(VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo *pRenderPassBegin,
const VkSubpassBeginInfo *pSubpassBeginInfo)
{
struct vk_data *const data =
get_device_data_by_command_buffer(commandBuffer);
if (data->valid) {
VkRenderPassBeginInfo alternateBegin;
pRenderPassBegin = process_render_pass_begin_info(
pRenderPassBegin, &alternateBegin, data);
}
data->funcs.CmdBeginRenderPass2KHR(commandBuffer, pRenderPassBegin,
pSubpassBeginInfo);
}
static void VKAPI_CALL
OBS_CmdBeginRenderPass2(VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo *pRenderPassBegin,
const VkSubpassBeginInfo *pSubpassBeginInfo)
{
struct vk_data *const data =
get_device_data_by_command_buffer(commandBuffer);
if (data->valid) {
VkRenderPassBeginInfo alternateBegin;
pRenderPassBegin = process_render_pass_begin_info(
pRenderPassBegin, &alternateBegin, data);
}
data->funcs.CmdBeginRenderPass2(commandBuffer, pRenderPassBegin,
pSubpassBeginInfo);
}
static void VKAPI_CALL OBS_DestroySwapchainKHR(VkDevice device,
VkSwapchainKHR sc,
const VkAllocationCallbacks *ac)
@@ -1797,6 +2216,13 @@ static PFN_vkVoidFunction VKAPI_CALL OBS_GetDeviceProcAddr(VkDevice device,
GETPROCADDR_IF_SUPPORTED(CreateSwapchainKHR);
GETPROCADDR_IF_SUPPORTED(DestroySwapchainKHR);
GETPROCADDR_IF_SUPPORTED(QueuePresentKHR);
GETPROCADDR(CreateImageView);
GETPROCADDR(DestroyImageView);
GETPROCADDR(CreateFramebuffer);
GETPROCADDR(DestroyFramebuffer);
GETPROCADDR(CmdBeginRenderPass);
GETPROCADDR_IF_SUPPORTED(CmdBeginRenderPass2KHR);
GETPROCADDR_IF_SUPPORTED(CmdBeginRenderPass2);
if (funcs->GetDeviceProcAddr == NULL)
return NULL;
@@ -42,6 +42,13 @@ struct vk_device_funcs {
DEF_FUNC(DestroyFence);
DEF_FUNC(WaitForFences);
DEF_FUNC(ResetFences);
DEF_FUNC(CreateImageView);
DEF_FUNC(DestroyImageView);
DEF_FUNC(CreateFramebuffer);
DEF_FUNC(DestroyFramebuffer);
DEF_FUNC(CmdBeginRenderPass);
DEF_FUNC(CmdBeginRenderPass2KHR);
DEF_FUNC(CmdBeginRenderPass2);
};
#undef DEF_FUNC