2021-01-19 16:25:54 +00:00
|
|
|
/*
|
|
|
|
vulkan_bsp.c
|
|
|
|
|
|
|
|
Vulkan bsp
|
|
|
|
|
|
|
|
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
|
|
|
|
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
|
|
|
|
|
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2012/1/7
|
|
|
|
Date: 2021/1/18
|
|
|
|
|
|
|
|
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_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "qfalloca.h"
|
|
|
|
|
|
|
|
#include "QF/cvar.h"
|
|
|
|
#include "QF/darray.h"
|
2022-05-25 04:29:11 +00:00
|
|
|
#include "QF/heapsort.h"
|
2021-01-19 16:25:54 +00:00
|
|
|
#include "QF/image.h"
|
|
|
|
#include "QF/render.h"
|
|
|
|
#include "QF/sys.h"
|
|
|
|
#include "QF/va.h"
|
|
|
|
|
2022-05-26 23:12:21 +00:00
|
|
|
#include "QF/math/bitop.h"
|
2021-07-24 05:19:52 +00:00
|
|
|
#include "QF/scene/entity.h"
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
#include "QF/Vulkan/qf_bsp.h"
|
|
|
|
#include "QF/Vulkan/qf_lightmap.h"
|
2021-12-08 12:11:36 +00:00
|
|
|
#include "QF/Vulkan/qf_matrices.h"
|
2022-05-30 03:10:00 +00:00
|
|
|
#include "QF/Vulkan/qf_renderpass.h"
|
2022-05-24 15:17:57 +00:00
|
|
|
#include "QF/Vulkan/qf_scene.h"
|
2021-01-19 16:25:54 +00:00
|
|
|
#include "QF/Vulkan/qf_texture.h"
|
2021-01-20 07:28:04 +00:00
|
|
|
#include "QF/Vulkan/buffer.h"
|
2021-01-23 11:42:53 +00:00
|
|
|
#include "QF/Vulkan/barrier.h"
|
2021-01-19 16:25:54 +00:00
|
|
|
#include "QF/Vulkan/command.h"
|
2021-01-31 10:58:55 +00:00
|
|
|
#include "QF/Vulkan/debug.h"
|
2021-01-19 16:25:54 +00:00
|
|
|
#include "QF/Vulkan/descriptor.h"
|
|
|
|
#include "QF/Vulkan/device.h"
|
2021-01-23 11:42:53 +00:00
|
|
|
#include "QF/Vulkan/image.h"
|
2021-01-21 17:20:32 +00:00
|
|
|
#include "QF/Vulkan/instance.h"
|
2021-01-21 07:39:11 +00:00
|
|
|
#include "QF/Vulkan/scrap.h"
|
2021-01-19 16:25:54 +00:00
|
|
|
#include "QF/Vulkan/staging.h"
|
|
|
|
|
2022-05-11 10:24:39 +00:00
|
|
|
#include "QF/simd/types.h"
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
#include "r_internal.h"
|
|
|
|
#include "vid_vulkan.h"
|
|
|
|
|
2021-12-17 06:51:33 +00:00
|
|
|
typedef struct bsp_push_constants_s {
|
|
|
|
quat_t fog;
|
|
|
|
float time;
|
2022-05-21 08:48:45 +00:00
|
|
|
float alpha;
|
2022-05-26 23:12:21 +00:00
|
|
|
float turb_scale;
|
2021-12-17 06:51:33 +00:00
|
|
|
} bsp_push_constants_t;
|
|
|
|
|
2021-04-01 23:48:11 +00:00
|
|
|
static const char * __attribute__((used)) bsp_pass_names[] = {
|
2021-02-14 02:35:06 +00:00
|
|
|
"depth",
|
|
|
|
"g-buffer",
|
2021-03-23 03:24:24 +00:00
|
|
|
"sky",
|
|
|
|
"turb",
|
2021-02-14 02:35:06 +00:00
|
|
|
};
|
|
|
|
|
2021-03-22 23:25:56 +00:00
|
|
|
static QFV_Subpass subpass_map[] = {
|
2022-06-08 09:16:10 +00:00
|
|
|
[QFV_bspDepth] = QFV_passDepth,
|
|
|
|
[QFV_bspGBuffer] = QFV_passGBuffer,
|
|
|
|
[QFV_bspSky] = QFV_passTranslucent,
|
|
|
|
[QFV_bspTurb] = QFV_passTranslucent,
|
2021-03-22 23:25:56 +00:00
|
|
|
};
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
static void
|
|
|
|
add_texture (texture_t *tx, vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
|
|
|
|
vulktex_t *tex = tx->render;
|
2021-12-17 03:20:32 +00:00
|
|
|
if (tex->tex) {
|
2022-05-22 16:28:43 +00:00
|
|
|
tex->tex_id = bctx->registered_textures.size;
|
|
|
|
DARRAY_APPEND (&bctx->registered_textures, tex);
|
2021-12-17 03:20:32 +00:00
|
|
|
tex->descriptor = Vulkan_CreateTextureDescriptor (ctx, tex->tex,
|
|
|
|
bctx->sampler);
|
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2022-05-31 06:32:12 +00:00
|
|
|
chain_surface (const bsp_face_t *face, bsp_pass_t *pass, const bspctx_t *bctx)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2022-05-26 13:31:31 +00:00
|
|
|
int ent_frame = pass->ent_frame;
|
|
|
|
// if the texture has no alt animations, anim_alt holds the sama data
|
|
|
|
// as anim_main
|
2022-05-31 06:32:12 +00:00
|
|
|
const texanim_t *anim = ent_frame ? &bctx->texdata.anim_alt[face->tex_id]
|
|
|
|
: &bctx->texdata.anim_main[face->tex_id];
|
2022-05-26 13:31:31 +00:00
|
|
|
int anim_ind = (bctx->anim_index + anim->offset) % anim->count;
|
2022-06-08 09:16:10 +00:00
|
|
|
int tex_id = bctx->texdata.frame_map[anim->base + anim_ind];
|
2022-05-26 13:31:31 +00:00
|
|
|
DARRAY_APPEND (&pass->face_queue[tex_id],
|
2022-05-25 04:29:11 +00:00
|
|
|
((instface_t) { pass->inst_id, face - bctx->faces }));
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-02-01 10:31:11 +00:00
|
|
|
register_textures (mod_brush_t *brush, vulkan_ctx_t *ctx)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
|
|
|
texture_t *tex;
|
|
|
|
|
2021-08-01 12:54:05 +00:00
|
|
|
for (unsigned i = 0; i < brush->numtextures; i++) {
|
2021-02-01 10:31:11 +00:00
|
|
|
tex = brush->textures[i];
|
2021-01-19 16:25:54 +00:00
|
|
|
if (!tex)
|
|
|
|
continue;
|
|
|
|
add_texture (tex, ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clear_textures (vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2022-05-22 16:28:43 +00:00
|
|
|
|
|
|
|
if (bctx->main_pass.face_queue) {
|
|
|
|
for (size_t i = 0; i < bctx->registered_textures.size; i++) {
|
|
|
|
DARRAY_CLEAR (&bctx->main_pass.face_queue[i]);
|
|
|
|
}
|
|
|
|
free (bctx->main_pass.face_queue);
|
|
|
|
bctx->main_pass.face_queue = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bctx->registered_textures.size = 0;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Vulkan_RegisterTextures (model_t **models, int num_models, vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
clear_textures (ctx);
|
|
|
|
add_texture (r_notexture_mip, ctx);
|
2022-05-31 06:32:12 +00:00
|
|
|
{
|
|
|
|
// FIXME make worldmodel non-special. needs smarter handling of
|
|
|
|
// textures on sub-models but not on main model.
|
|
|
|
mod_brush_t *brush = &r_refdef.worldmodel->brush;
|
|
|
|
register_textures (brush, ctx);
|
|
|
|
}
|
2022-05-26 13:31:31 +00:00
|
|
|
for (int i = 0; i < num_models; i++) {
|
|
|
|
model_t *m = models[i];
|
2021-01-19 16:25:54 +00:00
|
|
|
if (!m)
|
|
|
|
continue;
|
|
|
|
// sub-models are done as part of the main model
|
2021-02-01 05:39:00 +00:00
|
|
|
if (*m->path == '*')
|
2021-01-19 16:25:54 +00:00
|
|
|
continue;
|
|
|
|
// world has already been done, not interested in non-brush models
|
2022-05-31 06:32:12 +00:00
|
|
|
// FIXME see above
|
2022-03-14 06:27:43 +00:00
|
|
|
if (m == r_refdef.worldmodel || m->type != mod_brush)
|
2021-01-19 16:25:54 +00:00
|
|
|
continue;
|
2022-05-31 06:32:12 +00:00
|
|
|
mod_brush_t *brush = &m->brush;
|
2021-02-01 10:31:11 +00:00
|
|
|
brush->numsubmodels = 1; // no support for submodels in non-world model
|
|
|
|
register_textures (brush, ctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
int num_tex = bctx->registered_textures.size;
|
2022-05-26 13:31:31 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2022-05-31 06:32:12 +00:00
|
|
|
mod_brush_t *brush = &m->brush;
|
2022-05-26 13:31:31 +00:00
|
|
|
for (unsigned j = 0; j < brush->numtextures; j++) {
|
|
|
|
if (brush->textures[j]) {
|
|
|
|
textures[t++] = brush->textures[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 09:16:10 +00:00
|
|
|
// 2.5 for two texanim_t structs (32-bits each) and 1 uint16_t for each
|
|
|
|
// element
|
2022-05-26 13:31:31 +00:00
|
|
|
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;
|
2022-06-08 09:16:10 +00:00
|
|
|
bctx->texdata.frame_map = (uint16_t *) (texdata + 2 * num_tex);
|
2022-05-26 13:31:31 +00:00
|
|
|
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 };
|
2022-06-08 09:16:10 +00:00
|
|
|
bctx->texdata.frame_map[anim->base] = i;
|
2022-05-26 13:31:31 +00:00
|
|
|
|
|
|
|
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;
|
2022-06-08 09:16:10 +00:00
|
|
|
bctx->texdata.frame_map[a->base + a->offset] = vtex->tex_id;
|
2022-05-26 13:31:31 +00:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 09:16:10 +00:00
|
|
|
// create face queue arrays
|
2022-05-22 16:28:43 +00:00
|
|
|
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]
|
|
|
|
= (bsp_instfaceset_t) DARRAY_STATIC_INIT (128);
|
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
typedef struct {
|
|
|
|
msurface_t *face;
|
|
|
|
model_t *model;
|
|
|
|
int model_face_base;
|
|
|
|
} faceref_t;
|
|
|
|
|
|
|
|
typedef struct DARRAY_TYPE (faceref_t) facerefset_t;
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
static void
|
2022-05-31 06:32:12 +00:00
|
|
|
count_verts_inds (const faceref_t *faceref, uint32_t *verts, uint32_t *inds)
|
2021-01-20 06:11:50 +00:00
|
|
|
{
|
2022-05-22 16:28:43 +00:00
|
|
|
msurface_t *surf = faceref->face;
|
2021-07-15 12:38:12 +00:00
|
|
|
*verts = surf->numedges;
|
|
|
|
*inds = surf->numedges + 1;
|
2021-01-20 06:11:50 +00:00
|
|
|
}
|
|
|
|
|
2022-05-31 06:32:12 +00:00
|
|
|
typedef struct bspvert_s {
|
|
|
|
quat_t vertex;
|
|
|
|
quat_t tlst;
|
|
|
|
} bspvert_t;
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
typedef struct {
|
|
|
|
bsp_face_t *faces;
|
|
|
|
uint32_t *indices;
|
|
|
|
bspvert_t *vertices;
|
|
|
|
uint32_t index_base;
|
|
|
|
uint32_t vertex_base;
|
|
|
|
int tex_id;
|
|
|
|
} buildctx_t;
|
|
|
|
|
|
|
|
static void
|
2022-05-25 04:29:11 +00:00
|
|
|
build_surf_displist (const faceref_t *faceref, buildctx_t *build)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2022-05-22 16:28:43 +00:00
|
|
|
msurface_t *surf = faceref->face;
|
|
|
|
mod_brush_t *brush = &faceref->model->brush;;
|
2022-05-11 10:24:39 +00:00
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
int facenum = surf - brush->surfaces;
|
|
|
|
bsp_face_t *face = &build->faces[facenum + faceref->model_face_base];
|
2022-05-11 10:24:39 +00:00
|
|
|
// create a triangle fan
|
|
|
|
int numverts = surf->numedges;
|
2022-05-22 16:28:43 +00:00
|
|
|
face->first_index = build->index_base;
|
|
|
|
face->index_count = numverts + 1; // +1 for primitive restart
|
|
|
|
face->tex_id = build->tex_id;
|
|
|
|
face->flags = surf->flags;
|
|
|
|
build->index_base += face->index_count;
|
2022-05-11 10:24:39 +00:00
|
|
|
for (int i = 0; i < numverts; i++) {
|
2022-05-22 16:28:43 +00:00
|
|
|
build->indices[face->first_index + i] = build->vertex_base + i;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
2022-05-22 16:28:43 +00:00
|
|
|
build->indices[face->first_index + numverts] = -1; // primitive restart
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
bspvert_t *verts = build->vertices + build->vertex_base;
|
|
|
|
build->vertex_base += numverts;
|
2021-07-15 12:38:12 +00:00
|
|
|
mtexinfo_t *texinfo = surf->texinfo;
|
2022-05-22 16:28:43 +00:00
|
|
|
mvertex_t *vertices = brush->vertexes;
|
|
|
|
medge_t *edges = brush->edges;
|
|
|
|
int *surfedges = brush->surfedges;
|
2022-05-11 10:24:39 +00:00
|
|
|
for (int i = 0; i < numverts; i++) {
|
|
|
|
vec_t *vec;
|
|
|
|
int index = surfedges[surf->firstedge + i];
|
2021-01-20 06:11:50 +00:00
|
|
|
if (index > 0) {
|
2022-05-11 10:24:39 +00:00
|
|
|
// forward edge
|
2021-01-19 16:25:54 +00:00
|
|
|
vec = vertices[edges[index].v[0]].position;
|
2021-01-20 06:11:50 +00:00
|
|
|
} else {
|
2022-05-11 10:24:39 +00:00
|
|
|
// reverse edge
|
2021-01-19 16:25:54 +00:00
|
|
|
vec = vertices[edges[-index].v[1]].position;
|
2021-01-20 06:11:50 +00:00
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
VectorCopy (vec, verts[i].vertex);
|
2022-05-11 10:24:39 +00:00
|
|
|
verts[i].vertex[3] = 1; // homogeneous coord
|
|
|
|
|
|
|
|
vec2f_t st = {
|
|
|
|
DotProduct (vec, texinfo->vecs[0]) + texinfo->vecs[0][3],
|
|
|
|
DotProduct (vec, texinfo->vecs[1]) + texinfo->vecs[1][3],
|
|
|
|
};
|
|
|
|
verts[i].tlst[0] = st[0] / texinfo->texture->width;
|
|
|
|
verts[i].tlst[1] = st[1] / texinfo->texture->height;
|
|
|
|
|
|
|
|
if (surf->lightpic) {
|
|
|
|
//lightmap texture coordinates
|
|
|
|
//every lit surface has its own lighmap at a 1/16 resolution
|
|
|
|
//(ie, 16 albedo pixels for every lightmap pixel)
|
|
|
|
const vrect_t *rect = surf->lightpic->rect;
|
|
|
|
vec2f_t lmorg = (vec2f_t) { VEC2_EXP (&rect->x) } * 16 + 8;
|
|
|
|
vec2f_t texorg = { VEC2_EXP (surf->texturemins) };
|
|
|
|
st = ((st - texorg + lmorg) / 16) * surf->lightpic->size;
|
|
|
|
verts[i].tlst[2] = st[0];
|
|
|
|
verts[i].tlst[3] = st[1];
|
|
|
|
} else {
|
|
|
|
// no lightmap for this surface (probably sky or water), so
|
|
|
|
// make the lightmap texture polygone degenerate
|
2021-01-19 16:25:54 +00:00
|
|
|
verts[i].tlst[2] = 0;
|
|
|
|
verts[i].tlst[3] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
|
|
|
|
{
|
2021-01-20 06:11:50 +00:00
|
|
|
qfv_device_t *device = ctx->device;
|
2021-01-20 07:28:04 +00:00
|
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
2021-01-19 16:25:54 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
|
2022-04-25 22:26:32 +00:00
|
|
|
if (!num_models) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
facerefset_t *face_sets = alloca (bctx->registered_textures.size
|
|
|
|
* sizeof (facerefset_t));
|
|
|
|
for (size_t i = 0; i < bctx->registered_textures.size; i++) {
|
|
|
|
face_sets[i] = (facerefset_t) DARRAY_STATIC_INIT (1024);
|
|
|
|
}
|
|
|
|
|
2022-06-08 09:16:10 +00:00
|
|
|
for (int i = 0; i < bctx->num_models; i++) {
|
2022-05-25 04:29:11 +00:00
|
|
|
DARRAY_CLEAR (&bctx->main_pass.instances[i].entities);
|
|
|
|
}
|
|
|
|
free (bctx->main_pass.instances);
|
2022-06-08 09:16:10 +00:00
|
|
|
bctx->num_models = 0;
|
2022-05-25 04:29:11 +00:00
|
|
|
|
2021-07-13 13:59:51 +00:00
|
|
|
// run through all surfaces, chaining them to their textures, thus
|
2021-01-19 16:25:54 +00:00
|
|
|
// effectively sorting the surfaces by texture (without worrying about
|
|
|
|
// surface order on the same texture chain).
|
2022-05-22 16:28:43 +00:00
|
|
|
int face_base = 0;
|
2021-08-01 12:54:05 +00:00
|
|
|
for (int i = 0; i < num_models; i++) {
|
2022-05-11 10:24:39 +00:00
|
|
|
model_t *m = models[i];
|
2021-01-19 16:25:54 +00:00
|
|
|
// sub-models are done as part of the main model
|
2021-07-13 13:59:51 +00:00
|
|
|
// and non-bsp models don't have surfaces.
|
2022-05-25 04:29:11 +00:00
|
|
|
if (!m || m->type != mod_brush) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-06-08 09:16:10 +00:00
|
|
|
m->render_id = bctx->num_models++;
|
2022-05-25 04:29:11 +00:00
|
|
|
if (*m->path == '*') {
|
2021-01-19 16:25:54 +00:00
|
|
|
continue;
|
2022-05-25 04:29:11 +00:00
|
|
|
}
|
2022-05-11 10:24:39 +00:00
|
|
|
mod_brush_t *brush = &m->brush;
|
|
|
|
dmodel_t *dm = brush->submodels;
|
2021-08-01 12:54:05 +00:00
|
|
|
for (unsigned j = 0; j < brush->numsurfaces; j++) {
|
2021-01-19 16:25:54 +00:00
|
|
|
if (j == dm->firstface + dm->numfaces) {
|
2021-07-13 13:59:51 +00:00
|
|
|
// move on to the next sub-model
|
2021-01-19 16:25:54 +00:00
|
|
|
dm++;
|
2021-08-02 05:02:41 +00:00
|
|
|
if (dm == brush->submodels + brush->numsubmodels) {
|
2021-01-19 16:25:54 +00:00
|
|
|
// limit the surfaces
|
|
|
|
// probably never hit
|
2022-05-22 16:28:43 +00:00
|
|
|
Sys_Printf ("Vulkan_BuildDisplayLists: too many faces\n");
|
2021-02-01 10:31:11 +00:00
|
|
|
brush->numsurfaces = j;
|
2021-01-19 16:25:54 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-05-11 10:24:39 +00:00
|
|
|
msurface_t *surf = brush->surfaces + j;
|
2021-01-20 06:11:50 +00:00
|
|
|
// append surf to the texture chain
|
2022-05-11 10:24:39 +00:00
|
|
|
vulktex_t *tex = surf->texinfo->texture->render;
|
2022-05-22 16:28:43 +00:00
|
|
|
DARRAY_APPEND (&face_sets[tex->tex_id],
|
|
|
|
((faceref_t) { surf, m, face_base }));
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
2022-05-22 16:28:43 +00:00
|
|
|
face_base += brush->numsurfaces;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
2022-06-08 09:16:10 +00:00
|
|
|
bctx->main_pass.instances = malloc (bctx->num_models
|
2022-05-25 04:29:11 +00:00
|
|
|
* sizeof (bsp_instance_t));
|
2022-06-08 09:16:10 +00:00
|
|
|
for (int i = 0; i < bctx->num_models; i++) {
|
2022-05-25 04:29:11 +00:00
|
|
|
DARRAY_INIT (&bctx->main_pass.instances[i].entities, 16);
|
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
// All vertices from all brush models go into one giant vbo.
|
2021-01-20 06:11:50 +00:00
|
|
|
uint32_t vertex_count = 0;
|
|
|
|
uint32_t index_count = 0;
|
|
|
|
uint32_t poly_count = 0;
|
2022-05-22 16:28:43 +00:00
|
|
|
// This is not optimal as counted vertices are not shared between faces,
|
|
|
|
// however this greatly simplifies display list creation as no care needs
|
|
|
|
// to be taken when it comes to UVs, and every vertex needs a unique light
|
|
|
|
// map UV anyway (when lightmaps are used).
|
|
|
|
for (size_t i = 0; i < bctx->registered_textures.size; i++) {
|
|
|
|
for (size_t j = 0; j < face_sets[i].size; j++) {
|
|
|
|
faceref_t *faceref = &face_sets[i].a[j];
|
2021-01-20 06:11:50 +00:00
|
|
|
uint32_t verts, inds;
|
2022-05-22 16:28:43 +00:00
|
|
|
count_verts_inds (faceref, &verts, &inds);
|
2021-01-20 06:11:50 +00:00
|
|
|
vertex_count += verts;
|
|
|
|
index_count += inds;
|
|
|
|
poly_count++;
|
|
|
|
}
|
|
|
|
}
|
2021-01-20 07:28:04 +00:00
|
|
|
|
2022-05-29 13:13:36 +00:00
|
|
|
size_t atom = device->physDev->properties->limits.nonCoherentAtomSize;
|
2021-01-21 17:20:32 +00:00
|
|
|
size_t atom_mask = atom - 1;
|
2021-01-20 07:28:04 +00:00
|
|
|
size_t frames = bctx->frames.size;
|
|
|
|
size_t index_buffer_size = index_count * frames * sizeof (uint32_t);
|
|
|
|
size_t vertex_buffer_size = vertex_count * sizeof (bspvert_t);
|
2021-01-21 17:20:32 +00:00
|
|
|
|
|
|
|
index_buffer_size = (index_buffer_size + atom_mask) & ~atom_mask;
|
2022-05-11 10:24:39 +00:00
|
|
|
qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, "bsp",
|
|
|
|
vertex_buffer_size,
|
|
|
|
ctx->cmdpool);
|
2021-01-20 07:28:04 +00:00
|
|
|
qfv_packet_t *packet = QFV_PacketAcquire (stage);
|
2022-05-11 10:24:39 +00:00
|
|
|
bspvert_t *vertices = QFV_PacketExtend (packet, vertex_buffer_size);
|
|
|
|
// holds all the polygon definitions: vertex indices + poly_count
|
2022-05-22 16:28:43 +00:00
|
|
|
// primitive restart markers. The primitive restart markers are included
|
|
|
|
// in index_count.
|
2022-05-11 10:24:39 +00:00
|
|
|
// so each polygon within the list:
|
|
|
|
// index count-1 indices
|
|
|
|
// index
|
|
|
|
// ...
|
|
|
|
// "end of primitive" (~0u)
|
2022-05-22 16:28:43 +00:00
|
|
|
free (bctx->faces);
|
|
|
|
free (bctx->poly_indices);
|
2022-05-25 04:29:11 +00:00
|
|
|
free (bctx->models);
|
2022-06-08 09:16:10 +00:00
|
|
|
bctx->models = malloc (bctx->num_models * sizeof (bsp_model_t));
|
2022-05-22 16:28:43 +00:00
|
|
|
bctx->faces = malloc (face_base * sizeof (bsp_face_t));
|
|
|
|
bctx->poly_indices = malloc (index_count * sizeof (uint32_t));
|
2021-01-20 06:11:50 +00:00
|
|
|
|
2022-05-25 04:29:11 +00:00
|
|
|
face_base = 0;
|
|
|
|
for (int i = 0; i < num_models; i++) {
|
2022-05-25 11:08:36 +00:00
|
|
|
if (!models[i] || models[i]->type != mod_brush) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int num_faces = models[i]->brush.numsurfaces;
|
|
|
|
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;
|
2022-05-26 13:31:31 +00:00
|
|
|
while (i < num_models - 1 && models[i + 1]
|
|
|
|
&& models[i + 1]->path[0] == '*') {
|
2022-05-25 11:08:36 +00:00
|
|
|
i++;
|
|
|
|
m = &bctx->models[models[i]->render_id];
|
|
|
|
m->first_face = face_base + models[i]->brush.firstmodelsurface;
|
2022-05-25 04:29:11 +00:00
|
|
|
m->face_count = models[i]->brush.nummodelsurfaces;
|
|
|
|
}
|
2022-05-25 11:08:36 +00:00
|
|
|
face_base += num_faces;;
|
2022-05-25 04:29:11 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
// All usable surfaces have been chained to the (base) texture they use.
|
2022-05-11 10:24:39 +00:00
|
|
|
// Run through the textures, using their chains to build display lists.
|
2021-01-19 16:25:54 +00:00
|
|
|
// For animated textures, if a surface is on one texture of the group, it
|
2022-05-11 10:24:39 +00:00
|
|
|
// will effectively be on all (just one at a time).
|
2022-05-22 16:28:43 +00:00
|
|
|
buildctx_t build = {
|
|
|
|
.faces = bctx->faces,
|
|
|
|
.indices = bctx->poly_indices,
|
|
|
|
.vertices = vertices,
|
|
|
|
.index_base = 0,
|
|
|
|
.vertex_base = 0,
|
|
|
|
};
|
|
|
|
for (size_t i = 0; i < bctx->registered_textures.size; i++) {
|
|
|
|
build.tex_id = i;
|
|
|
|
for (size_t j = 0; j < face_sets[i].size; j++) {
|
|
|
|
faceref_t *faceref = &face_sets[i].a[j];
|
|
|
|
build_surf_displist (faceref, &build);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vulkan,
|
2022-05-22 16:28:43 +00:00
|
|
|
"R_BuildDisplayLists: verts:%u, inds:%u, polys:%u\n",
|
|
|
|
vertex_count, index_count, poly_count);
|
2021-01-20 07:28:04 +00:00
|
|
|
if (index_buffer_size > bctx->index_buffer_size) {
|
|
|
|
if (bctx->index_buffer) {
|
|
|
|
dfunc->vkUnmapMemory (device->dev, bctx->index_memory);
|
|
|
|
dfunc->vkDestroyBuffer (device->dev, bctx->index_buffer, 0);
|
|
|
|
dfunc->vkFreeMemory (device->dev, bctx->index_memory, 0);
|
|
|
|
}
|
|
|
|
bctx->index_buffer
|
|
|
|
= QFV_CreateBuffer (device, index_buffer_size,
|
|
|
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
2021-01-20 07:51:35 +00:00
|
|
|
| VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, bctx->index_buffer,
|
|
|
|
"buffer:bsp:index");
|
2021-01-20 07:28:04 +00:00
|
|
|
bctx->index_memory
|
|
|
|
= QFV_AllocBufferMemory (device, bctx->index_buffer,
|
2022-04-06 05:40:40 +00:00
|
|
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
2021-01-20 07:28:04 +00:00
|
|
|
index_buffer_size, 0);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY,
|
|
|
|
bctx->index_memory, "memory:bsp:index");
|
2021-01-20 07:28:04 +00:00
|
|
|
QFV_BindBufferMemory (device,
|
|
|
|
bctx->index_buffer, bctx->index_memory, 0);
|
|
|
|
bctx->index_buffer_size = index_buffer_size;
|
|
|
|
void *data;
|
|
|
|
dfunc->vkMapMemory (device->dev, bctx->index_memory, 0,
|
|
|
|
index_buffer_size, 0, &data);
|
|
|
|
uint32_t *index_data = data;
|
|
|
|
for (size_t i = 0; i < frames; i++) {
|
2021-01-20 07:51:35 +00:00
|
|
|
uint32_t offset = index_count * i;
|
|
|
|
bctx->frames.a[i].index_data = index_data + offset;
|
|
|
|
bctx->frames.a[i].index_offset = offset * sizeof (uint32_t);
|
2021-01-21 05:37:39 +00:00
|
|
|
bctx->frames.a[i].index_count = 0;
|
2021-01-20 07:28:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vertex_buffer_size > bctx->vertex_buffer_size) {
|
|
|
|
if (bctx->vertex_buffer) {
|
|
|
|
dfunc->vkDestroyBuffer (device->dev, bctx->vertex_buffer, 0);
|
|
|
|
dfunc->vkFreeMemory (device->dev, bctx->vertex_memory, 0);
|
|
|
|
}
|
|
|
|
bctx->vertex_buffer
|
|
|
|
= QFV_CreateBuffer (device, vertex_buffer_size,
|
|
|
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
|
|
|
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER,
|
|
|
|
bctx->vertex_buffer, "buffer:bsp:vertex");
|
2021-01-20 07:28:04 +00:00
|
|
|
bctx->vertex_memory
|
|
|
|
= QFV_AllocBufferMemory (device, bctx->vertex_buffer,
|
|
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
|
|
vertex_buffer_size, 0);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY,
|
|
|
|
bctx->vertex_memory, "memory:bsp:vertex");
|
2021-01-20 07:28:04 +00:00
|
|
|
QFV_BindBufferMemory (device,
|
|
|
|
bctx->vertex_buffer, bctx->vertex_memory, 0);
|
|
|
|
bctx->vertex_buffer_size = vertex_buffer_size;
|
|
|
|
}
|
|
|
|
|
2021-04-24 06:47:31 +00:00
|
|
|
qfv_bufferbarrier_t bb = bufferBarriers[qfv_BB_Unknown_to_TransferWrite];
|
|
|
|
bb.barrier.buffer = bctx->vertex_buffer;
|
|
|
|
bb.barrier.size = vertex_buffer_size;
|
|
|
|
dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages,
|
|
|
|
0, 0, 0, 1, &bb.barrier, 0, 0);
|
2021-01-20 07:28:04 +00:00
|
|
|
VkBufferCopy copy_region = { packet->offset, 0, vertex_buffer_size };
|
2021-01-21 12:24:54 +00:00
|
|
|
dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer,
|
2021-01-20 07:28:04 +00:00
|
|
|
bctx->vertex_buffer, 1, ©_region);
|
2021-04-24 06:47:31 +00:00
|
|
|
bb = bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead];
|
|
|
|
bb.barrier.buffer = bctx->vertex_buffer;
|
|
|
|
bb.barrier.size = vertex_buffer_size;
|
|
|
|
dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages,
|
|
|
|
0, 0, 0, 1, &bb.barrier, 0, 0);
|
2021-01-20 07:28:04 +00:00
|
|
|
QFV_PacketSubmit (packet);
|
2021-01-20 06:11:50 +00:00
|
|
|
QFV_DestroyStagingBuffer (stage);
|
2022-05-22 16:28:43 +00:00
|
|
|
for (size_t i = 0; i < bctx->registered_textures.size; i++) {
|
|
|
|
DARRAY_CLEAR (&face_sets[i]);
|
|
|
|
}
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2022-05-25 04:29:11 +00:00
|
|
|
static int
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
R_DrawBrushModel (entity_t ent, bsp_pass_t *pass, vulkan_ctx_t *ctx)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
transform_t transform = Entity_Transform (ent);
|
2022-10-25 03:53:30 +00:00
|
|
|
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg);
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
model_t *model = renderer->model;
|
2022-10-25 03:53:30 +00:00
|
|
|
float radius;
|
2021-03-19 11:18:45 +00:00
|
|
|
vec3_t mins, maxs;
|
2022-05-25 04:29:11 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-03-09 14:52:40 +00:00
|
|
|
mat4f_t mat;
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
Transform_GetWorldMatrix (transform, mat);
|
2021-03-09 14:52:40 +00:00
|
|
|
if (mat[0][0] != 1 || mat[1][1] != 1 || mat[2][2] != 1) {
|
2021-01-19 16:25:54 +00:00
|
|
|
radius = model->radius;
|
2022-05-31 06:32:12 +00:00
|
|
|
if (R_CullSphere (pass->frustum, (vec_t*)&mat[3], radius)) { //FIXME
|
2022-05-25 04:29:11 +00:00
|
|
|
return 1;
|
2021-03-19 11:18:45 +00:00
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
} else {
|
2021-03-19 11:18:45 +00:00
|
|
|
VectorAdd (mat[3], model->mins, mins);
|
|
|
|
VectorAdd (mat[3], model->maxs, maxs);
|
2022-05-31 06:32:12 +00:00
|
|
|
if (R_CullBox (pass->frustum, mins, maxs))
|
2022-05-25 04:29:11 +00:00
|
|
|
return 1;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
if (Vulkan_Scene_AddEntity (ctx, ent) < 0) {
|
2022-05-25 04:29:11 +00:00
|
|
|
return 0;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2022-10-25 03:53:30 +00:00
|
|
|
animation_t *animation = Ent_GetComponent (ent.id, scene_animation,
|
|
|
|
ent.reg);
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
pass->ent_frame = animation->frame & 1;
|
2022-05-25 04:29:11 +00:00
|
|
|
pass->inst_id = model->render_id;
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
pass->inst_id |= renderer->colormod[3] < 1 ? INST_ALPHA : 0;
|
2022-05-25 04:29:11 +00:00
|
|
|
if (!pass->instances[model->render_id].entities.size) {
|
|
|
|
bsp_model_t *m = &bctx->models[model->render_id];
|
|
|
|
bsp_face_t *face = &bctx->faces[m->first_face];
|
|
|
|
for (unsigned i = 0; i < m->face_count; i++, face++) {
|
|
|
|
// enqueue the polygon
|
|
|
|
chain_surface (face, pass, bctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-25 04:29:11 +00:00
|
|
|
DARRAY_APPEND (&pass->instances[model->render_id].entities,
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
renderer->render_id);
|
2022-05-25 04:29:11 +00:00
|
|
|
return 1;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
visit_leaf (mleaf_t *leaf)
|
|
|
|
{
|
2022-05-13 13:00:03 +00:00
|
|
|
// since this leaf will be rendered, any entities in the leaf also need
|
|
|
|
// to be rendered (the bsp tree doubles as an entity cull structure)
|
2021-01-19 16:25:54 +00:00
|
|
|
if (leaf->efrags)
|
|
|
|
R_StoreEfrags (leaf->efrags);
|
|
|
|
}
|
|
|
|
|
2022-05-13 13:00:03 +00:00
|
|
|
// 1 = back side, 0 = front side
|
2021-01-19 16:25:54 +00:00
|
|
|
static inline int
|
2022-05-31 06:32:12 +00:00
|
|
|
get_side (const bsp_pass_t *pass, const mnode_t *node)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
|
|
|
// find the node side on which we are
|
2022-05-31 06:32:12 +00:00
|
|
|
vec4f_t org = pass->position;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-22 02:18:32 +00:00
|
|
|
return dotf (org, node->plane)[0] < 0;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
2022-05-31 06:32:12 +00:00
|
|
|
visit_node (bsp_pass_t *pass, const mnode_t *node, int side)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2022-05-31 06:32:12 +00:00
|
|
|
bspctx_t *bctx = pass->bsp_context;
|
2021-01-19 16:25:54 +00:00
|
|
|
int c;
|
|
|
|
|
|
|
|
// sneaky hack for side = side ? SURF_PLANEBACK : 0;
|
2022-05-13 13:00:03 +00:00
|
|
|
// seems to be microscopically faster even on modern hardware
|
|
|
|
side = (-side) & SURF_PLANEBACK;
|
|
|
|
// chain any visible surfaces on the node that face the camera.
|
|
|
|
// not all nodes have any surfaces to draw (purely a split plane)
|
2021-01-19 16:25:54 +00:00
|
|
|
if ((c = node->numsurfaces)) {
|
2022-05-22 16:28:43 +00:00
|
|
|
const bsp_face_t *face = bctx->faces + node->firstsurface;
|
|
|
|
const int *frame = pass->face_frames + node->firstsurface;
|
2022-05-31 06:32:12 +00:00
|
|
|
int vis_frame = pass->vis_frame;
|
2022-05-22 16:28:43 +00:00
|
|
|
for (; c; c--, face++, frame++) {
|
2022-05-31 06:32:12 +00:00
|
|
|
if (*frame != vis_frame)
|
2021-01-19 16:25:54 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// side is either 0 or SURF_PLANEBACK
|
2022-05-13 13:00:03 +00:00
|
|
|
// if side and the surface facing differ, then the camera is
|
|
|
|
// on backside of the surface
|
2022-05-22 16:28:43 +00:00
|
|
|
if (side ^ (face->flags & SURF_PLANEBACK))
|
2021-01-19 16:25:54 +00:00
|
|
|
continue; // wrong side
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
chain_surface (face, pass, bctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
2022-05-31 06:32:12 +00:00
|
|
|
test_node (const bsp_pass_t *pass, int node_id)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2022-05-22 02:18:32 +00:00
|
|
|
if (node_id < 0)
|
2021-01-19 16:25:54 +00:00
|
|
|
return 0;
|
2022-05-31 06:32:12 +00:00
|
|
|
if (pass->node_frames[node_id] != pass->vis_frame)
|
2021-01-19 16:25:54 +00:00
|
|
|
return 0;
|
2022-05-31 06:32:12 +00:00
|
|
|
mnode_t *node = pass->brush->nodes + node_id;
|
|
|
|
if (R_CullBox (pass->frustum, node->minmaxs, node->minmaxs + 3))
|
2021-01-19 16:25:54 +00:00
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-05-31 06:32:12 +00:00
|
|
|
R_VisitWorldNodes (bsp_pass_t *pass, vulkan_ctx_t *ctx)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2022-05-31 06:32:12 +00:00
|
|
|
const mod_brush_t *brush = pass->brush;
|
2021-01-19 16:25:54 +00:00
|
|
|
typedef struct {
|
2022-05-22 02:18:32 +00:00
|
|
|
int node_id;
|
2021-01-19 16:25:54 +00:00
|
|
|
int side;
|
|
|
|
} rstack_t;
|
|
|
|
rstack_t *node_ptr;
|
|
|
|
rstack_t *node_stack;
|
2022-05-22 02:18:32 +00:00
|
|
|
int node_id;
|
|
|
|
int front;
|
2021-01-19 16:25:54 +00:00
|
|
|
int side;
|
|
|
|
|
2022-05-22 02:18:32 +00:00
|
|
|
node_id = 0;
|
2021-01-19 16:25:54 +00:00
|
|
|
// +2 for paranoia
|
2021-02-01 10:31:11 +00:00
|
|
|
node_stack = alloca ((brush->depth + 2) * sizeof (rstack_t));
|
2021-01-19 16:25:54 +00:00
|
|
|
node_ptr = node_stack;
|
|
|
|
|
|
|
|
while (1) {
|
2022-05-31 06:32:12 +00:00
|
|
|
while (test_node (pass, node_id)) {
|
2022-05-22 02:18:32 +00:00
|
|
|
mnode_t *node = brush->nodes + node_id;
|
2022-05-31 06:32:12 +00:00
|
|
|
side = get_side (pass, node);
|
2021-01-19 16:25:54 +00:00
|
|
|
front = node->children[side];
|
2022-05-31 06:32:12 +00:00
|
|
|
if (test_node (pass, front)) {
|
2022-05-22 02:18:32 +00:00
|
|
|
node_ptr->node_id = node_id;
|
2021-01-19 16:25:54 +00:00
|
|
|
node_ptr->side = side;
|
|
|
|
node_ptr++;
|
2022-05-22 02:18:32 +00:00
|
|
|
node_id = front;
|
2021-01-19 16:25:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
2021-07-22 07:13:12 +00:00
|
|
|
// front is either not a node (ie, is a leaf) or is not visible
|
|
|
|
// if node is visible, then at least one of its child nodes
|
|
|
|
// must also be visible, and a leaf child in front of the node
|
|
|
|
// will be visible, so no need for vis checks on a leaf
|
2022-05-22 02:18:32 +00:00
|
|
|
if (front < 0) {
|
|
|
|
mleaf_t *leaf = brush->leafs + ~front;
|
|
|
|
if (leaf->contents != CONTENTS_SOLID) {
|
|
|
|
visit_leaf (leaf);
|
|
|
|
}
|
|
|
|
}
|
2022-05-31 06:32:12 +00:00
|
|
|
visit_node (pass, node, side);
|
2022-05-22 02:18:32 +00:00
|
|
|
node_id = node->children[side ^ 1];
|
|
|
|
}
|
|
|
|
if (node_id < 0) {
|
|
|
|
mleaf_t *leaf = brush->leafs + ~node_id;
|
|
|
|
if (leaf->contents != CONTENTS_SOLID) {
|
|
|
|
visit_leaf (leaf);
|
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
if (node_ptr != node_stack) {
|
|
|
|
node_ptr--;
|
2022-05-22 02:18:32 +00:00
|
|
|
node_id = node_ptr->node_id;
|
2021-01-19 16:25:54 +00:00
|
|
|
side = node_ptr->side;
|
2022-05-22 02:18:32 +00:00
|
|
|
mnode_t *node = brush->nodes + node_id;
|
2022-05-31 06:32:12 +00:00
|
|
|
visit_node (pass, node, side);
|
2022-05-22 02:18:32 +00:00
|
|
|
node_id = node->children[side ^ 1];
|
2021-01-19 16:25:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 02:35:06 +00:00
|
|
|
static void
|
2021-12-17 03:20:32 +00:00
|
|
|
bind_texture (vulktex_t *tex, uint32_t setnum, VkPipelineLayout layout,
|
|
|
|
qfv_devfuncs_t *dfunc, VkCommandBuffer cmd)
|
2021-02-14 02:35:06 +00:00
|
|
|
{
|
2021-12-17 03:20:32 +00:00
|
|
|
VkDescriptorSet sets[] = {
|
|
|
|
tex->descriptor,
|
|
|
|
};
|
|
|
|
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
|
layout, setnum, 1, sets, 0, 0);
|
2021-02-14 02:35:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-12-17 06:51:33 +00:00
|
|
|
push_fragconst (bsp_push_constants_t *constants, VkPipelineLayout layout,
|
|
|
|
qfv_device_t *device, VkCommandBuffer cmd)
|
2021-02-14 02:35:06 +00:00
|
|
|
{
|
2021-12-17 06:51:33 +00:00
|
|
|
qfv_push_constants_t push_constants[] = {
|
|
|
|
//{ VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof (mat), mat },
|
|
|
|
{ VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
field_offset (bsp_push_constants_t, fog),
|
|
|
|
sizeof (constants->fog), &constants->fog },
|
|
|
|
{ VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
field_offset (bsp_push_constants_t, time),
|
|
|
|
sizeof (constants->time), &constants->time },
|
2022-05-21 08:48:45 +00:00
|
|
|
{ VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
field_offset (bsp_push_constants_t, alpha),
|
|
|
|
sizeof (constants->alpha), &constants->alpha },
|
2022-05-26 23:12:21 +00:00
|
|
|
{ VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
field_offset (bsp_push_constants_t, turb_scale),
|
|
|
|
sizeof (constants->turb_scale), &constants->turb_scale },
|
2021-12-17 06:51:33 +00:00
|
|
|
};
|
2022-05-26 23:12:21 +00:00
|
|
|
QFV_PushConstants (device, cmd, layout, 4, push_constants);
|
2021-02-14 02:35:06 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
static void
|
2021-02-19 02:14:54 +00:00
|
|
|
bsp_begin_subpass (QFV_BspSubpass subpass, VkPipeline pipeline,
|
2021-12-08 12:11:36 +00:00
|
|
|
VkPipelineLayout layout, qfv_renderframe_t *rFrame)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-12-02 12:58:29 +00:00
|
|
|
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
|
2021-01-19 16:25:54 +00:00
|
|
|
qfv_device_t *device = ctx->device;
|
|
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2021-02-05 01:22:32 +00:00
|
|
|
__auto_type cframe = &ctx->frames.a[ctx->curFrame];
|
2021-01-19 16:25:54 +00:00
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-02-19 02:14:54 +00:00
|
|
|
VkCommandBuffer cmd = bframe->cmdSet.a[subpass];
|
2021-01-20 17:13:40 +00:00
|
|
|
|
2021-01-20 07:51:35 +00:00
|
|
|
dfunc->vkResetCommandBuffer (cmd, 0);
|
2021-01-19 16:25:54 +00:00
|
|
|
VkCommandBufferInheritanceInfo inherit = {
|
|
|
|
VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 0,
|
2021-12-02 12:58:29 +00:00
|
|
|
rFrame->renderpass->renderpass, subpass_map[subpass],
|
2021-01-19 16:25:54 +00:00
|
|
|
cframe->framebuffer,
|
|
|
|
0, 0, 0,
|
|
|
|
};
|
|
|
|
VkCommandBufferBeginInfo beginInfo = {
|
|
|
|
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0,
|
|
|
|
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
|
|
|
|
| VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &inherit,
|
|
|
|
};
|
2021-01-20 07:51:35 +00:00
|
|
|
dfunc->vkBeginCommandBuffer (cmd, &beginInfo);
|
|
|
|
|
2021-04-18 11:40:43 +00:00
|
|
|
QFV_duCmdBeginLabel (device, cmd, va (ctx->va_ctx, "bsp:%s",
|
|
|
|
bsp_pass_names[subpass]),
|
2021-03-22 23:25:56 +00:00
|
|
|
{0, 0.5, 0.6, 1});
|
|
|
|
|
2021-01-20 07:51:35 +00:00
|
|
|
dfunc->vkCmdBindPipeline (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
2021-02-14 02:35:06 +00:00
|
|
|
pipeline);
|
2022-04-01 11:34:41 +00:00
|
|
|
dfunc->vkCmdSetViewport (cmd, 0, 1, &rFrame->renderpass->viewport);
|
|
|
|
dfunc->vkCmdSetScissor (cmd, 0, 1, &rFrame->renderpass->scissor);
|
2021-01-20 07:51:35 +00:00
|
|
|
|
2022-05-24 15:17:57 +00:00
|
|
|
VkBuffer buffers[] = { bctx->vertex_buffer, bctx->entid_buffer };
|
|
|
|
VkDeviceSize offsets[] = { 0, bframe->entid_offset };
|
|
|
|
dfunc->vkCmdBindVertexBuffers (cmd, 0, 2, buffers, offsets);
|
2021-01-20 07:51:35 +00:00
|
|
|
dfunc->vkCmdBindIndexBuffer (cmd, bctx->index_buffer, bframe->index_offset,
|
|
|
|
VK_INDEX_TYPE_UINT32);
|
|
|
|
|
2021-12-08 15:25:50 +00:00
|
|
|
VkDescriptorSet sets[] = {
|
2021-12-13 01:39:01 +00:00
|
|
|
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
|
2022-05-24 15:17:57 +00:00
|
|
|
Vulkan_Scene_Descriptors (ctx),
|
2021-12-08 12:11:36 +00:00
|
|
|
};
|
|
|
|
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
2022-05-24 15:17:57 +00:00
|
|
|
layout, 0, 2, sets, 0, 0);
|
2021-01-19 16:25:54 +00:00
|
|
|
|
|
|
|
//XXX glsl_Fog_GetColor (fog);
|
|
|
|
//XXX fog[3] = glsl_Fog_GetDensity () / 64.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-02-14 02:35:06 +00:00
|
|
|
bsp_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
|
|
|
qfv_device_t *device = ctx->device;
|
|
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
2021-02-14 02:35:06 +00:00
|
|
|
|
2021-03-22 23:25:56 +00:00
|
|
|
QFV_duCmdEndLabel (device, cmd);
|
2021-02-14 02:35:06 +00:00
|
|
|
dfunc->vkEndCommandBuffer (cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-12-02 12:58:29 +00:00
|
|
|
bsp_begin (qfv_renderframe_t *rFrame)
|
2021-02-14 02:35:06 +00:00
|
|
|
{
|
2021-12-02 12:58:29 +00:00
|
|
|
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
|
2021-01-19 16:25:54 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2021-02-14 02:35:06 +00:00
|
|
|
//XXX quat_t fog;
|
|
|
|
|
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
|
|
|
|
2021-12-02 12:58:29 +00:00
|
|
|
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passDepth],
|
2021-02-14 02:35:06 +00:00
|
|
|
bframe->cmdSet.a[QFV_bspDepth]);
|
2021-12-02 12:58:29 +00:00
|
|
|
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passGBuffer],
|
2021-02-14 02:35:06 +00:00
|
|
|
bframe->cmdSet.a[QFV_bspGBuffer]);
|
|
|
|
|
2021-12-17 03:20:32 +00:00
|
|
|
qfvPushDebug (ctx, "bsp_begin_subpass");
|
2021-12-08 12:11:36 +00:00
|
|
|
bsp_begin_subpass (QFV_bspDepth, bctx->depth, bctx->layout, rFrame);
|
|
|
|
bsp_begin_subpass (QFV_bspGBuffer, bctx->gbuf, bctx->layout, rFrame);
|
2021-12-17 03:20:32 +00:00
|
|
|
qfvPopDebug (ctx);
|
2021-02-14 02:35:06 +00:00
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-02-14 02:35:06 +00:00
|
|
|
static void
|
|
|
|
bsp_end (vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2021-01-19 16:25:54 +00:00
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-02-14 02:35:06 +00:00
|
|
|
|
|
|
|
bsp_end_subpass (bframe->cmdSet.a[QFV_bspDepth], ctx);
|
|
|
|
bsp_end_subpass (bframe->cmdSet.a[QFV_bspGBuffer], ctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 03:24:24 +00:00
|
|
|
static void
|
2021-12-02 12:58:29 +00:00
|
|
|
turb_begin (qfv_renderframe_t *rFrame)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-12-02 12:58:29 +00:00
|
|
|
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
|
2021-03-23 03:24:24 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-03-23 03:24:24 +00:00
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-12-02 12:58:29 +00:00
|
|
|
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent],
|
2021-03-23 03:24:24 +00:00
|
|
|
bframe->cmdSet.a[QFV_bspTurb]);
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-12-17 03:20:32 +00:00
|
|
|
qfvPushDebug (ctx, "bsp_begin_subpass");
|
2021-12-08 12:11:36 +00:00
|
|
|
bsp_begin_subpass (QFV_bspTurb, bctx->turb, bctx->layout, rFrame);
|
2021-12-17 03:20:32 +00:00
|
|
|
qfvPopDebug (ctx);
|
2021-03-23 03:24:24 +00:00
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-03-23 03:24:24 +00:00
|
|
|
static void
|
|
|
|
turb_end (vulkan_ctx_t *ctx)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-03-23 03:24:24 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-03-23 03:24:24 +00:00
|
|
|
bsp_end_subpass (bframe->cmdSet.a[QFV_bspTurb], ctx);
|
|
|
|
}
|
2022-02-18 04:29:41 +00:00
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
static void
|
2021-12-02 12:58:29 +00:00
|
|
|
sky_begin (qfv_renderframe_t *rFrame)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-12-02 12:58:29 +00:00
|
|
|
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
|
2021-01-23 11:42:53 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-01-23 11:42:53 +00:00
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-02-14 02:35:06 +00:00
|
|
|
|
2021-12-02 12:58:29 +00:00
|
|
|
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passTranslucent],
|
2021-03-23 03:24:24 +00:00
|
|
|
bframe->cmdSet.a[QFV_bspSky]);
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-12-17 03:20:32 +00:00
|
|
|
qfvPushDebug (ctx, "bsp_begin_subpass");
|
2021-03-25 06:54:34 +00:00
|
|
|
if (bctx->skybox_tex) {
|
2021-12-08 12:11:36 +00:00
|
|
|
bsp_begin_subpass (QFV_bspSky, bctx->skybox, bctx->layout, rFrame);
|
2021-03-25 06:54:34 +00:00
|
|
|
} else {
|
2021-12-08 12:11:36 +00:00
|
|
|
bsp_begin_subpass (QFV_bspSky, bctx->skysheet, bctx->layout, rFrame);
|
2021-03-25 06:54:34 +00:00
|
|
|
}
|
2021-12-17 03:20:32 +00:00
|
|
|
qfvPopDebug (ctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-01-23 11:42:53 +00:00
|
|
|
sky_end (vulkan_ctx_t *ctx)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-01-23 11:42:53 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-02-14 02:35:06 +00:00
|
|
|
|
2021-03-23 03:24:24 +00:00
|
|
|
bsp_end_subpass (bframe->cmdSet.a[QFV_bspSky], ctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
static void
|
|
|
|
clear_queues (bspctx_t *bctx, bsp_pass_t *pass)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2022-05-22 16:28:43 +00:00
|
|
|
for (size_t i = 0; i < bctx->registered_textures.size; i++) {
|
|
|
|
DARRAY_RESIZE (&pass->face_queue[i], 0);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
2022-05-25 04:29:11 +00:00
|
|
|
for (int i = 0; i < pass->num_queues; i++) {
|
|
|
|
DARRAY_RESIZE (&pass->draw_queues[i], 0);
|
|
|
|
}
|
2022-06-08 09:16:10 +00:00
|
|
|
for (int i = 0; i < bctx->num_models; i++) {
|
2022-05-25 04:29:11 +00:00
|
|
|
pass->instances[i].first_instance = -1;
|
|
|
|
DARRAY_RESIZE (&pass->instances[i].entities, 0);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
2022-05-22 16:28:43 +00:00
|
|
|
pass->index_count = 0;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2022-05-24 15:17:57 +00:00
|
|
|
static void
|
2022-05-31 06:32:12 +00:00
|
|
|
queue_faces (bsp_pass_t *pass, const bspctx_t *bctx, bspframe_t *bframe)
|
2022-05-24 15:17:57 +00:00
|
|
|
{
|
|
|
|
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) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (size_t j = 0; j < queue->size; j++) {
|
|
|
|
__auto_type is = queue->a[j];
|
|
|
|
__auto_type f = bctx->faces[is.face];
|
2022-05-25 04:29:11 +00:00
|
|
|
|
2022-05-26 23:12:21 +00:00
|
|
|
f.flags |= ((is.inst_id & INST_ALPHA)
|
|
|
|
>> (BITOP_LOG2(INST_ALPHA)
|
|
|
|
- BITOP_LOG2(SURF_DRAWALPHA))) & SURF_DRAWALPHA;
|
|
|
|
is.inst_id &= ~INST_ALPHA;
|
2022-05-25 04:29:11 +00:00
|
|
|
if (pass->instances[is.inst_id].first_instance == -1) {
|
|
|
|
uint32_t count = pass->instances[is.inst_id].entities.size;
|
|
|
|
pass->instances[is.inst_id].first_instance = pass->entid_count;
|
|
|
|
memcpy (pass->entid_data + pass->entid_count,
|
|
|
|
pass->instances[is.inst_id].entities.a,
|
|
|
|
count * sizeof (uint32_t));
|
|
|
|
pass->entid_count += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
int dq = 0;
|
2022-05-26 23:12:21 +00:00
|
|
|
if (f.flags & SURF_DRAWSKY) {
|
2022-05-25 04:29:11 +00:00
|
|
|
dq = 1;
|
|
|
|
}
|
2022-05-26 23:12:21 +00:00
|
|
|
if (f.flags & SURF_DRAWALPHA) {
|
2022-05-25 04:29:11 +00:00
|
|
|
dq = 2;
|
|
|
|
}
|
2022-05-26 23:12:21 +00:00
|
|
|
if (f.flags & SURF_DRAWTURB) {
|
|
|
|
dq = 3;
|
|
|
|
}
|
2022-05-25 04:29:11 +00:00
|
|
|
|
|
|
|
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
|
2022-05-26 13:31:31 +00:00
|
|
|
|| draw->tex_id != i
|
2022-05-25 04:29:11 +00:00
|
|
|
|| draw->inst_id != is.inst_id) {
|
|
|
|
bsp_instance_t *instance = &pass->instances[is.inst_id];
|
|
|
|
DARRAY_APPEND (&pass->draw_queues[dq], ((bsp_draw_t) {
|
|
|
|
.tex_id = i,
|
|
|
|
.inst_id = is.inst_id,
|
|
|
|
.instance_count = instance->entities.size,
|
|
|
|
.first_index = pass->index_count,
|
|
|
|
.first_instance = instance->first_instance,
|
|
|
|
}));
|
|
|
|
dq_size = pass->draw_queues[dq].size;
|
|
|
|
draw = &pass->draw_queues[dq].a[dq_size - 1];
|
|
|
|
}
|
|
|
|
|
2022-05-24 15:17:57 +00:00
|
|
|
memcpy (pass->indices + pass->index_count,
|
|
|
|
bctx->poly_indices + f.first_index,
|
|
|
|
f.index_count * sizeof (uint32_t));
|
2022-05-25 04:29:11 +00:00
|
|
|
draw->index_count += f.index_count;
|
2022-05-24 15:17:57 +00:00
|
|
|
pass->index_count += f.index_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bframe->index_count += pass->index_count;
|
|
|
|
}
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
static void
|
2022-05-22 16:28:43 +00:00
|
|
|
draw_queue (bsp_pass_t *pass, int queue, VkPipelineLayout layout,
|
|
|
|
qfv_device_t *device, VkCommandBuffer cmd)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2022-05-22 16:28:43 +00:00
|
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
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];
|
2022-05-24 15:17:57 +00:00
|
|
|
bind_texture (tex, 2, layout, dfunc, cmd);
|
2022-05-22 16:28:43 +00:00
|
|
|
}
|
|
|
|
dfunc->vkCmdDrawIndexed (cmd, d.index_count, d.instance_count,
|
|
|
|
d.first_index, 0, d.first_instance);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-24 15:17:57 +00:00
|
|
|
static int
|
2022-05-25 04:29:11 +00:00
|
|
|
ent_model_cmp (const void *_a, const void *_b)
|
2022-05-24 15:17:57 +00:00
|
|
|
{
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
const entity_t *a = _a;
|
|
|
|
const entity_t *b = _b;
|
2022-10-25 03:53:30 +00:00
|
|
|
renderer_t *ra = Ent_GetComponent (a->id, scene_renderer, a->reg);
|
|
|
|
renderer_t *rb = Ent_GetComponent (b->id, scene_renderer, b->reg);
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
return ra->model->render_id - rb->model->render_id;
|
2022-05-24 15:17:57 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
void
|
2021-12-02 12:58:29 +00:00
|
|
|
Vulkan_DrawWorld (qfv_renderframe_t *rFrame)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-12-02 12:58:29 +00:00
|
|
|
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
|
2021-01-20 17:13:40 +00:00
|
|
|
qfv_device_t *device = ctx->device;
|
2022-05-22 16:28:43 +00:00
|
|
|
//qfv_devfuncs_t *dfunc = device->funcs;
|
2021-01-19 16:25:54 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2021-01-20 17:13:40 +00:00
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-31 06:32:12 +00:00
|
|
|
bctx->main_pass.bsp_context = bctx;
|
|
|
|
bctx->main_pass.position = r_refdef.frame.position;
|
|
|
|
bctx->main_pass.frustum = r_refdef.frustum;
|
|
|
|
bctx->main_pass.vis_frame = r_visframecount;
|
2022-05-22 16:28:43 +00:00
|
|
|
bctx->main_pass.face_frames = r_face_visframes;
|
|
|
|
bctx->main_pass.leaf_frames = r_leaf_visframes;
|
|
|
|
bctx->main_pass.node_frames = r_node_visframes;
|
2022-05-24 15:17:57 +00:00
|
|
|
bctx->main_pass.entid_data = bframe->entid_data;
|
|
|
|
bctx->main_pass.entid_count = 0;
|
2022-05-22 16:28:43 +00:00
|
|
|
|
2022-05-26 13:31:31 +00:00
|
|
|
bctx->anim_index = r_data->realtime * 5;
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
clear_queues (bctx, &bctx->main_pass); // do this first for water and skys
|
2021-01-21 05:37:39 +00:00
|
|
|
bframe->index_count = 0;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
entity_t worldent = nullentity;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
int world_id = Vulkan_Scene_AddEntity (ctx, worldent);
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-26 13:31:31 +00:00
|
|
|
bctx->main_pass.ent_frame = 0; // world is always frame 0
|
2022-05-25 04:29:11 +00:00
|
|
|
bctx->main_pass.inst_id = world_id;
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
bctx->main_pass.brush = &r_refdef.worldmodel->brush;
|
2022-05-28 09:14:26 +00:00
|
|
|
if (bctx->main_pass.instances) {
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
DARRAY_APPEND (&bctx->main_pass.instances[world_id].entities, world_id);
|
2022-05-28 09:14:26 +00:00
|
|
|
}
|
2022-05-31 06:32:12 +00:00
|
|
|
R_VisitWorldNodes (&bctx->main_pass, ctx);
|
2022-04-25 22:26:32 +00:00
|
|
|
if (!bctx->vertex_buffer) {
|
|
|
|
return;
|
|
|
|
}
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
if (r_drawentities) {
|
2022-05-25 04:29:11 +00:00
|
|
|
heapsort (r_ent_queue->ent_queues[mod_brush].a,
|
|
|
|
r_ent_queue->ent_queues[mod_brush].size,
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
sizeof (entity_t), ent_model_cmp);
|
2022-03-04 16:48:10 +00:00
|
|
|
for (size_t i = 0; i < r_ent_queue->ent_queues[mod_brush].size; i++) {
|
[scene] Make entity_t just an entity id for ECS
This puts the hierarchy (transform) reference, animation, visibility,
renderer, active, and old_origin data in separate components. There are
a few bugs (crashes on grenade explosions in gl/glsl/vulkan, immediately
in sw, reasons known, missing brush models in vulkan).
While quake doesn't really need an ECS, the direction I want to take QF
does, and it does seem to have improved memory bandwidth a little
(uncertain). However, there's a lot more work to go (especially fixing
the above bugs), but this seems to be a good start.
2022-10-23 01:32:09 +00:00
|
|
|
entity_t ent = r_ent_queue->ent_queues[mod_brush].a[i];
|
2022-05-25 04:29:11 +00:00
|
|
|
if (!R_DrawBrushModel (ent, &bctx->main_pass, ctx)) {
|
|
|
|
Sys_Printf ("Too many entities!\n");
|
|
|
|
break;
|
2022-05-24 15:17:57 +00:00
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-25 04:29:11 +00:00
|
|
|
bframe->entid_count = bctx->main_pass.entid_count;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-24 15:17:57 +00:00
|
|
|
queue_faces (&bctx->main_pass, bctx, bframe);
|
|
|
|
|
2021-12-02 12:58:29 +00:00
|
|
|
bsp_begin (rFrame);
|
2021-01-20 17:13:40 +00:00
|
|
|
|
2022-03-30 16:26:57 +00:00
|
|
|
bsp_push_constants_t frag_constants = { .time = vr_data.realtime };
|
2021-12-17 06:51:33 +00:00
|
|
|
push_fragconst (&frag_constants, bctx->layout, device,
|
2021-02-14 02:35:06 +00:00
|
|
|
bframe->cmdSet.a[QFV_bspGBuffer]);
|
2022-05-22 16:28:43 +00:00
|
|
|
VkPipelineLayout layout = bctx->layout;
|
2022-05-24 15:17:57 +00:00
|
|
|
|
|
|
|
__auto_type pass = &bctx->main_pass;
|
2022-05-22 16:28:43 +00:00
|
|
|
pass->textures = 0;
|
|
|
|
draw_queue (pass, 0, layout, device, bframe->cmdSet.a[QFV_bspDepth]);
|
|
|
|
pass->textures = &bctx->registered_textures;
|
|
|
|
draw_queue (pass, 0, layout, device, bframe->cmdSet.a[QFV_bspGBuffer]);
|
2021-01-19 16:25:54 +00:00
|
|
|
bsp_end (ctx);
|
2021-12-17 06:52:17 +00:00
|
|
|
}
|
2021-01-21 17:20:32 +00:00
|
|
|
|
2021-12-17 06:52:17 +00:00
|
|
|
void
|
|
|
|
Vulkan_Bsp_Flush (vulkan_ctx_t *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];
|
2022-05-29 13:13:36 +00:00
|
|
|
size_t atom = device->physDev->properties->limits.nonCoherentAtomSize;
|
2021-01-21 17:20:32 +00:00
|
|
|
size_t atom_mask = atom - 1;
|
2022-05-24 15:17:57 +00:00
|
|
|
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);
|
2021-01-21 17:20:32 +00:00
|
|
|
|
2022-04-25 22:26:32 +00:00
|
|
|
if (!bframe->index_count) {
|
|
|
|
return;
|
|
|
|
}
|
2022-05-24 15:17:57 +00:00
|
|
|
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 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
|
|
|
|
},
|
2021-01-21 17:20:32 +00:00
|
|
|
};
|
2022-05-24 15:17:57 +00:00
|
|
|
dfunc->vkFlushMappedMemoryRanges (device->dev, 2, ranges);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-12-02 12:58:29 +00:00
|
|
|
Vulkan_DrawWaterSurfaces (qfv_renderframe_t *rFrame)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-12-02 12:58:29 +00:00
|
|
|
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
|
2021-03-23 03:24:24 +00:00
|
|
|
qfv_device_t *device = ctx->device;
|
2022-05-22 16:28:43 +00:00
|
|
|
//qfv_devfuncs_t *dfunc = device->funcs;
|
2021-03-23 03:24:24 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-26 23:12:21 +00:00
|
|
|
if (!bctx->main_pass.draw_queues[3].size)
|
2021-01-19 16:25:54 +00:00
|
|
|
return;
|
|
|
|
|
2021-12-02 12:58:29 +00:00
|
|
|
turb_begin (rFrame);
|
2022-05-26 23:12:21 +00:00
|
|
|
|
|
|
|
VkPipelineLayout layout = bctx->layout;
|
2022-05-21 08:48:45 +00:00
|
|
|
bsp_push_constants_t frag_constants = {
|
|
|
|
.time = vr_data.realtime,
|
2022-05-26 23:12:21 +00:00
|
|
|
.alpha = 1,
|
|
|
|
.turb_scale = 0,
|
2022-05-21 08:48:45 +00:00
|
|
|
};
|
2022-05-26 23:12:21 +00:00
|
|
|
push_fragconst (&frag_constants, layout, device,
|
2021-03-23 03:24:24 +00:00
|
|
|
bframe->cmdSet.a[QFV_bspTurb]);
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
__auto_type pass = &bctx->main_pass;
|
|
|
|
pass->textures = &bctx->registered_textures;
|
|
|
|
draw_queue (pass, 2, layout, device, bframe->cmdSet.a[QFV_bspTurb]);
|
|
|
|
|
2022-05-26 23:12:21 +00:00
|
|
|
frag_constants.alpha = r_wateralpha;
|
|
|
|
frag_constants.turb_scale = 1;
|
|
|
|
push_fragconst (&frag_constants, bctx->layout, device,
|
|
|
|
bframe->cmdSet.a[QFV_bspTurb]);
|
|
|
|
draw_queue (pass, 3, layout, device, bframe->cmdSet.a[QFV_bspTurb]);
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
turb_end (ctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-12-02 12:58:29 +00:00
|
|
|
Vulkan_DrawSky (qfv_renderframe_t *rFrame)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-12-02 12:58:29 +00:00
|
|
|
vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
|
2021-01-23 11:42:53 +00:00
|
|
|
qfv_device_t *device = ctx->device;
|
|
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
2021-01-19 16:25:54 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
2021-01-20 17:13:40 +00:00
|
|
|
bspframe_t *bframe = &bctx->frames.a[ctx->curFrame];
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
if (!bctx->main_pass.draw_queues[1].size)
|
2021-01-19 16:25:54 +00:00
|
|
|
return;
|
|
|
|
|
2021-12-02 12:58:29 +00:00
|
|
|
sky_begin (rFrame);
|
2021-12-17 03:20:32 +00:00
|
|
|
vulktex_t skybox = { .descriptor = bctx->skybox_descriptor };
|
2022-05-24 15:17:57 +00:00
|
|
|
bind_texture (&skybox, 3, bctx->layout, dfunc,
|
2021-12-17 03:20:32 +00:00
|
|
|
bframe->cmdSet.a[QFV_bspSky]);
|
2022-03-30 16:26:57 +00:00
|
|
|
bsp_push_constants_t frag_constants = { .time = vr_data.realtime };
|
2021-12-17 06:51:33 +00:00
|
|
|
push_fragconst (&frag_constants, bctx->layout, device,
|
2021-03-23 03:24:24 +00:00
|
|
|
bframe->cmdSet.a[QFV_bspSky]);
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
VkPipelineLayout layout = bctx->layout;
|
|
|
|
__auto_type pass = &bctx->main_pass;
|
|
|
|
pass->textures = &bctx->registered_textures;
|
|
|
|
draw_queue (pass, 1, layout, device, bframe->cmdSet.a[QFV_bspSky]);
|
|
|
|
|
|
|
|
sky_end (ctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2021-01-23 11:42:53 +00:00
|
|
|
static void
|
|
|
|
create_default_skys (vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
qfv_device_t *device = ctx->device;
|
|
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
VkImage skybox;
|
|
|
|
VkImage skysheet;
|
|
|
|
VkDeviceMemory memory;
|
|
|
|
VkImageView boxview;
|
|
|
|
VkImageView sheetview;
|
|
|
|
|
|
|
|
bctx->default_skybox = calloc (2, sizeof (qfv_tex_t));
|
|
|
|
bctx->default_skysheet = bctx->default_skybox + 1;
|
|
|
|
|
|
|
|
VkExtent3D extents = { 1, 1, 1 };
|
|
|
|
skybox = QFV_CreateImage (device, 1, VK_IMAGE_TYPE_2D,
|
|
|
|
VK_FORMAT_B8G8R8A8_UNORM, extents, 1, 1,
|
|
|
|
VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
VK_IMAGE_USAGE_SAMPLED_BIT
|
|
|
|
| VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skybox,
|
|
|
|
"bsp:image:default_skybox");
|
2021-01-23 11:42:53 +00:00
|
|
|
|
|
|
|
skysheet = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D,
|
|
|
|
VK_FORMAT_B8G8R8A8_UNORM, extents, 1, 2,
|
|
|
|
VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
VK_IMAGE_USAGE_SAMPLED_BIT
|
|
|
|
| VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, skysheet,
|
|
|
|
"bsp:image:default_skysheet");
|
|
|
|
|
2021-01-23 11:42:53 +00:00
|
|
|
VkMemoryRequirements requirements;
|
|
|
|
dfunc->vkGetImageMemoryRequirements (device->dev, skybox, &requirements);
|
|
|
|
size_t boxsize = requirements.size;
|
|
|
|
dfunc->vkGetImageMemoryRequirements (device->dev, skysheet, &requirements);
|
|
|
|
size_t sheetsize = requirements.size;
|
|
|
|
|
|
|
|
memory = QFV_AllocImageMemory (device, skybox,
|
|
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
|
|
boxsize + sheetsize,
|
|
|
|
VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
|
|
|
| VK_IMAGE_USAGE_SAMPLED_BIT);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, memory,
|
|
|
|
"bsp:memory:default_skys");
|
2021-01-23 11:42:53 +00:00
|
|
|
|
|
|
|
QFV_BindImageMemory (device, skybox, memory, 0);
|
|
|
|
QFV_BindImageMemory (device, skysheet, memory, boxsize);
|
|
|
|
|
|
|
|
boxview = QFV_CreateImageView (device, skybox, VK_IMAGE_VIEW_TYPE_CUBE,
|
|
|
|
VK_FORMAT_B8G8R8A8_UNORM,
|
|
|
|
VK_IMAGE_ASPECT_COLOR_BIT);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, boxview,
|
2021-03-25 06:54:34 +00:00
|
|
|
"bsp:iview:default_skybox");
|
2021-01-23 11:42:53 +00:00
|
|
|
|
|
|
|
sheetview = QFV_CreateImageView (device, skysheet,
|
|
|
|
VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
|
|
|
VK_FORMAT_B8G8R8A8_UNORM,
|
|
|
|
VK_IMAGE_ASPECT_COLOR_BIT);
|
2021-01-31 10:58:55 +00:00
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, sheetview,
|
|
|
|
"bsp:iview:default_skysheet");
|
2021-01-23 11:42:53 +00:00
|
|
|
|
|
|
|
bctx->default_skybox->image = skybox;
|
|
|
|
bctx->default_skybox->view = boxview;
|
|
|
|
bctx->default_skybox->memory = memory;
|
|
|
|
bctx->default_skysheet->image = skysheet;
|
|
|
|
bctx->default_skysheet->view = sheetview;
|
|
|
|
|
|
|
|
// temporarily commandeer the light map's staging buffer
|
|
|
|
qfv_packet_t *packet = QFV_PacketAcquire (bctx->light_stage);
|
2021-04-24 03:42:29 +00:00
|
|
|
|
|
|
|
qfv_imagebarrier_t ib = imageBarriers[qfv_LT_Undefined_to_TransferDst];
|
|
|
|
ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
|
|
|
ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
|
|
|
VkImageMemoryBarrier barriers[2] = { ib.barrier, ib.barrier };
|
2021-01-23 11:42:53 +00:00
|
|
|
barriers[0].image = skybox;
|
|
|
|
barriers[1].image = skysheet;
|
2021-04-24 03:42:29 +00:00
|
|
|
dfunc->vkCmdPipelineBarrier (packet->cmd, ib.srcStages, ib.dstStages,
|
2021-01-23 11:42:53 +00:00
|
|
|
0, 0, 0, 0, 0,
|
|
|
|
2, barriers);
|
|
|
|
|
|
|
|
VkClearColorValue color = {};
|
|
|
|
VkImageSubresourceRange range = {
|
|
|
|
VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
0, VK_REMAINING_MIP_LEVELS,
|
|
|
|
0, VK_REMAINING_ARRAY_LAYERS
|
|
|
|
};
|
|
|
|
dfunc->vkCmdClearColorImage (packet->cmd, skybox,
|
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
&color, 1, &range);
|
|
|
|
dfunc->vkCmdClearColorImage (packet->cmd, skysheet,
|
|
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
|
|
&color, 1, &range);
|
|
|
|
|
2021-04-24 03:42:29 +00:00
|
|
|
ib = imageBarriers[qfv_LT_TransferDst_to_ShaderReadOnly];
|
|
|
|
ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
|
|
|
ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
|
|
|
barriers[0] = ib.barrier;
|
|
|
|
barriers[1] = ib.barrier;
|
2021-01-23 11:42:53 +00:00
|
|
|
barriers[0].image = skybox;
|
|
|
|
barriers[1].image = skysheet;
|
2021-04-24 03:42:29 +00:00
|
|
|
dfunc->vkCmdPipelineBarrier (packet->cmd, ib.srcStages, ib.dstStages,
|
2021-01-23 11:42:53 +00:00
|
|
|
0, 0, 0, 0, 0,
|
|
|
|
2, barriers);
|
|
|
|
QFV_PacketSubmit (packet);
|
|
|
|
}
|
|
|
|
|
2022-05-26 10:14:44 +00:00
|
|
|
static void
|
|
|
|
create_notexture (vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
const char *missing = "Missing";
|
|
|
|
byte data[2][64 * 64 * 4]; // 2 * 64x64 rgba (8x8 chars)
|
|
|
|
tex_t tex[2] = {
|
|
|
|
{ .width = 64,
|
|
|
|
.height = 64,
|
|
|
|
.format = tex_rgba,
|
|
|
|
.loaded = 1,
|
|
|
|
.data = data[0],
|
|
|
|
},
|
|
|
|
{ .width = 64,
|
|
|
|
.height = 64,
|
|
|
|
.format = tex_rgba,
|
|
|
|
.loaded = 1,
|
|
|
|
.data = data[1],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 0; i < 64 * 64; i++) {
|
|
|
|
data[0][i * 4 + 0] = 0x20;
|
|
|
|
data[0][i * 4 + 1] = 0x20;
|
|
|
|
data[0][i * 4 + 2] = 0x20;
|
|
|
|
data[0][i * 4 + 3] = 0xff;
|
|
|
|
|
|
|
|
data[1][i * 4 + 0] = 0x00;
|
|
|
|
data[1][i * 4 + 1] = 0x00;
|
|
|
|
data[1][i * 4 + 2] = 0x00;
|
|
|
|
data[1][i * 4 + 3] = 0xff;
|
|
|
|
}
|
|
|
|
int x = 4;
|
|
|
|
int y = 4;
|
|
|
|
for (const char *c = missing; *c; c++) {
|
|
|
|
byte *bitmap = font8x8_data + *c * 8;
|
|
|
|
for (int l = 0; l < 8; l++) {
|
|
|
|
byte d = *bitmap++;
|
|
|
|
for (int b = 0; b < 8; b++) {
|
|
|
|
if (d & 0x80) {
|
|
|
|
int base = ((y + l) * 64 + x + b) * 4;
|
|
|
|
data[0][base + 0] = 0x00;
|
|
|
|
data[0][base + 1] = 0x00;
|
|
|
|
data[0][base + 2] = 0x00;
|
|
|
|
data[0][base + 3] = 0xff;
|
|
|
|
|
|
|
|
data[1][base + 0] = 0xff;
|
|
|
|
data[1][base + 1] = 0x00;
|
|
|
|
data[1][base + 2] = 0xff;
|
|
|
|
data[1][base + 3] = 0xff;
|
|
|
|
}
|
|
|
|
d <<= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x += 8;
|
|
|
|
}
|
|
|
|
for (int i = 1; i < 7; i++) {
|
|
|
|
y += 8;
|
|
|
|
memcpy (data[0] + y * 64 * 4, data[0] + 4 * 64 * 4, 8 * 64 * 4);
|
|
|
|
memcpy (data[1] + y * 64 * 4, data[1] + 4 * 64 * 4, 8 * 64 * 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
bctx->notexture.tex = Vulkan_LoadTexArray (ctx, tex, 2, 1, "notexture");
|
|
|
|
}
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
void
|
|
|
|
Vulkan_Bsp_Init (vulkan_ctx_t *ctx)
|
|
|
|
{
|
|
|
|
qfv_device_t *device = ctx->device;
|
2022-05-24 15:17:57 +00:00
|
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-12-02 13:48:50 +00:00
|
|
|
qfvPushDebug (ctx, "bsp init");
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
bspctx_t *bctx = calloc (1, sizeof (bspctx_t));
|
|
|
|
ctx->bsp_context = bctx;
|
|
|
|
|
2021-01-31 10:58:55 +00:00
|
|
|
bctx->light_scrap = QFV_CreateScrap (device, "lightmap_atlas", 2048,
|
|
|
|
tex_frgba, ctx->staging);
|
2021-01-19 16:25:54 +00:00
|
|
|
size_t size = QFV_ScrapSize (bctx->light_scrap);
|
2021-01-31 10:58:55 +00:00
|
|
|
bctx->light_stage = QFV_CreateStagingBuffer (device, "lightmap", size,
|
|
|
|
ctx->cmdpool);
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-01-23 11:42:53 +00:00
|
|
|
create_default_skys (ctx);
|
2022-05-26 10:14:44 +00:00
|
|
|
create_notexture (ctx);
|
2021-01-23 11:42:53 +00:00
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
DARRAY_INIT (&bctx->registered_textures, 64);
|
|
|
|
|
2022-05-26 23:12:21 +00:00
|
|
|
bctx->main_pass.num_queues = 4;//solid, sky, water, transparent
|
2022-05-22 16:28:43 +00:00
|
|
|
bctx->main_pass.draw_queues = malloc (bctx->main_pass.num_queues
|
|
|
|
* sizeof (bsp_drawset_t));
|
|
|
|
for (int i = 0; i < bctx->main_pass.num_queues; i++) {
|
|
|
|
DARRAY_INIT (&bctx->main_pass.draw_queues[i], 64);
|
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2021-02-05 01:22:32 +00:00
|
|
|
size_t frames = ctx->frames.size;
|
2021-01-19 16:25:54 +00:00
|
|
|
DARRAY_INIT (&bctx->frames, frames);
|
|
|
|
DARRAY_RESIZE (&bctx->frames, frames);
|
|
|
|
bctx->frames.grow = 0;
|
|
|
|
|
2021-12-16 14:00:17 +00:00
|
|
|
bctx->depth = Vulkan_CreateGraphicsPipeline (ctx, "bsp_depth");
|
|
|
|
bctx->gbuf = Vulkan_CreateGraphicsPipeline (ctx, "bsp_gbuf");
|
|
|
|
bctx->skybox = Vulkan_CreateGraphicsPipeline (ctx, "bsp_skybox");
|
|
|
|
bctx->skysheet = Vulkan_CreateGraphicsPipeline (ctx, "bsp_skysheet");
|
|
|
|
bctx->turb = Vulkan_CreateGraphicsPipeline (ctx, "bsp_turb");
|
2021-02-04 08:03:49 +00:00
|
|
|
bctx->layout = Vulkan_CreatePipelineLayout (ctx, "quakebsp_layout");
|
|
|
|
bctx->sampler = Vulkan_CreateSampler (ctx, "quakebsp_sampler");
|
2021-01-19 16:25:54 +00:00
|
|
|
|
2022-05-25 04:29:11 +00:00
|
|
|
size_t entid_count = Vulkan_Scene_MaxEntities (ctx);
|
|
|
|
size_t entid_size = entid_count * sizeof (uint32_t);
|
2022-05-29 13:13:36 +00:00
|
|
|
size_t atom = device->physDev->properties->limits.nonCoherentAtomSize;
|
2022-05-24 15:17:57 +00:00
|
|
|
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);
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
for (size_t i = 0; i < frames; i++) {
|
|
|
|
__auto_type bframe = &bctx->frames.a[i];
|
2021-02-14 02:35:06 +00:00
|
|
|
|
|
|
|
DARRAY_INIT (&bframe->cmdSet, QFV_bspNumPasses);
|
|
|
|
DARRAY_RESIZE (&bframe->cmdSet, QFV_bspNumPasses);
|
|
|
|
bframe->cmdSet.grow = 0;
|
|
|
|
|
|
|
|
QFV_AllocateCommandBuffers (device, ctx->cmdpool, 1, &bframe->cmdSet);
|
|
|
|
|
|
|
|
for (int j = 0; j < QFV_bspNumPasses; j++) {
|
|
|
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_COMMAND_BUFFER,
|
|
|
|
bframe->cmdSet.a[i],
|
|
|
|
va (ctx->va_ctx, "cmd:bsp:%zd:%s", i,
|
|
|
|
bsp_pass_names[j]));
|
|
|
|
}
|
2022-05-25 04:29:11 +00:00
|
|
|
bframe->entid_data = entid_data + i * entid_count;
|
2022-05-24 15:17:57 +00:00
|
|
|
bframe->entid_offset = i * entid_size;
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
2021-12-17 03:20:32 +00:00
|
|
|
|
|
|
|
bctx->skybox_descriptor
|
|
|
|
= Vulkan_CreateTextureDescriptor (ctx, bctx->default_skybox,
|
|
|
|
bctx->sampler);
|
2022-05-26 10:14:44 +00:00
|
|
|
bctx->notexture.descriptor
|
|
|
|
= Vulkan_CreateTextureDescriptor (ctx, bctx->notexture.tex,
|
|
|
|
bctx->sampler);
|
|
|
|
|
|
|
|
r_notexture_mip->render = &bctx->notexture;
|
2021-12-17 03:20:32 +00:00
|
|
|
|
2021-12-02 13:48:50 +00:00
|
|
|
qfvPopDebug (ctx);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Vulkan_Bsp_Shutdown (struct vulkan_ctx_s *ctx)
|
|
|
|
{
|
|
|
|
qfv_device_t *device = ctx->device;
|
|
|
|
qfv_devfuncs_t *dfunc = device->funcs;
|
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
|
2021-02-14 02:35:06 +00:00
|
|
|
for (size_t i = 0; i < bctx->frames.size; i++) {
|
|
|
|
__auto_type bframe = &bctx->frames.a[i];
|
|
|
|
free (bframe->cmdSet.a);
|
|
|
|
}
|
|
|
|
|
2021-02-19 02:14:54 +00:00
|
|
|
dfunc->vkDestroyPipeline (device->dev, bctx->depth, 0);
|
|
|
|
dfunc->vkDestroyPipeline (device->dev, bctx->gbuf, 0);
|
2021-03-25 06:54:34 +00:00
|
|
|
dfunc->vkDestroyPipeline (device->dev, bctx->skybox, 0);
|
|
|
|
dfunc->vkDestroyPipeline (device->dev, bctx->skysheet, 0);
|
2021-03-23 03:24:24 +00:00
|
|
|
dfunc->vkDestroyPipeline (device->dev, bctx->turb, 0);
|
2022-05-25 04:29:11 +00:00
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
DARRAY_CLEAR (&bctx->registered_textures);
|
|
|
|
for (int i = 0; i < bctx->main_pass.num_queues; i++) {
|
|
|
|
DARRAY_CLEAR (&bctx->main_pass.draw_queues[i]);
|
|
|
|
}
|
2022-05-25 04:29:11 +00:00
|
|
|
|
|
|
|
free (bctx->faces);
|
|
|
|
free (bctx->models);
|
|
|
|
|
2022-05-22 16:28:43 +00:00
|
|
|
free (bctx->main_pass.draw_queues);
|
2022-06-08 09:16:10 +00:00
|
|
|
for (int i = 0; i < bctx->num_models; i++) {
|
2022-05-25 04:29:11 +00:00
|
|
|
DARRAY_CLEAR (&bctx->main_pass.instances[i].entities);
|
|
|
|
}
|
|
|
|
free (bctx->main_pass.instances);
|
2021-01-19 16:25:54 +00:00
|
|
|
DARRAY_CLEAR (&bctx->frames);
|
2022-05-25 04:29:11 +00:00
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
QFV_DestroyStagingBuffer (bctx->light_stage);
|
|
|
|
QFV_DestroyScrap (bctx->light_scrap);
|
2021-01-20 07:28:04 +00:00
|
|
|
if (bctx->vertex_buffer) {
|
|
|
|
dfunc->vkDestroyBuffer (device->dev, bctx->vertex_buffer, 0);
|
|
|
|
dfunc->vkFreeMemory (device->dev, bctx->vertex_memory, 0);
|
|
|
|
}
|
|
|
|
if (bctx->index_buffer) {
|
|
|
|
dfunc->vkDestroyBuffer (device->dev, bctx->index_buffer, 0);
|
|
|
|
dfunc->vkFreeMemory (device->dev, bctx->index_memory, 0);
|
|
|
|
}
|
2022-05-24 15:17:57 +00:00
|
|
|
dfunc->vkDestroyBuffer (device->dev, bctx->entid_buffer, 0);
|
|
|
|
dfunc->vkFreeMemory (device->dev, bctx->entid_memory, 0);
|
2021-01-23 11:42:53 +00:00
|
|
|
|
2021-03-25 06:54:34 +00:00
|
|
|
if (bctx->skybox_tex) {
|
|
|
|
Vulkan_UnloadTex (ctx, bctx->skybox_tex);
|
|
|
|
}
|
2022-05-26 10:14:44 +00:00
|
|
|
if (bctx->notexture.tex) {
|
|
|
|
Vulkan_UnloadTex (ctx, bctx->notexture.tex);
|
|
|
|
}
|
2021-03-25 06:54:34 +00:00
|
|
|
|
2021-01-23 11:42:53 +00:00
|
|
|
dfunc->vkDestroyImageView (device->dev, bctx->default_skysheet->view, 0);
|
|
|
|
dfunc->vkDestroyImage (device->dev, bctx->default_skysheet->image, 0);
|
|
|
|
|
|
|
|
dfunc->vkDestroyImageView (device->dev, bctx->default_skybox->view, 0);
|
|
|
|
dfunc->vkDestroyImage (device->dev, bctx->default_skybox->image, 0);
|
|
|
|
dfunc->vkFreeMemory (device->dev, bctx->default_skybox->memory, 0);
|
|
|
|
free (bctx->default_skybox);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
|
|
|
|
2021-03-25 06:54:34 +00:00
|
|
|
void
|
|
|
|
Vulkan_LoadSkys (const char *sky, vulkan_ctx_t *ctx)
|
2021-01-19 16:25:54 +00:00
|
|
|
{
|
2021-03-25 06:54:34 +00:00
|
|
|
bspctx_t *bctx = ctx->bsp_context;
|
|
|
|
|
|
|
|
const char *name;
|
2021-01-19 16:25:54 +00:00
|
|
|
int i;
|
|
|
|
tex_t *tex;
|
|
|
|
static const char *sky_suffix[] = { "ft", "bk", "up", "dn", "rt", "lf"};
|
|
|
|
|
2021-03-25 06:54:34 +00:00
|
|
|
if (bctx->skybox_tex) {
|
|
|
|
Vulkan_UnloadTex (ctx, bctx->skybox_tex);
|
2021-12-17 03:20:32 +00:00
|
|
|
Vulkan_FreeTexture (ctx, bctx->skybox_descriptor);
|
2021-03-25 06:54:34 +00:00
|
|
|
}
|
|
|
|
bctx->skybox_tex = 0;
|
|
|
|
|
|
|
|
if (!sky || !*sky) {
|
[cvar] Make cvars properly typed
This is an extremely extensive patch as it hits every cvar, and every
usage of the cvars. Cvars no longer store the value they control,
instead, they use a cexpr value object to reference the value and
specify the value's type (currently, a null type is used for strings).
Non-string cvars are passed through cexpr, allowing expressions in the
cvars' settings. Also, cvars have returned to an enhanced version of the
original (id quake) registration scheme.
As a minor benefit, relevant code having direct access to the
cvar-controlled variables is probably a slight optimization as it
removed a pointer dereference, and the variables can be located for data
locality.
The static cvar descriptors are made private as an additional safety
layer, though there's nothing stopping external modification via
Cvar_FindVar (which is needed for adding listeners).
While not used yet (partly due to working out the design), cvars can
have a validation function.
Registering a cvar allows a primary listener (and its data) to be
specified: it will always be called first when the cvar is modified. The
combination of proper listeners and direct access to the controlled
variable greatly simplifies the more complex cvar interactions as much
less null checking is required, and there's no need for one cvar's
callback to call another's.
nq-x11 is known to work at least well enough for the demos. More testing
will come.
2022-04-23 03:22:45 +00:00
|
|
|
sky = r_skyname;
|
2021-03-25 06:54:34 +00:00
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
|
|
|
|
if (!*sky || !strcasecmp (sky, "none")) {
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vulkan, "Skybox unloaded\n");
|
2021-12-17 03:20:32 +00:00
|
|
|
bctx->skybox_descriptor
|
|
|
|
= Vulkan_CreateTextureDescriptor (ctx, bctx->default_skybox,
|
|
|
|
bctx->sampler);
|
2021-01-19 16:25:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-25 06:54:34 +00:00
|
|
|
name = va (ctx->va_ctx, "env/%s_map", sky);
|
|
|
|
tex = LoadImage (name, 1);
|
|
|
|
if (tex) {
|
|
|
|
bctx->skybox_tex = Vulkan_LoadEnvMap (ctx, tex, sky);
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vulkan, "Loaded %s\n", name);
|
2021-01-19 16:25:54 +00:00
|
|
|
} else {
|
2021-03-25 06:54:34 +00:00
|
|
|
int failed = 0;
|
|
|
|
tex_t *sides[6] = { };
|
|
|
|
|
2021-01-19 16:25:54 +00:00
|
|
|
for (i = 0; i < 6; i++) {
|
2021-03-25 06:54:34 +00:00
|
|
|
name = va (ctx->va_ctx, "env/%s%s", sky, sky_suffix[i]);
|
|
|
|
tex = LoadImage (name, 1);
|
|
|
|
if (!tex) {
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vulkan, "Couldn't load %s\n", name);
|
2021-01-19 16:25:54 +00:00
|
|
|
// also look in gfx/env, where Darkplaces looks for skies
|
2021-03-25 06:54:34 +00:00
|
|
|
name = va (ctx->va_ctx, "gfx/env/%s%s", sky, sky_suffix[i]);
|
|
|
|
tex = LoadImage (name, 1);
|
|
|
|
if (!tex) {
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vulkan, "Couldn't load %s\n", name);
|
2021-03-25 06:54:34 +00:00
|
|
|
failed = 1;
|
2021-01-19 16:25:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2021-04-24 23:38:48 +00:00
|
|
|
//FIXME find a better way (also, assumes data and struct together)
|
|
|
|
sides[i] = malloc (ImageSize (tex, 1));
|
|
|
|
memcpy (sides[i], tex, ImageSize (tex, 1));
|
|
|
|
sides[i]->data = (byte *)(sides[i] + 1);
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vulkan, "Loaded %s\n", name);
|
2021-03-25 06:54:34 +00:00
|
|
|
}
|
|
|
|
if (!failed) {
|
|
|
|
bctx->skybox_tex = Vulkan_LoadEnvSides (ctx, sides, sky);
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
2021-04-24 23:38:48 +00:00
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
free (sides[i]);
|
|
|
|
}
|
2021-01-19 16:25:54 +00:00
|
|
|
}
|
2021-03-25 06:54:34 +00:00
|
|
|
if (bctx->skybox_tex) {
|
2021-12-17 03:20:32 +00:00
|
|
|
bctx->skybox_descriptor
|
2022-02-17 16:17:25 +00:00
|
|
|
= Vulkan_CreateTextureDescriptor (ctx, bctx->skybox_tex,
|
2021-12-17 03:20:32 +00:00
|
|
|
bctx->sampler);
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vulkan, "Skybox %s loaded\n", sky);
|
2021-03-25 06:54:34 +00:00
|
|
|
}
|
|
|
|
}
|