From 23db917ec4efea4b2964009c95579b1ed766cd4e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 11 Jan 2021 01:24:15 +0900 Subject: [PATCH] [vulkan] Create a staging buffer struct And move the barrier prefabs into a more convenient place. --- include/QF/Vulkan/barrier.h | 21 ++++ include/QF/Vulkan/qf_vid.h | 1 + include/QF/Vulkan/staging.h | 18 ++++ include/vid_vulkan.h | 1 + libs/video/renderer/Makemodule.am | 2 + libs/video/renderer/vid_render_vulkan.c | 1 + libs/video/renderer/vulkan/barrier.c | 92 ++++++++++++++++++ libs/video/renderer/vulkan/staging.c | 96 +++++++++++++++++++ .../video/renderer/vulkan/vulkan_vid_common.c | 82 +++------------- 9 files changed, 243 insertions(+), 71 deletions(-) create mode 100644 include/QF/Vulkan/barrier.h create mode 100644 include/QF/Vulkan/staging.h create mode 100644 libs/video/renderer/vulkan/barrier.c create mode 100644 libs/video/renderer/vulkan/staging.c diff --git a/include/QF/Vulkan/barrier.h b/include/QF/Vulkan/barrier.h new file mode 100644 index 000000000..12cea49ab --- /dev/null +++ b/include/QF/Vulkan/barrier.h @@ -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 diff --git a/include/QF/Vulkan/qf_vid.h b/include/QF/Vulkan/qf_vid.h index f859d93f2..d5f59cc84 100644 --- a/include/QF/Vulkan/qf_vid.h +++ b/include/QF/Vulkan/qf_vid.h @@ -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 diff --git a/include/QF/Vulkan/staging.h b/include/QF/Vulkan/staging.h new file mode 100644 index 000000000..d281f1854 --- /dev/null +++ b/include/QF/Vulkan/staging.h @@ -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 diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index 0bc8d629d..05e127825 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -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; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 1d6c5eaea..36b013d97 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -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 \ diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index f84f9eb84..64d8f3766 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -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); diff --git a/libs/video/renderer/vulkan/barrier.c b/libs/video/renderer/vulkan/barrier.c new file mode 100644 index 000000000..c7c1f21a3 --- /dev/null +++ b/libs/video/renderer/vulkan/barrier.c @@ -0,0 +1,92 @@ +/* + barrier.c + + Memory barrier helpers + + Copyright (C) 2021 Bill Currie + + 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 }, +}; diff --git a/libs/video/renderer/vulkan/staging.c b/libs/video/renderer/vulkan/staging.c new file mode 100644 index 000000000..de791239c --- /dev/null +++ b/libs/video/renderer/vulkan/staging.c @@ -0,0 +1,96 @@ +/* + shader.c + + Vulkan shader manager + + Copyright (C) 2021 Bill Currie + + 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 +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#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); +} diff --git a/libs/video/renderer/vulkan/vulkan_vid_common.c b/libs/video/renderer/vulkan/vulkan_vid_common.c index c2b17d0fe..c230955dc 100644 --- a/libs/video/renderer/vulkan/vulkan_vid_common.c +++ b/libs/video/renderer/vulkan/vulkan_vid_common.c @@ -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) {