diff --git a/include/QF/Makemodule.am b/include/QF/Makemodule.am index 64a9c3cc0..875262cf6 100644 --- a/include/QF/Makemodule.am +++ b/include/QF/Makemodule.am @@ -197,6 +197,7 @@ include_qf_vulkan = \ include/QF/Vulkan/qf_matrices.h \ include/QF/Vulkan/qf_model.h \ include/QF/Vulkan/qf_particles.h \ + include/QF/Vulkan/qf_scene.h \ include/QF/Vulkan/qf_sprite.h \ include/QF/Vulkan/qf_texture.h \ include/QF/Vulkan/qf_vid.h \ diff --git a/include/QF/Vulkan/qf_bsp.h b/include/QF/Vulkan/qf_bsp.h index d5b3137de..c55d1aec9 100644 --- a/include/QF/Vulkan/qf_bsp.h +++ b/include/QF/Vulkan/qf_bsp.h @@ -99,6 +99,8 @@ typedef struct bsp_instfaceset_s typedef struct bsp_pass_s { uint32_t *indices; // points into index buffer uint32_t index_count; // number of indices written to buffer + uint32_t *entid_data; + uint32_t entid_count; int vis_frame; int *face_frames; int *leaf_frames; @@ -132,9 +134,12 @@ typedef enum { } QFV_BspSubpass; typedef struct bspframe_s { - uint32_t *index_data; // pointer into mega-buffer for this frame (c) - uint32_t index_offset; // offset of index_data within mega-buffer (c) - uint32_t index_count; // number if indices queued (d) + uint32_t *index_data; // pointer into mega-buffer for this frame (c) + uint32_t index_offset; // offset of index_data within mega-buffer (c) + uint32_t index_count; // number if indices queued (d) + uint32_t *entid_data; + uint32_t entid_offset; + uint32_t entid_count; qfv_cmdbufferset_t cmdSet; } bspframe_t; @@ -142,9 +147,6 @@ typedef struct bspframeset_s DARRAY_TYPE (bspframe_t) bspframeset_t; typedef struct bspctx_s { - struct entity_s *entity; - vec_t *transform; - float *color; uint32_t inst_id; regtexset_t registered_textures; @@ -182,6 +184,8 @@ typedef struct bspctx_s { VkDeviceMemory vertex_memory; VkBuffer index_buffer; VkDeviceMemory index_memory; + VkBuffer entid_buffer; + VkDeviceMemory entid_memory; bspframeset_t frames; } bspctx_t; diff --git a/include/QF/Vulkan/qf_scene.h b/include/QF/Vulkan/qf_scene.h new file mode 100644 index 000000000..654c6fa58 --- /dev/null +++ b/include/QF/Vulkan/qf_scene.h @@ -0,0 +1,80 @@ +/* + qf_scene.h + + Vulkan specific scene stuff + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/5/24 + + 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 + +*/ +#ifndef __QF_Vulkan_qf_scene_h +#define __QF_Vulkan_qf_scene_h + +#ifndef VK_NO_PROTOTYPES +#define VK_NO_PROTOTYPES +#endif +#include + +#include "QF/darray.h" +#include "QF/simd/types.h" + +typedef struct entdata_s { + // transpose of entity transform matrix without row 4 + vec4f_t xform[3]; + vec4f_t color; +} entdata_t; + +typedef struct entdataset_s + DARRAY_TYPE (entdata_t) entdataset_t; + +typedef struct scnframe_s { + // used to check if the entity has been pooled this frame (cleared + // every frame) + struct set_s *pooled_entities; + // data for entities pooled this frame (cleared every frame). transfered + // to gpu + entdataset_t entity_pool; + VkDescriptorSet descriptors; +} scnframe_t; + +typedef struct scnframeset_s + DARRAY_TYPE (scnframe_t) scnframeset_t; + +typedef struct scenectx_s { + struct qfv_resource_s *entities; + scnframeset_t frames; + VkDescriptorPool pool; + VkDescriptorSetLayout setLayout; + int max_entities; +} scenectx_t; + +struct vulkan_ctx_s; +struct entity_s; + +void Vulkan_Scene_Init (struct vulkan_ctx_s *ctx); +void Vulkan_Scene_Shutdown (struct vulkan_ctx_s *ctx); +int Vulkan_Scene_MaxEntities (struct vulkan_ctx_s *ctx) __attribute__((pure)); +VkDescriptorSet Vulkan_Scene_Descriptors (struct vulkan_ctx_s *ctx) __attribute__((pure)); +int Vulkan_Scene_AddEntity (struct vulkan_ctx_s *ctx, struct entity_s *entity); + +#endif//__QF_Vulkan_qf_scene_h diff --git a/include/QF/scene/entity.h b/include/QF/scene/entity.h index 6aadfab65..770033f64 100644 --- a/include/QF/scene/entity.h +++ b/include/QF/scene/entity.h @@ -73,6 +73,7 @@ typedef struct renderer_s { int skinnum; // for Alias models int fullbright; float min_light; + int render_id; mat4_t full_transform; } renderer_t; diff --git a/include/vid_vulkan.h b/include/vid_vulkan.h index c3610bb0b..749047e24 100644 --- a/include/vid_vulkan.h +++ b/include/vid_vulkan.h @@ -68,6 +68,7 @@ typedef struct vulkan_ctx_s { struct aliasctx_s *alias_context; struct bspctx_s *bsp_context; struct iqmctx_s *iqm_context; + struct scenectx_s *scene_context; struct particlectx_s *particle_context; struct spritectx_s *sprite_context; struct drawctx_s *draw_context; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index d164eb5f3..6a52b1af4 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -227,6 +227,7 @@ libs_video_renderer_librender_vulkan_la_SOURCES = \ libs/video/renderer/vulkan/vulkan_main.c \ libs/video/renderer/vulkan/vulkan_matrices.c \ libs/video/renderer/vulkan/vulkan_particles.c \ + libs/video/renderer/vulkan/vulkan_scene.c \ libs/video/renderer/vulkan/vulkan_sprite.c \ libs/video/renderer/vulkan/vulkan_texture.c \ libs/video/renderer/vulkan/vulkan_vid_common.c diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index a727cbf26..6e66fdc54 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -50,6 +50,7 @@ #include "QF/Vulkan/qf_main.h" #include "QF/Vulkan/qf_matrices.h" #include "QF/Vulkan/qf_particles.h" +#include "QF/Vulkan/qf_scene.h" #include "QF/Vulkan/qf_sprite.h" #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/qf_vid.h" @@ -92,6 +93,7 @@ vulkan_R_Init (void) Vulkan_Texture_Init (vulkan_ctx); Vulkan_Matrix_Init (vulkan_ctx); + Vulkan_Scene_Init (vulkan_ctx); Vulkan_Alias_Init (vulkan_ctx); Vulkan_Bsp_Init (vulkan_ctx); Vulkan_IQM_Init (vulkan_ctx); @@ -705,6 +707,7 @@ vulkan_vid_render_shutdown (void) Vulkan_IQM_Shutdown (vulkan_ctx); Vulkan_Bsp_Shutdown (vulkan_ctx); Vulkan_Alias_Shutdown (vulkan_ctx); + Vulkan_Scene_Shutdown (vulkan_ctx); Vulkan_Matrix_Shutdown (vulkan_ctx); Vulkan_Texture_Shutdown (vulkan_ctx); diff --git a/libs/video/renderer/vulkan/qfpipeline.plist b/libs/video/renderer/vulkan/qfpipeline.plist index 24ccdf848..9c16a5556 100644 --- a/libs/video/renderer/vulkan/qfpipeline.plist +++ b/libs/video/renderer/vulkan/qfpipeline.plist @@ -97,6 +97,16 @@ }, ); }; + entity_pool = { + flags = free_descriptor_set; + maxSets = 512; + bindings = ( + { + type = storage_buffer; + descriptorCount = $properties.descriptorPools.entity_pool.maxSets; + }, + ); + }; bone_pool = { flags = free_descriptor_set; maxSets = 512; @@ -216,6 +226,16 @@ }, ); }; + entity_set = { + bindings = ( + { + binding = 0; + descriptorType = storage_buffer; + descriptorCount = 1; + stageFlags = vertex; + }, + ); + }; bone_set = { bindings = ( { @@ -340,16 +360,11 @@ setLayouts = (matrix_set, twod_set); }; quakebsp_layout = { - setLayouts = (matrix_set, texture_set, texture_set); + setLayouts = (matrix_set, entity_set, texture_set, texture_set); pushConstantRanges = ( - { - stageFlags = vertex; - offset = 0; - size = "16 * 4"; - }, { stageFlags = fragment; - offset = 64; + offset = 0; size = "4 * 4 + 4 + 4"; }, ); @@ -499,10 +514,12 @@ brush = { bindings = ( { binding = 0; stride = "2 * 4 * 4"; inputRate = vertex; }, + { binding = 1; stride = "4"; inputRate = instance; }, ); attributes = ( { location = 0; binding = 0; format = r32g32b32a32_sfloat; offset = 0; }, { location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; }, + { location = 2; binding = 1; format = r32_uint; offset = 0; }, ); }; iqm = { @@ -786,9 +803,11 @@ vertexInput = { bindings = ( "$properties.vertexInput.brush.bindings[0]", + "$properties.vertexInput.brush.bindings[1]", ); attributes = ( "$properties.vertexInput.brush.attributes[0]", + "$properties.vertexInput.brush.attributes[2]", ); }; inputAssembly = $properties.inputAssembly.brush; diff --git a/libs/video/renderer/vulkan/shader/bsp_depth.vert b/libs/video/renderer/vulkan/shader/bsp_depth.vert index 8ee96735f..14f5e802e 100644 --- a/libs/video/renderer/vulkan/shader/bsp_depth.vert +++ b/libs/video/renderer/vulkan/shader/bsp_depth.vert @@ -1,4 +1,7 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable + +#include "entity.h" layout (set = 0, binding = 0) uniform Matrices { mat4 Projection3d; @@ -7,14 +10,16 @@ layout (set = 0, binding = 0) uniform Matrices { mat4 Projection2d; }; -layout (push_constant) uniform PushConstants { - mat4 Model; +layout (set = 1, binding = 0) buffer Entities { + Entity entities[]; }; layout (location = 0) in vec4 vertex; +layout (location = 2) in uint entid; void main (void) { - gl_Position = Projection3d * (View * (Model * vertex)); + vec3 vert = vertex * entities[entid].transform; + gl_Position = Projection3d * (View * vec4 (vert, 1)); } diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.frag b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag index b09d7232b..f807f52a2 100644 --- a/libs/video/renderer/vulkan/shader/bsp_gbuf.frag +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.frag @@ -1,9 +1,8 @@ #version 450 -layout (set = 1, binding = 0) uniform sampler2DArray Texture; +layout (set = 2, binding = 0) uniform sampler2DArray Texture; layout (push_constant) uniform PushConstants { - layout (offset = 64) vec4 fog; float time; float alpha; diff --git a/libs/video/renderer/vulkan/shader/bsp_gbuf.vert b/libs/video/renderer/vulkan/shader/bsp_gbuf.vert index 7b80384c5..b5866d8b6 100644 --- a/libs/video/renderer/vulkan/shader/bsp_gbuf.vert +++ b/libs/video/renderer/vulkan/shader/bsp_gbuf.vert @@ -1,4 +1,7 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable + +#include "entity.h" layout (set = 0, binding = 0) uniform Matrices { mat4 Projection3d; @@ -7,12 +10,13 @@ layout (set = 0, binding = 0) uniform Matrices { mat4 Projection2d; }; -layout (push_constant) uniform PushConstants { - mat4 Model; +layout (set = 1, binding = 0) buffer Entities { + Entity entities[]; }; layout (location = 0) in vec4 vertex; layout (location = 1) in vec4 tl_uv; +layout (location = 2) in uint entid; layout (location = 0) out vec4 tl_st; layout (location = 1) out vec3 direction; @@ -21,7 +25,8 @@ void main (void) { // geometry shader will take care of Projection and View - gl_Position = Model * vertex; + vec3 vert = vertex * entities[entid].transform; + gl_Position = vec4 (vert, 1); direction = (Sky * vertex).xyz; tl_st = tl_uv; } diff --git a/libs/video/renderer/vulkan/shader/bsp_shadow.vert b/libs/video/renderer/vulkan/shader/bsp_shadow.vert index f80dfd673..ea1dfb8d6 100644 --- a/libs/video/renderer/vulkan/shader/bsp_shadow.vert +++ b/libs/video/renderer/vulkan/shader/bsp_shadow.vert @@ -1,16 +1,21 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable -layout (push_constant) uniform PushConstants { - mat4 Model; +#include "entity.h" + +layout (set = 1, binding = 0) buffer Entities { + Entity entities[]; }; layout (location = 0) in vec4 vertex; +layout (location = 2) in uint entid; layout (location = 0) out int InstanceIndex; void main (void) { - gl_Position = Model * vertex; + vec3 vert = vertex * entities[entid].transform; + gl_Position = vec4 (vert, 1);; InstanceIndex = gl_InstanceIndex; } diff --git a/libs/video/renderer/vulkan/shader/bsp_sky.frag b/libs/video/renderer/vulkan/shader/bsp_sky.frag index 1734b5b12..897310930 100644 --- a/libs/video/renderer/vulkan/shader/bsp_sky.frag +++ b/libs/video/renderer/vulkan/shader/bsp_sky.frag @@ -3,11 +3,10 @@ layout (constant_id = 0) const bool doSkyBox = false; layout (constant_id = 1) const bool doSkySheet = false; -layout (set = 1, binding = 0) uniform sampler2DArray SkySheet; -layout (set = 2, binding = 0) uniform samplerCube SkyBox; +layout (set = 2, binding = 0) uniform sampler2DArray SkySheet; +layout (set = 3, binding = 0) uniform samplerCube SkyBox; layout (push_constant) uniform PushConstants { - layout (offset = 64) vec4 fog; float time; float alpha; diff --git a/libs/video/renderer/vulkan/shader/bsp_turb.frag b/libs/video/renderer/vulkan/shader/bsp_turb.frag index 1c78dde73..fdc7dfc10 100644 --- a/libs/video/renderer/vulkan/shader/bsp_turb.frag +++ b/libs/video/renderer/vulkan/shader/bsp_turb.frag @@ -1,9 +1,8 @@ #version 450 -layout (set = 1, binding = 0) uniform sampler2DArray Texture; +layout (set = 2, binding = 0) uniform sampler2DArray Texture; layout (push_constant) uniform PushConstants { - layout (offset = 64) vec4 fog; float time; float alpha; diff --git a/libs/video/renderer/vulkan/shader/entity.h b/libs/video/renderer/vulkan/shader/entity.h new file mode 100644 index 000000000..0da5a9d27 --- /dev/null +++ b/libs/video/renderer/vulkan/shader/entity.h @@ -0,0 +1,4 @@ +struct Entity { + mat3x4 transform; + vec4 color; +}; diff --git a/libs/video/renderer/vulkan/shader/quakebsp.frag b/libs/video/renderer/vulkan/shader/quakebsp.frag index 21a93d530..750395c83 100644 --- a/libs/video/renderer/vulkan/shader/quakebsp.frag +++ b/libs/video/renderer/vulkan/shader/quakebsp.frag @@ -7,7 +7,6 @@ layout (set = 0, binding = 4) uniform sampler2DArray SkySheet; layout (set = 0, binding = 5) uniform samplerCube SkyCube; layout (push_constant) uniform PushConstants { - layout (offset = 64) vec4 fog; float time; float alpha; diff --git a/libs/video/renderer/vulkan/shader/quakebsp.vert b/libs/video/renderer/vulkan/shader/quakebsp.vert index 397bd2595..7d1c4024e 100644 --- a/libs/video/renderer/vulkan/shader/quakebsp.vert +++ b/libs/video/renderer/vulkan/shader/quakebsp.vert @@ -1,4 +1,7 @@ #version 450 +#extension GL_GOOGLE_include_directive : enable + +#include "entity.h" layout (set = 0, binding = 0) uniform Matrices { mat4 Projection3d; @@ -7,12 +10,13 @@ layout (set = 0, binding = 0) uniform Matrices { mat4 Projection2d; }; -layout (push_constant) uniform PushConstants { - mat4 Model; +layout (set = 1, binding = 0) buffer Entities { + Entity entities[]; }; layout (location = 0) in vec4 vertex; layout (location = 1) in vec4 tl_uv; +layout (location = 2) in uint entid; layout (location = 0) out vec4 tl_st; layout (location = 1) out vec3 direction; @@ -20,7 +24,8 @@ layout (location = 1) out vec3 direction; void main (void) { - gl_Position = Projection3d * (View * (Model * vertex)); + vec3 vert = vertex * entities[entid].transform; + gl_Position = Projection3d * (View * vec4 (vert, 1)); direction = (Sky * vertex).xyz; tl_st = tl_uv; } diff --git a/libs/video/renderer/vulkan/vulkan_bsp.c b/libs/video/renderer/vulkan/vulkan_bsp.c index a4e9a340d..cb33837e6 100644 --- a/libs/video/renderer/vulkan/vulkan_bsp.c +++ b/libs/video/renderer/vulkan/vulkan_bsp.c @@ -55,6 +55,7 @@ #include "QF/Vulkan/qf_bsp.h" #include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_matrices.h" +#include "QF/Vulkan/qf_scene.h" #include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/buffer.h" #include "QF/Vulkan/barrier.h" @@ -74,7 +75,6 @@ #include "vid_vulkan.h" typedef struct bsp_push_constants_s { - mat4f_t Model; quat_t fog; float time; float alpha; @@ -94,13 +94,6 @@ static QFV_Subpass subpass_map[] = { QFV_passTranslucent, // QFV_bspTurb }; -static float identity[] = { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, -}; - static vulktex_t vulkan_notexture = { }; #define ALLOC_CHUNK 64 @@ -486,11 +479,7 @@ R_DrawBrushModel (entity_t *e, vulkan_ctx_t *ctx) vec3_t mins, maxs; vec4f_t org; mod_brush_t *brush; - bspctx_t *bctx = ctx->bsp_context; - - bctx->entity = e; - bctx->transform = e->renderer.full_transform; - bctx->color = e->renderer.colormod; + //bspctx_t *bctx = ctx->bsp_context; model = e->renderer.model; brush = &model->brush; @@ -660,18 +649,6 @@ R_VisitWorldNodes (mod_brush_t *brush, vulkan_ctx_t *ctx) } } -static void -push_transform (vec_t *transform, VkPipelineLayout layout, - qfv_device_t *device, VkCommandBuffer cmd) -{ - qfv_push_constants_t push_constants[] = { - { VK_SHADER_STAGE_VERTEX_BIT, - field_offset (bsp_push_constants_t, Model), - sizeof (mat4f_t), transform }, - }; - QFV_PushConstants (device, cmd, layout, 1, push_constants); -} - static void bind_texture (vulktex_t *tex, uint32_t setnum, VkPipelineLayout layout, qfv_devfuncs_t *dfunc, VkCommandBuffer cmd) @@ -737,16 +714,18 @@ bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline, dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport); dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor); - VkDeviceSize offsets[] = { 0 }; - dfunc->vkCmdBindVertexBuffers (cmd, 0, 1, &bctx->vertex_buffer, offsets); + VkBuffer buffers[] = { bctx->vertex_buffer, bctx->entid_buffer }; + VkDeviceSize offsets[] = { 0, bframe->entid_offset }; + dfunc->vkCmdBindVertexBuffers (cmd, 0, 2, buffers, offsets); dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset, VK_INDEX_TYPE_UINT32); VkDescriptorSet sets[] = { Vulkan_Matrix_Descriptors (ctx, ctx->curFrame), + Vulkan_Scene_Descriptors (ctx), }; dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, - layout, 0, 1, sets, 0, 0); + layout, 0, 2, sets, 0, 0); //XXX glsl_Fog_GetColor (fog); //XXX fog[3] = glsl_Fog_GetDensity () / 64.0; @@ -869,70 +848,9 @@ clear_queues (bspctx_t *bctx, bsp_pass_t *pass) } static void -draw_queue (bsp_pass_t *pass, int queue, VkPipelineLayout layout, - qfv_device_t *device, VkCommandBuffer cmd) +queue_faces (bsp_pass_t *pass, bspctx_t *bctx, bspframe_t *bframe) { - qfv_devfuncs_t *dfunc = device->funcs; - - for (size_t i = 0; i < pass->draw_queues[queue].size; i++) { - __auto_type d = pass->draw_queues[queue].a[i]; - if (pass->textures) { - vulktex_t *tex = pass->textures->a[d.tex_id]; - bind_texture (tex, 1, layout, dfunc, cmd); - } - dfunc->vkCmdDrawIndexed (cmd, d.index_count, d.instance_count, - d.first_index, 0, d.first_instance); - } -} - -void -Vulkan_DrawWorld (qfv_renderframe_t *rFrame) -{ - vulkan_ctx_t *ctx = rFrame->vulkan_ctx; - qfv_device_t *device = ctx->device; - //qfv_devfuncs_t *dfunc = device->funcs; - bspctx_t *bctx = ctx->bsp_context; - bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; - entity_t worldent; - mod_brush_t *brush; - - bctx->main_pass.face_frames = r_face_visframes; - bctx->main_pass.leaf_frames = r_leaf_visframes; - bctx->main_pass.node_frames = r_node_visframes; - - clear_queues (bctx, &bctx->main_pass); // do this first for water and skys - bframe->index_count = 0; - - memset (&worldent, 0, sizeof (worldent)); - worldent.renderer.model = r_refdef.worldmodel; - brush = &r_refdef.worldmodel->brush; - - bctx->entity = &worldent; - bctx->transform = 0; - bctx->color = 0; - - R_VisitWorldNodes (brush, ctx); - if (!bctx->vertex_buffer) { - return; - } - if (r_drawentities) { - for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { - entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; - R_DrawBrushModel (ent, ctx); - } - } - - bsp_begin (rFrame); - - push_transform (identity, bctx->layout, device, - bframe->cmdSet.a[QFV_bspDepth]); - push_transform (identity, bctx->layout, device, - bframe->cmdSet.a[QFV_bspGBuffer]); - bsp_push_constants_t frag_constants = { .time = vr_data.realtime }; - push_fragconst (&frag_constants, bctx->layout, device, - bframe->cmdSet.a[QFV_bspGBuffer]); - __auto_type pass = &bctx->main_pass; - pass->indices = bframe->index_data; + pass->indices = bframe->index_data + bframe->index_count; for (size_t i = 0; i < bctx->registered_textures.size; i++) { __auto_type queue = &pass->face_queue[i]; if (!queue->size) { @@ -962,7 +880,88 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame) } DARRAY_APPEND (&pass->draw_queues[dq], draw); } + bframe->index_count += pass->index_count; +} + +static void +draw_queue (bsp_pass_t *pass, int queue, VkPipelineLayout layout, + qfv_device_t *device, VkCommandBuffer cmd) +{ + qfv_devfuncs_t *dfunc = device->funcs; + + for (size_t i = 0; i < pass->draw_queues[queue].size; i++) { + __auto_type d = pass->draw_queues[queue].a[i]; + if (pass->textures) { + vulktex_t *tex = pass->textures->a[d.tex_id]; + bind_texture (tex, 2, layout, dfunc, cmd); + } + dfunc->vkCmdDrawIndexed (cmd, d.index_count, d.instance_count, + d.first_index, 0, d.first_instance); + } +} + +static int +add_entity (vulkan_ctx_t *ctx, bsp_pass_t *pass, entity_t *entity) +{ + int entid = Vulkan_Scene_AddEntity (ctx, entity); + if (entid >= 0) { + pass->entid_data[pass->entid_count++] = entid; + } + return entid >= 0; +} + +void +Vulkan_DrawWorld (qfv_renderframe_t *rFrame) +{ + vulkan_ctx_t *ctx = rFrame->vulkan_ctx; + qfv_device_t *device = ctx->device; + //qfv_devfuncs_t *dfunc = device->funcs; + bspctx_t *bctx = ctx->bsp_context; + bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; + mod_brush_t *brush; + + bctx->main_pass.face_frames = r_face_visframes; + bctx->main_pass.leaf_frames = r_leaf_visframes; + bctx->main_pass.node_frames = r_node_visframes; + bctx->main_pass.entid_data = bframe->entid_data; + bctx->main_pass.entid_count = 0; + + clear_queues (bctx, &bctx->main_pass); // do this first for water and skys + bframe->index_count = 0; + + entity_t worldent = { + .renderer = { + .model = r_refdef.worldmodel, + .colormod = { 1, 1, 1, 1 }, + }, + }; + brush = &r_refdef.worldmodel->brush; + + add_entity (ctx, &bctx->main_pass, &worldent); + + R_VisitWorldNodes (brush, ctx); + if (!bctx->vertex_buffer) { + return; + } + if (r_drawentities) { + for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) { + entity_t *ent = r_ent_queue->ent_queues[mod_brush].a[i]; + if (add_entity (ctx, &bctx->main_pass, ent)) { + R_DrawBrushModel (ent, ctx); + } + } + } + + queue_faces (&bctx->main_pass, bctx, bframe); + + bsp_begin (rFrame); + + bsp_push_constants_t frag_constants = { .time = vr_data.realtime }; + push_fragconst (&frag_constants, bctx->layout, device, + bframe->cmdSet.a[QFV_bspGBuffer]); VkPipelineLayout layout = bctx->layout; + + __auto_type pass = &bctx->main_pass; pass->textures = 0; draw_queue (pass, 0, layout, device, bframe->cmdSet.a[QFV_bspDepth]); pass->textures = &bctx->registered_textures; @@ -979,20 +978,28 @@ Vulkan_Bsp_Flush (vulkan_ctx_t *ctx) bspframe_t *bframe = &bctx->frames.a[ctx->curFrame]; size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; size_t atom_mask = atom - 1; - size_t offset = bframe->index_offset; - size_t size = bframe->index_count * sizeof (uint32_t); + size_t index_offset = bframe->index_offset; + size_t index_size = bframe->index_count * sizeof (uint32_t); + size_t entid_offset = bframe->entid_offset; + size_t entid_size = bframe->entid_count * sizeof (uint32_t); if (!bframe->index_count) { return; } - offset &= ~atom_mask; - size = (size + atom_mask) & ~atom_mask; + index_offset &= ~atom_mask; + index_size = (index_size + atom_mask) & ~atom_mask; + entid_offset &= ~atom_mask; + entid_size = (entid_size + atom_mask) & ~atom_mask; - VkMappedMemoryRange range = { - VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, - bctx->index_memory, offset, size + VkMappedMemoryRange ranges[] = { + { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + bctx->index_memory, index_offset, index_size + }, + { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0, + bctx->entid_memory, entid_offset, entid_size + }, }; - dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); + dfunc->vkFlushMappedMemoryRanges (device->dev, 2, ranges); } void @@ -1008,8 +1015,6 @@ Vulkan_DrawWaterSurfaces (qfv_renderframe_t *rFrame) return; turb_begin (rFrame); - push_transform (identity, bctx->layout, device, - bframe->cmdSet.a[QFV_bspTurb]); bsp_push_constants_t frag_constants = { .time = vr_data.realtime, .alpha = r_wateralpha @@ -1039,10 +1044,8 @@ Vulkan_DrawSky (qfv_renderframe_t *rFrame) sky_begin (rFrame); vulktex_t skybox = { .descriptor = bctx->skybox_descriptor }; - bind_texture (&skybox, 2, bctx->layout, dfunc, + bind_texture (&skybox, 3, bctx->layout, dfunc, bframe->cmdSet.a[QFV_bspSky]); - push_transform (identity, bctx->layout, device, - bframe->cmdSet.a[QFV_bspSky]); bsp_push_constants_t frag_constants = { .time = vr_data.realtime }; push_fragconst (&frag_constants, bctx->layout, device, bframe->cmdSet.a[QFV_bspSky]); @@ -1166,6 +1169,7 @@ void Vulkan_Bsp_Init (vulkan_ctx_t *ctx) { qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; r_notexture_mip->render = &vulkan_notexture; @@ -1204,6 +1208,28 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) bctx->layout = Vulkan_CreatePipelineLayout (ctx, "quakebsp_layout"); bctx->sampler = Vulkan_CreateSampler (ctx, "quakebsp_sampler"); + size_t entid_size = Vulkan_Scene_MaxEntities (ctx) * sizeof (uint32_t); + size_t atom = device->physDev->properties.limits.nonCoherentAtomSize; + size_t atom_mask = atom - 1; + entid_size = (entid_size + atom_mask) & ~atom_mask; + bctx->entid_buffer + = QFV_CreateBuffer (device, frames * entid_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, bctx->entid_buffer, + "buffer:bsp:entid"); + bctx->entid_memory + = QFV_AllocBufferMemory (device, bctx->entid_buffer, + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + frames * entid_size, 0); + QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, + bctx->entid_memory, "memory:bsp:entid"); + QFV_BindBufferMemory (device, + bctx->entid_buffer, bctx->entid_memory, 0); + uint32_t *entid_data; + dfunc->vkMapMemory (device->dev, bctx->entid_memory, 0, + frames * entid_size, 0, (void **) &entid_data); + for (size_t i = 0; i < frames; i++) { __auto_type bframe = &bctx->frames.a[i]; @@ -1219,6 +1245,8 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx) va (ctx->va_ctx, "cmd:bsp:%zd:%s", i, bsp_pass_names[j])); } + bframe->entid_data = entid_data + i * entid_size; + bframe->entid_offset = i * entid_size; } bctx->skybox_descriptor @@ -1261,6 +1289,8 @@ Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx) dfunc->vkDestroyBuffer (device->dev, bctx->index_buffer, 0); dfunc->vkFreeMemory (device->dev, bctx->index_memory, 0); } + dfunc->vkDestroyBuffer (device->dev, bctx->entid_buffer, 0); + dfunc->vkFreeMemory (device->dev, bctx->entid_memory, 0); if (bctx->skybox_tex) { Vulkan_UnloadTex (ctx, bctx->skybox_tex); diff --git a/libs/video/renderer/vulkan/vulkan_scene.c b/libs/video/renderer/vulkan/vulkan_scene.c new file mode 100644 index 000000000..6a8c568ef --- /dev/null +++ b/libs/video/renderer/vulkan/vulkan_scene.c @@ -0,0 +1,205 @@ +/* + vulkan_scene.c + + Vulkan scene handling + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/5/24 + + 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 + +#include "QF/mathlib.h" +#include "QF/set.h" +#include "QF/va.h" + +#include "QF/scene/entity.h" + +#include "QF/Vulkan/qf_scene.h" +#include "QF/Vulkan/debug.h" +#include "QF/Vulkan/descriptor.h" +#include "QF/Vulkan/device.h" +#include "QF/Vulkan/instance.h" +#include "QF/Vulkan/resource.h" + +#include "vid_vulkan.h" + +static const int qfv_max_entities = 4096; //FIXME should make dynamic + +int +Vulkan_Scene_MaxEntities (vulkan_ctx_t *ctx) +{ + scenectx_t *sctx = ctx->scene_context; + return sctx->max_entities; +} + +VkDescriptorSet +Vulkan_Scene_Descriptors (vulkan_ctx_t *ctx) +{ + scenectx_t *sctx = ctx->scene_context; + scnframe_t *sframe = &sctx->frames.a[ctx->curFrame]; + return sframe->descriptors; +} + +int +Vulkan_Scene_AddEntity (vulkan_ctx_t *ctx, entity_t *entity) +{ + scenectx_t *sctx = ctx->scene_context; + scnframe_t *sframe = &sctx->frames.a[ctx->curFrame]; + + entdata_t *entdata = 0; + //lock + int id = -entity->id; + if (!set_is_member (sframe->pooled_entities, id)) { + if (sframe->entity_pool.size < sframe->entity_pool.maxSize) { + set_add (sframe->pooled_entities, id); + entity->renderer.render_id = sframe->entity_pool.size++; + entdata = sframe->entity_pool.a + entity->renderer.render_id; + } else { + entity->renderer.render_id = -1; + } + } + //unlock + if (entdata) { + mat4f_t f; + if (entity->transform) { //FIXME give world entity an entity :P + mat4ftranspose (f, Transform_GetWorldMatrixPtr (entity->transform)); + entdata->xform[0] = f[0]; + entdata->xform[1] = f[1]; + entdata->xform[2] = f[2]; + } else { + entdata->xform[0] = (vec4f_t) { 1, 0, 0, 0 }; + entdata->xform[1] = (vec4f_t) { 0, 1, 0, 0 }; + entdata->xform[2] = (vec4f_t) { 0, 0, 1, 0 }; + } + entdata->color = (vec4f_t) { QuatExpand (entity->renderer.colormod) }; + } + return entity->renderer.render_id; +} + +static VkWriteDescriptorSet base_buffer_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0, + 0, 0, 1, + VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + 0, 0, 0 +}; + +void +Vulkan_Scene_Init (vulkan_ctx_t *ctx) +{ + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + + qfvPushDebug (ctx, "scene init"); + + scenectx_t *sctx = calloc (1, sizeof (scenectx_t) + + sizeof (qfv_resource_t) + + sizeof (qfv_resobj_t)); + ctx->scene_context = sctx; + sctx->max_entities = qfv_max_entities; + + size_t frames = ctx->frames.size; + DARRAY_INIT (&sctx->frames, frames); + DARRAY_RESIZE (&sctx->frames, frames); + sctx->frames.grow = 0; + + sctx->entities = (qfv_resource_t *) &sctx[1]; + *sctx->entities = (qfv_resource_t) { + .name = "scene", + .va_ctx = ctx->va_ctx, + .memory_properties = VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + .num_objects = 1, + .objects = (qfv_resobj_t *) &sctx->entities[1], + }; + sctx->entities->objects[0] = (qfv_resobj_t) { + .name = "entities", + .type = qfv_res_buffer, + .buffer = { + .size = frames * qfv_max_entities * sizeof (entdata_t), + .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + }, + }; + + QFV_CreateResource (device, sctx->entities); + + sctx->pool = Vulkan_CreateDescriptorPool (ctx, "entity_pool"); + sctx->setLayout = Vulkan_CreateDescriptorSetLayout (ctx, "entity_set"); + __auto_type layouts = QFV_AllocDescriptorSetLayoutSet (frames, alloca); + for (size_t i = 0; i < layouts->size; i++) { + layouts->a[i] = sctx->setLayout; + } + __auto_type sets = QFV_AllocateDescriptorSet (device, sctx->pool, layouts); + + entdata_t *entdata; + dfunc->vkMapMemory (device->dev, sctx->entities->memory, 0, VK_WHOLE_SIZE, + 0, (void **) &entdata); + + VkBuffer buffer = sctx->entities->objects[0].buffer.buffer; + size_t entdata_size = qfv_max_entities * sizeof (entdata_t); + for (size_t i = 0; i < frames; i++) { + __auto_type sframe = &sctx->frames.a[i]; + + sframe->descriptors = sets->a[i]; + VkDescriptorBufferInfo bufferInfo = { + buffer, i * entdata_size, entdata_size + }; + VkWriteDescriptorSet write[1]; + write[0] = base_buffer_write; + write[0].dstSet = sframe->descriptors; + write[0].pBufferInfo = &bufferInfo; + dfunc->vkUpdateDescriptorSets (device->dev, 1, write, 0, 0); + + sframe->entity_pool = (entdataset_t) { + .maxSize = qfv_max_entities, + .a = entdata + i * qfv_max_entities, + }; + sframe->pooled_entities = set_new (); + } + free (sets); + qfvPopDebug (ctx); +} + +void +Vulkan_Scene_Shutdown (vulkan_ctx_t *ctx) +{ + qfvPushDebug (ctx, "scene shutdown"); + qfv_device_t *device = ctx->device; + qfv_devfuncs_t *dfunc = device->funcs; + scenectx_t *sctx = ctx->scene_context; + + for (size_t i = 0; i < sctx->frames.size; i++) { + __auto_type sframe = &sctx->frames.a[i]; + set_delete (sframe->pooled_entities); + } + + dfunc->vkUnmapMemory (device->dev, sctx->entities->memory); + QFV_DestroyResource (device, sctx->entities); + + free (sctx->frames.a); + free (sctx); + qfvPopDebug (ctx); +}