diff --git a/include/QF/Vulkan/qf_particles.h b/include/QF/Vulkan/qf_particles.h index 4e2c7f0b6..26feb51fb 100644 --- a/include/QF/Vulkan/qf_particles.h +++ b/include/QF/Vulkan/qf_particles.h @@ -21,6 +21,14 @@ typedef struct qfv_parameters_s { vec4f_t ramp; } qfv_parameters_t; +// Doubles as VkDrawIndirectCommand +typedef struct qfv_particle_system_s { + uint32_t vertexCount; // always 1 + uint32_t particleCount; + uint32_t firstVertex; // always 0 + uint32_t firstInstance; // always 0 +} qfv_particle_system_t; + typedef enum { QFV_particleTranslucent, @@ -50,6 +58,9 @@ typedef struct particlectx_s { VkPipeline update; VkPipeline draw; + VkDeviceMemory memory; + struct qfv_stagebuf_s *stage; + VkDescriptorPool pool; VkDescriptorSetLayout setLayout; VkPipelineLayout physics_layout; diff --git a/libs/video/renderer/vulkan/deferred.plist b/libs/video/renderer/vulkan/deferred.plist index 087710d8c..1eade9e2e 100644 --- a/libs/video/renderer/vulkan/deferred.plist +++ b/libs/video/renderer/vulkan/deferred.plist @@ -432,6 +432,14 @@ dstAccessMask = input_attachment_read|depth_stencil_attachment_read; dependencyFlags = by_region; }, + { + srcSubpass = ~0u; // external + dstSubpass = 1; // translucent + srcStageMask = compute_shader; + dstStageMask = vertex_input|draw_indirect; + srcAccessMask = shader_write; + dstAccessMask = vertex_attribute_read|indirect_command_read; + }, { srcSubpass = 0; // depth dstSubpass = 2; // g-buffer diff --git a/libs/video/renderer/vulkan/vulkan_particles.c b/libs/video/renderer/vulkan/vulkan_particles.c index 14a98df44..461c01c91 100644 --- a/libs/video/renderer/vulkan/vulkan_particles.c +++ b/libs/video/renderer/vulkan/vulkan_particles.c @@ -44,14 +44,20 @@ #include "QF/plugin/vid_render.h" +#include "QF/Vulkan/qf_vid.h" //FIXME header issues +#include "QF/Vulkan/buffer.h" #include "QF/Vulkan/debug.h" #include "QF/Vulkan/device.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/staging.h" #include "QF/Vulkan/qf_particles.h" #include "r_internal.h" #include "vid_vulkan.h" +//FIXME make dynamic +#define MaxParticles 2048 + static const char * __attribute__((used)) particle_pass_names[] = { "draw", }; @@ -61,6 +67,57 @@ Vulkan_DrawParticles (vulkan_ctx_t *ctx) { } +static void +create_buffers (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + particlectx_t *pctx = ctx->particle_context; + size_t size = 0; + size_t mp = MaxParticles; + + VkMemoryRequirements stReq, parmReq, sysReq; + for (size_t i = 0; i < pctx->frames.size; i++) { + __auto_type pframe = &pctx->frames.a[i]; + pframe->state + = QFV_CreateBuffer (device, sizeof (qfv_particle_t) * mp, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + pframe->params + = QFV_CreateBuffer (device, sizeof (qfv_particle_t) * mp, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + pframe->system + = QFV_CreateBuffer (device, sizeof (qfv_particle_t) * mp, + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); + dfunc->vkGetBufferMemoryRequirements (device->dev, pframe->state, + &stReq); + dfunc->vkGetBufferMemoryRequirements (device->dev, pframe->params, + &parmReq); + dfunc->vkGetBufferMemoryRequirements (device->dev, pframe->system, + &sysReq); + size = QFV_NextOffset (size + stReq.size, &stReq); + size = QFV_NextOffset (size + parmReq.size, &parmReq); + size = QFV_NextOffset (size + sysReq.size, &sysReq); + } + size_t stageSize = (size / pctx->frames.size)*(pctx->frames.size + 1); + pctx->stage = QFV_CreateStagingBuffer (device, "particles", stageSize, + ctx->cmdpool); + pctx->memory = QFV_AllocBufferMemory (device, pctx->frames.a[0].state, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + size, 0); + size_t offset = 0; + for (size_t i = 0; i < pctx->frames.size; i++) { + __auto_type pframe = &pctx->frames.a[i]; + QFV_BindBufferMemory (device, pframe->state, pctx->memory, offset); + offset = QFV_NextOffset (offset + stReq.size, &parmReq); + QFV_BindBufferMemory (device, pframe->params, pctx->memory, offset); + offset = QFV_NextOffset (offset + parmReq.size, &sysReq); + QFV_BindBufferMemory (device, pframe->system, pctx->memory, offset); + offset = QFV_NextOffset (offset + sysReq.size, &stReq); + } +} + void Vulkan_Particles_Init (vulkan_ctx_t *ctx) { @@ -83,7 +140,7 @@ Vulkan_Particles_Init (vulkan_ctx_t *ctx) "partphysics_layout"); pctx->update_layout = Vulkan_CreatePipelineLayout (ctx, "partupdate_layout"); - pctx->draw_layout = Vulkan_CreatePipelineLayout (ctx, "draw_layout"); + pctx->draw_layout = Vulkan_CreatePipelineLayout (ctx, "partdraw_layout"); pctx->pool = Vulkan_CreateDescriptorPool (ctx, "particle_pool"); pctx->setLayout = Vulkan_CreateDescriptorSetLayout (ctx, "particle_set"); @@ -104,6 +161,7 @@ Vulkan_Particles_Init (vulkan_ctx_t *ctx) particle_pass_names[j])); } } + create_buffers (ctx); qfvPopDebug (ctx); } @@ -117,7 +175,12 @@ Vulkan_Particles_Shutdown (vulkan_ctx_t *ctx) for (size_t i = 0; i < pctx->frames.size; i++) { __auto_type pframe = &pctx->frames.a[i]; free (pframe->cmdSet.a); + dfunc->vkDestroyBuffer (device->dev, pframe->state, 0); + dfunc->vkDestroyBuffer (device->dev, pframe->params, 0); + dfunc->vkDestroyBuffer (device->dev, pframe->system, 0); } + dfunc->vkFreeMemory (device->dev, pctx->memory, 0); + QFV_DestroyStagingBuffer (pctx->stage); dfunc->vkDestroyPipeline (device->dev, pctx->physics, 0); dfunc->vkDestroyPipeline (device->dev, pctx->update, 0);