[vulkan] Create a staging buffer struct

And move the barrier prefabs into a more convenient place.
This commit is contained in:
Bill Currie 2021-01-11 01:24:15 +09:00
parent ba6450d0b4
commit 23db917ec4
9 changed files with 243 additions and 71 deletions

View file

@ -0,0 +1,21 @@
#ifndef __QF_Vulkan_barrier_h
#define __QF_Vulkan_barrier_h
typedef struct {
VkPipelineStageFlags src;
VkPipelineStageFlags dst;
} qfv_pipelinestagepair_t;
//XXX Note: imageLayoutTransitionBarriers, imageLayoutTransitionStages and
// the enum must be kept in sync
enum {
qfv_LT_Undefined_to_TransferDst,
qfv_LT_TransferDst_to_ShaderReadOnly,
qfv_LT_Undefined_to_DepthStencil,
qfv_LT_Undefined_to_Color,
};
extern const VkImageMemoryBarrier imageLayoutTransitionBarriers[];
extern const qfv_pipelinestagepair_t imageLayoutTransitionStages[];
#endif//__QF_Vulkan_barrier_h

View file

@ -45,5 +45,6 @@ void Vulkan_CreateSwapchain (struct vulkan_ctx_s *ctx);
void Vulkan_CreateDevice (struct vulkan_ctx_s *ctx);
void Vulkan_Init_Common (struct vulkan_ctx_s *ctx);
void Vulkan_Shutdown_Common (struct vulkan_ctx_s *ctx);
void Vulkan_CreateStagingBuffers (struct vulkan_ctx_s *ctx);
#endif // __QF_Vulkan_vid_h

View file

@ -0,0 +1,18 @@
#ifndef __QF_Vulkan_staging_h
#define __QF_Vulkan_staging_h
typedef struct qfv_stagebuf_s {
struct qfv_device_s *device;
VkBuffer buffer;
VkDeviceMemory memory;
size_t size;
void *data;
} qfv_stagebuf_t;
qfv_stagebuf_t *QFV_CreateStagingBuffer (struct qfv_device_s *device,
size_t size);
void QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage);
void QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size);
#endif//__QF_Vulkan_staging_h

View file

@ -57,6 +57,7 @@ typedef struct vulkan_ctx_s {
VkCommandBuffer cmdbuffer;
VkFence fence; // for ctx->cmdbuffer only
vulkan_renderpass_t renderpass;
struct qfv_stagebuf_s *staging[2];
VkPipeline pipeline;
size_t curFrame;
vulkan_framebufferset_t framebuffers;

View file

@ -215,6 +215,7 @@ libs_video_renderer_vid_render_vulkan_la_DEPENDENCIES=$(vulkan_libs)
libs_video_renderer_vid_render_vulkan_la_SOURCES = \
$(video_renderer_common_sources) \
libs/video/renderer/vid_render_vulkan.c \
libs/video/renderer/vulkan/barrier.c \
libs/video/renderer/vulkan/buffer.c \
libs/video/renderer/vulkan/command.c \
libs/video/renderer/vulkan/descriptor.c \
@ -226,6 +227,7 @@ libs_video_renderer_vid_render_vulkan_la_SOURCES = \
libs/video/renderer/vulkan/pipeline.c \
libs/video/renderer/vulkan/renderpass.c \
libs/video/renderer/vulkan/shader.c \
libs/video/renderer/vulkan/staging.c \
libs/video/renderer/vulkan/swapchain.c \
libs/video/renderer/vulkan/util.c \
libs/video/renderer/vulkan/util.h \

View file

@ -62,6 +62,7 @@ vulkan_R_Init (void)
qfv_device_t *device = vulkan_ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
Vulkan_CreateStagingBuffers (vulkan_ctx);
Vulkan_CreateSwapchain (vulkan_ctx);
Vulkan_CreateRenderPass (vulkan_ctx);
Vulkan_CreateFramebuffers (vulkan_ctx);

View file

@ -0,0 +1,92 @@
/*
barrier.c
Memory barrier helpers
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/barrier.h"
const VkImageMemoryBarrier imageLayoutTransitionBarriers[] = {
// undefined -> transfer dst optimal
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
// transfer dst optimal -> shader read only optimal
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
// undefined -> depth stencil attachment optimal
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
0,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 }
},
// undefined -> color attachment optimal
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
0,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
{ /* end of transition barriers */ }
};
const qfv_pipelinestagepair_t imageLayoutTransitionStages[] = {
// undefined -> transfer dst optimal
{ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT },
// preinitialized -> shader read only optimal
{ VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT },
// transfer dst optimal -> shader read only optimal
{ VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT },
// undefined -> depth stencil attachment optimal
{ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT },
// undefined -> color attachment optimal
{ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT },
};

