mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 23:32:09 +00:00
[vulkan] Use a buffer for entity transform and color data
This allows the use of an entity id to index into the entity data and fetch the transform and colormod data in the vertex shader, thus making instanced rendering possible. Non-world brush entities are still not rendered, but the world entity is using both the entity data buffer and entid buffer.
This commit is contained in:
parent
3900e59f1a
commit
a08261c620
19 changed files with 502 additions and 137 deletions
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
80
include/QF/Vulkan/qf_scene.h
Normal file
80
include/QF/Vulkan/qf_scene.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
qf_scene.h
|
||||
|
||||
Vulkan specific scene stuff
|
||||
|
||||
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
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 <vulkan/vulkan.h>
|
||||
|
||||
#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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
4
libs/video/renderer/vulkan/shader/entity.h
Normal file
4
libs/video/renderer/vulkan/shader/entity.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
struct Entity {
|
||||
mat3x4 transform;
|
||||
vec4 color;
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
205
libs/video/renderer/vulkan/vulkan_scene.c
Normal file
205
libs/video/renderer/vulkan/vulkan_scene.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
vulkan_scene.c
|
||||
|
||||
Vulkan scene handling
|
||||
|
||||
Copyright (C) 2022 Bill Currie <bill@taniwha.org>
|
||||
|
||||
Author: Bill Currie <bill@taniwha.org>
|
||||
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 <string.h>
|
||||
|
||||
#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);
|
||||
}
|
Loading…
Reference in a new issue