[vulkan] Get bsp texture animations working again

The texture animation data is compacted into a small struct for each
texture, resulting in much less data access when animating the texture.
More importantly, no looping over the list of frames. I plan on
migrating this to at least the other hardware renderers.
This commit is contained in:
Bill Currie 2022-05-26 22:31:31 +09:00
parent 77505abd94
commit 61178978be
2 changed files with 116 additions and 17 deletions

View file

@ -64,11 +64,30 @@ typedef struct bsp_packetset_s
typedef struct bsp_indexset_s
DARRAY_TYPE (uint32_t) bsp_indexset_t;
typedef struct bsp_tex_s {
VkDescriptorSet descriptors;
bsp_packetset_t packets;
bsp_indexset_t indices;
} bsp_tex_t;
typedef struct texname_s {
char name[MIPTEXNAME];
} texname_t;
typedef struct texmip_s {
uint32_t width;
uint32_t height;
uint32_t offsets[MIPLEVELS];
} texmip_t;
typedef struct texanim_s {
uint16_t base;
byte offset;
byte count;
} texanim_t;
typedef struct texdata_s {
// texname_t *names;
// texmip_t **mips;
texanim_t *anim_main;
texanim_t *anim_alt;
uint16_t *anim_map;
// int num_tex;
} texdata_t;
typedef struct vulktex_s {
struct qfv_tex_s *tex;
@ -79,9 +98,6 @@ typedef struct vulktex_s {
typedef struct regtexset_s
DARRAY_TYPE (vulktex_t *) regtexset_t;
typedef struct bsp_texset_s
DARRAY_TYPE (bsp_tex_t) bsp_texset_t;
typedef struct bsp_draw_s {
uint32_t tex_id;
uint32_t inst_id;
@ -123,8 +139,9 @@ typedef struct bsp_pass_s {
regtexset_t *textures;
int num_queues;
bsp_drawset_t *draw_queues;
uint32_t inst_id;
uint32_t inst_id;
bsp_instance_t *instances;
int ent_frame;
} bsp_pass_t;
typedef struct bspvert_s {
@ -172,6 +189,8 @@ typedef struct bspctx_s {
struct qfv_tex_s *skybox_tex;
VkDescriptorSet skybox_descriptor;
vulktex_t notexture;
quat_t default_color;
quat_t last_color;
@ -182,6 +201,9 @@ typedef struct bspctx_s {
bsp_face_t *faces;
uint32_t *poly_indices;
texdata_t texdata;
int anim_index;
int model_id;
bsp_pass_t main_pass; // camera view depth, gbuffer, etc

View file

@ -120,8 +120,14 @@ Vulkan_ClearElements (vulkan_ctx_t *ctx)
static inline void
chain_surface (const bsp_face_t *face, bsp_pass_t *pass, bspctx_t *bctx)
{
DARRAY_APPEND (&pass->face_queue[face->tex_id],
int ent_frame = pass->ent_frame;
// if the texture has no alt animations, anim_alt holds the sama data
// as anim_main
texanim_t *anim = ent_frame ? &bctx->texdata.anim_alt[face->tex_id]
: &bctx->texdata.anim_main[face->tex_id];
int anim_ind = (bctx->anim_index + anim->offset) % anim->count;
int tex_id = bctx->texdata.anim_map[anim->base + anim_ind];
DARRAY_APPEND (&pass->face_queue[tex_id],
((instface_t) { pass->inst_id, face - bctx->faces }));
}
@ -157,15 +163,13 @@ clear_textures (vulkan_ctx_t *ctx)
void
Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
{
int i;
model_t *m;
mod_brush_t *brush = &r_refdef.worldmodel->brush;
clear_textures (ctx);
add_texture (r_notexture_mip, ctx);
register_textures (brush, ctx);
for (i = 0; i < num_models; i++) {
m = models[i];
for (int i = 0; i < num_models; i++) {
model_t *m = models[i];
if (!m)
continue;
// sub-models are done as part of the main model
@ -181,6 +185,74 @@ Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
bspctx_t *bctx = ctx->bsp_context;
int num_tex = bctx->registered_textures.size;
texture_t **textures = alloca (num_tex * sizeof (texture_t *));
textures[0] = r_notexture_mip;
for (int i = 0, t = 1; i < num_models; i++) {
model_t *m = models[i];
// sub-models are done as part of the main model
if (!m || *m->path == '*') {
continue;
}
brush = &m->brush;
for (unsigned j = 0; j < brush->numtextures; j++) {
if (brush->textures[j]) {
textures[t++] = brush->textures[j];
}
}
}
size_t texdata_size = 2.5 * num_tex * sizeof (texanim_t);
texanim_t *texdata = Hunk_AllocName (0, texdata_size, "texdata");
bctx->texdata.anim_main = texdata;
bctx->texdata.anim_alt = texdata + num_tex;
bctx->texdata.anim_map = (uint16_t *) (texdata + 2 * num_tex);
int16_t map_index = 0;
for (int i = 0; i < num_tex; i++) {
texanim_t *anim = bctx->texdata.anim_main + i;
if (anim->count) {
// already done as part of an animation group
continue;
}
*anim = (texanim_t) { .base = map_index, .offset = 0, .count = 1 };
bctx->texdata.anim_map[anim->base] = i;
if (textures[i]->anim_total > 1) {
// bsp loader multiplies anim_total by ANIM_CYCLE to slow the
// frame rate
anim->count = textures[i]->anim_total / ANIM_CYCLE;
texture_t *tx = textures[i]->anim_next;
for (int j = 1; j < anim->count; j++) {
if (!tx) {
Sys_Error ("broken cycle");
}
vulktex_t *vtex = tx->render;
texanim_t *a = bctx->texdata.anim_main + vtex->tex_id;
if (a->count) {
Sys_Error ("crossed cycle");
}
*a = *anim;
a->offset = j;
bctx->texdata.anim_map[a->base + a->offset] = vtex->tex_id;
tx = tx->anim_next;
}
if (tx != textures[i]) {
Sys_Error ("infinite cycle");
}
};
map_index += bctx->texdata.anim_main[i].count;
}
for (int i = 0; i < num_tex; i++) {
texanim_t *alt = bctx->texdata.anim_alt + i;
if (textures[i]->alternate_anims) {
texture_t *tx = textures[i]->alternate_anims;
vulktex_t *vtex = tx->render;
*alt = bctx->texdata.anim_main[vtex->tex_id];
} else {
*alt = bctx->texdata.anim_main[i];
}
}
bctx->main_pass.face_queue = malloc (num_tex * sizeof (bsp_instfaceset_t));
for (int i = 0; i < num_tex; i++) {
bctx->main_pass.face_queue[i]
@ -398,7 +470,8 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
bsp_model_t *m = &bctx->models[models[i]->render_id];
m->first_face = face_base + models[i]->brush.firstmodelsurface;
m->face_count = models[i]->brush.nummodelsurfaces;
while (models[i + 1] && models[i + 1]->path[0] == '*') {
while (i < num_models - 1 && models[i + 1]
&& models[i + 1]->path[0] == '*') {
i++;
m = &bctx->models[models[i]->render_id];
m->first_face = face_base + models[i]->brush.firstmodelsurface;
@ -529,6 +602,7 @@ R_DrawBrushModel (entity_t *e, bsp_pass_t *pass, vulkan_ctx_t *ctx)
return 0;
}
pass->ent_frame = e->animation.frame & 1;
pass->inst_id = model->render_id;
if (!pass->instances[model->render_id].entities.size) {
bsp_model_t *m = &bctx->models[model->render_id];
@ -902,7 +976,7 @@ queue_faces (bsp_pass_t *pass, bspctx_t *bctx, bspframe_t *bframe)
size_t dq_size = pass->draw_queues[dq].size;
bsp_draw_t *draw = &pass->draw_queues[dq].a[dq_size - 1];
if (!pass->draw_queues[dq].size
|| draw->tex_id != f.tex_id
|| draw->tex_id != i
|| draw->inst_id != is.inst_id) {
bsp_instance_t *instance = &pass->instances[is.inst_id];
DARRAY_APPEND (&pass->draw_queues[dq], ((bsp_draw_t) {
@ -967,6 +1041,8 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame)
bctx->main_pass.entid_data = bframe->entid_data;
bctx->main_pass.entid_count = 0;
bctx->anim_index = r_data->realtime * 5;
clear_queues (bctx, &bctx->main_pass); // do this first for water and skys
bframe->index_count = 0;
@ -981,6 +1057,7 @@ Vulkan_DrawWorld (qfv_renderframe_t *rFrame)
Vulkan_Scene_AddEntity (ctx, &worldent);
int world_id = worldent.renderer.model->render_id;
bctx->main_pass.ent_frame = 0; // world is always frame 0
bctx->main_pass.inst_id = world_id;
DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities,
worldent.renderer.render_id);