View file

@ -0,0 +1,96 @@
/*
shader.c
Vulkan shader manager
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_MATH_H
# include <math.h>
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include "QF/alloc.h"
#include "QF/cvar.h"
#include "QF/dstring.h"
#include "QF/hash.h"
#include "QF/qfplist.h"
#include "QF/quakefs.h"
#include "QF/sys.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/buffer.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/staging.h"
#include "vid_vulkan.h"
qfv_stagebuf_t *
QFV_CreateStagingBuffer (qfv_device_t *device, size_t size)
{
qfv_devfuncs_t *dfunc = device->funcs;
qfv_stagebuf_t *stage = malloc (sizeof (qfv_stagebuf_t));
stage->device = device;
stage->buffer = QFV_CreateBuffer (device, size,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
stage->memory = QFV_AllocBufferMemory (device, stage->buffer,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
size, 0);
QFV_BindBufferMemory (device, stage->buffer, stage->memory, 0);
dfunc->vkMapMemory (device->dev, stage->memory, 0, size, 0, &stage->data);
return stage;
}
void
QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage)
{
qfv_device_t *device = stage->device;
qfv_devfuncs_t *dfunc = device->funcs;
dfunc->vkUnmapMemory (device->dev, stage->memory);
dfunc->vkFreeMemory (device->dev, stage->memory, 0);
dfunc->vkDestroyBuffer (device->dev, stage->buffer, 0);
free (stage);
}
void
QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size)
{
qfv_device_t *device = stage->device;
qfv_devfuncs_t *dfunc = device->funcs;
VkMappedMemoryRange range = {
VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0,
stage->memory, offset, size
};
dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range);
}

View file

@ -53,6 +53,7 @@
#include "QF/va.h"
#include "QF/vid.h"
#include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/barrier.h"
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/command.h"
@ -61,6 +62,7 @@
#include "QF/Vulkan/pipeline.h"
#include "QF/Vulkan/renderpass.h"
#include "QF/Vulkan/shader.h"
#include "QF/Vulkan/staging.h"
#include "QF/Vulkan/swapchain.h"
#include "compat.h"
@ -171,6 +173,8 @@ Vulkan_Shutdown_Common (vulkan_ctx_t *ctx)
if (ctx->swapchain) {
QFV_DestroySwapchain (ctx->swapchain);
}
QFV_DestroyStagingBuffer (ctx->staging[0]);
QFV_DestroyStagingBuffer (ctx->staging[1]);
ctx->instance->funcs->vkDestroySurfaceKHR (ctx->instance->instance,
ctx->surface, 0);
clear_table (&ctx->pipelineLayouts);
@ -194,6 +198,13 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx)
ctx->device = QFV_CreateDevice (ctx, device_extensions);
}
void
Vulkan_CreateStagingBuffers (vulkan_ctx_t *ctx)
{
ctx->staging[0] = QFV_CreateStagingBuffer (ctx->device, 1024*1024);
ctx->staging[1] = QFV_CreateStagingBuffer (ctx->device, 1024*1024);
}
void
Vulkan_CreateSwapchain (vulkan_ctx_t *ctx)
{
@ -209,77 +220,6 @@ Vulkan_CreateSwapchain (vulkan_ctx_t *ctx)
}
}
typedef struct {
VkPipelineStageFlags src;
VkPipelineStageFlags dst;
} qfv_pipelinestagepair_t;
//XXX Note: imageLayoutTransitionBarriers, imageLayoutTransitionStages and
// the enum be kept in sync
enum {
qfv_LT_Undefined_to_TransferDst,
qfv_LT_TransferDst_to_ShaderReadOnly,
qfv_LT_Undefined_to_DepthStencil,
qfv_LT_Undefined_to_Color,
};
static VkImageMemoryBarrier imageLayoutTransitionBarriers[] = {
// undefined -> transfer dst optimal
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
// transfer dst optimal -> shader read only optimal
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
// undefined -> depth stencil attachment optimal
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
0,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT
| VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 }
},
// undefined -> color attachment optimal
{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
0,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, 0,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
},
{ /* end of transition barriers */ }
};
static qfv_pipelinestagepair_t imageLayoutTransitionStages[] = {
// undefined -> transfer dst optimal
{ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT },
// transfer dst optimal -> shader read only optimal
{ VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT },
// undefined -> depth stencil attachment optimal
{ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT },
// undefined -> color attachment optimal
{ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT },
};
static void
qfv_load_pipeline (vulkan_ctx_t *ctx)
{