From 2e9e247ca4bbb2211b09f612fa11adc1863a624e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 19 Dec 2023 03:28:29 +0900 Subject: [PATCH] [vulkan] Use resource for allocating alias models So far only the mesh data, so it doesn't make any difference to allocations, but it's the first step to reducing memory object allocation. --- include/QF/Vulkan/qf_alias.h | 2 +- libs/models/alias/vulkan_model_alias.c | 375 ++++++++++++------------- 2 files changed, 186 insertions(+), 191 deletions(-) diff --git a/include/QF/Vulkan/qf_alias.h b/include/QF/Vulkan/qf_alias.h index 389960894..205510afc 100644 --- a/include/QF/Vulkan/qf_alias.h +++ b/include/QF/Vulkan/qf_alias.h @@ -56,7 +56,7 @@ typedef struct qfv_alias_mesh_s { VkBuffer vertex_buffer; VkBuffer uv_buffer; VkBuffer index_buffer; - VkDeviceMemory memory; + struct qfv_resource_s *resources; } qfv_alias_mesh_t; typedef struct qfv_alias_skin_s { diff --git a/libs/models/alias/vulkan_model_alias.c b/libs/models/alias/vulkan_model_alias.c index c39ee77d3..95efd2be3 100644 --- a/libs/models/alias/vulkan_model_alias.c +++ b/libs/models/alias/vulkan_model_alias.c @@ -53,6 +53,7 @@ #include "QF/Vulkan/debug.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/resource.h" #include "QF/Vulkan/staging.h" #include "mod_internal.h" @@ -81,7 +82,6 @@ vulkan_alias_clear (model_t *m, void *data) { vulkan_ctx_t *ctx = data; qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; aliashdr_t *hdr; qfv_alias_mesh_t *mesh; @@ -92,10 +92,7 @@ vulkan_alias_clear (model_t *m, void *data) hdr = Cache_Get (&m->cache); } mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); - dfunc->vkDestroyBuffer (device->dev, mesh->vertex_buffer, 0); - dfunc->vkDestroyBuffer (device->dev, mesh->uv_buffer, 0); - dfunc->vkDestroyBuffer (device->dev, mesh->index_buffer, 0); - dfunc->vkFreeMemory (device->dev, mesh->memory, 0); + QFV_DestroyResource (device, mesh->resources); __auto_type skins = (maliasskindesc_t *) ((byte *) hdr + hdr->skindesc); for (int i = 0; i < hdr->mdl.numskins; i++) { @@ -239,67 +236,14 @@ Vulkan_Mod_LoadAllSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) } } -void -Vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) +static int +separate_verts (int *indexmap, int numverts, int numtris, + const mod_alias_ctx_t *alias_ctx) { - alias_ctx->mod->clear = vulkan_alias_clear; - alias_ctx->mod->data = ctx; -} - -void -Vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) -{ -} - -static size_t -get_buffer_size (qfv_device_t *device, VkBuffer buffer) -{ - qfv_devfuncs_t *dfunc = device->funcs; - size_t size; - size_t align; - - VkMemoryRequirements requirements; - dfunc->vkGetBufferMemoryRequirements (device->dev, buffer, &requirements); - size = requirements.size; - align = requirements.alignment - 1; - size = (size + align) & ~(align); - return size; -} - -void -Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, - int _s, int extra, vulkan_ctx_t *ctx) -{ - aliashdr_t *header = alias_ctx->header; - qfv_device_t *device = ctx->device; - qfv_devfuncs_t *dfunc = device->funcs; - aliasvrt_t *verts; - aliasuv_t *uv; - trivertx_t *pv; - int *indexmap; - uint32_t *indices; - int numverts; - int numtris; - int i, j; - int pose; - vec3_t pos; - - if (header->mdl.ident == HEADER_MDL16) - VectorScale (header->mdl.scale, 1/256.0, header->mdl.scale); - - numverts = header->mdl.numverts; - numtris = header->mdl.numtris; - - // initialize indexmap to -1 (unduplicated). any other value indicates - // both that the vertex has been duplicated and the index of the - // duplicate vertex. - indexmap = malloc (numverts * sizeof (int)); - memset (indexmap, -1, numverts * sizeof (int)); - // check for onseam verts, and duplicate any that are associated with // back-facing triangles - for (i = 0; i < numtris; i++) { - for (j = 0; j < 3; j++) { + for (int i = 0; i < numtris; i++) { + for (int j = 0; j < 3; j++) { int vind = alias_ctx->triangles.a[i].vertindex[j]; if (alias_ctx->stverts.a[vind].onseam && !alias_ctx->triangles.a[i].facesfront) { @@ -311,92 +255,27 @@ Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, } } } + return numverts; +} - // we now know exactly how many vertices we need, so built the vertex - // and index data arrays - // The layout is: - // vbuf:{vertex, normal} * (numposes * numverts) - // uvbuf:{uv} * (numverts) - // ibuf:{index} * (numtris * 3) - // numverts includes the duplicated seam vertices. - // The vertex buffer will be bound with various offsets based on the - // current and previous pose, uvbuff "statically" bound as uvs are not - // animated by pose, and the same for ibuf: indices will never change for - // the mesh - size_t vert_count = numverts * header->numposes; - size_t vert_size = vert_count * sizeof (aliasvrt_t); - size_t uv_size = numverts * sizeof (aliasuv_t); - size_t ind_size = 3 * numtris * sizeof (uint32_t); - - VkBuffer vbuff = QFV_CreateBuffer (device, vert_size, - VK_BUFFER_USAGE_TRANSFER_DST_BIT - | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - VkBuffer uvbuff = QFV_CreateBuffer (device, uv_size, - VK_BUFFER_USAGE_TRANSFER_DST_BIT - | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - VkBuffer ibuff = QFV_CreateBuffer (device, ind_size, - VK_BUFFER_USAGE_TRANSFER_DST_BIT - | VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, vbuff, - va (ctx->va_ctx, "buffer:alias:vertex:%s", - alias_ctx->mod->name)); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, uvbuff, - va (ctx->va_ctx, "buffer:alias:uv:%s", - alias_ctx->mod->name)); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, ibuff, - va (ctx->va_ctx, "buffer:alias:index:%s", - alias_ctx->mod->name)); - size_t voffs = 0; - size_t uvoffs = voffs + get_buffer_size (device, vbuff); - size_t ioffs = uvoffs + get_buffer_size (device, uvbuff); - size_t buff_size = ioffs + get_buffer_size (device, ibuff); - VkDeviceMemory mem; - mem = QFV_AllocBufferMemory (device, vbuff, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - buff_size, 0); - QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, mem, - va (ctx->va_ctx, "memory:alias:vuvi:%s", - alias_ctx->mod->name)); - QFV_BindBufferMemory (device, vbuff, mem, voffs); - QFV_BindBufferMemory (device, uvbuff, mem, uvoffs); - QFV_BindBufferMemory (device, ibuff, mem, ioffs); - - qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, - va (ctx->va_ctx, - "alias:%s", - alias_ctx->mod->name), - buff_size, ctx->cmdpool); - qfv_packet_t *packet = QFV_PacketAcquire (stage); - verts = QFV_PacketExtend (packet, vert_size); - uv = QFV_PacketExtend (packet, uv_size); - indices = QFV_PacketExtend (packet, ind_size); - - // populate the uvs, duplicating and shifting any that are on the seam - // and associated with back-facing triangles (marked by non-negative - // indexmap entry). - // the s coordinate is shifted right by half the skin width. - for (i = 0; i < header->mdl.numverts; i++) { - int vind = indexmap[i]; - uv[i].u = (float) alias_ctx->stverts.a[i].s / header->mdl.skinwidth; - uv[i].v = (float) alias_ctx->stverts.a[i].t / header->mdl.skinheight; - if (vind != -1) { - uv[vind] = uv[i]; - uv[vind].u += 0.5; - } - } - - // poputlate the vertex position and normal data, duplicating for +static void +build_verts (aliasvrt_t *verts, int numposes, int numverts, const mdl_t *mdl, + const int *indexmap, const mod_alias_ctx_t *alias_ctx) +{ + int i, pose; + // populate the vertex position and normal data, duplicating for // back-facing on-seam verts (indicated by non-negative indexmap entry) - for (i = 0, pose = 0; i < header->numposes; i++, pose += numverts) { - for (j = 0; j < header->mdl.numverts; j++) { - pv = &alias_ctx->poseverts.a[i][j]; - if (extra) { - VectorMultAdd (pv[header->mdl.numverts].v, 256, pv->v, pos); + for (i = 0, pose = 0; i < numposes; i++, pose += numverts) { + for (int j = 0; j < mdl->numverts; j++) { + auto pv = &alias_ctx->poseverts.a[i][j]; + vec3_t pos; + if (mdl->ident == HEADER_MDL16) { + VectorMultAdd (pv[mdl->numverts].v, 256, pv->v, pos); } else { VectorCopy (pv->v, pos); } - VectorCompMultAdd (header->mdl.scale_origin, header->mdl.scale, - pos, verts[pose + j].vertex); + VectorCompMultAdd (mdl->scale_origin, mdl->scale, pos, + verts[pose + j].vertex); verts[pose + j].vertex[3] = 1; VectorCopy (vertex_normals[pv->lightnormalindex], verts[pose + j].normal); @@ -407,10 +286,35 @@ Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, } } } +} + +static void +build_uvs (aliasuv_t *uv, const mdl_t *mdl, const int *indexmap, + const mod_alias_ctx_t *alias_ctx) +{ + // populate the uvs, duplicating and shifting any that are on the seam + // and associated with back-facing triangles (marked by non-negative + // indexmap entry). + // the s coordinate is shifted right by half the skin width. + for (int i = 0; i < mdl->numverts; i++) { + int vind = indexmap[i]; + uv[i].u = (float) alias_ctx->stverts.a[i].s / mdl->skinwidth; + uv[i].v = (float) alias_ctx->stverts.a[i].t / mdl->skinheight; + if (vind != -1) { + uv[vind] = uv[i]; + uv[vind].u += 0.5; + } + } +} + +static void +build_inds (uint32_t *indices, int numtris, const int *indexmap, + const mod_alias_ctx_t *alias_ctx) +{ // now build the indices for DrawElements - for (i = 0; i < numtris; i++) { - for (j = 0; j < 3; j++) { + for (int i = 0; i < numtris; i++) { + for (int j = 0; j < 3; j++) { int vind = alias_ctx->triangles.a[i].vertindex[j]; // can't use indexmap to do the test because it indicates only // that the vertex has been duplicated, not whether or not @@ -422,57 +326,148 @@ Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, indices[3 * i + j] = vind; } } - // finished with indexmap - free (indexmap); +} - header->poseverts = numverts; +void +Vulkan_Mod_FinalizeAliasModel (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) +{ + auto device = ctx->device; - qfv_bufferbarrier_t bb = bufferBarriers[qfv_BB_Unknown_to_TransferWrite]; - VkBufferMemoryBarrier wr_barriers[] = { - bb.barrier, bb.barrier, bb.barrier, + alias_ctx->mod->clear = vulkan_alias_clear; + alias_ctx->mod->data = ctx; + + auto hdr = alias_ctx->header; + + int numverts = hdr->mdl.numverts; + int numtris = hdr->mdl.numtris; + + int indexmap[numverts]; + // initialize indexmap to -1 (unduplicated). any other value indicates + // both that the vertex has been duplicated and the index of the + // duplicate vertex. + memset (indexmap, -1, sizeof (indexmap)); + + numverts = separate_verts (indexmap, numverts, numtris, alias_ctx); + hdr->poseverts = numverts; + // we now know exactly how many vertices we need, so build the vertex + // and index data arrays + // The layout is: + // vbuf:{vertex, normal} * (numposes * numverts) + // uvbuf:{uv} * (numverts) + // ibuf:{index} * (numtris * 3) + // numverts includes the duplicated seam vertices. + // The vertex buffer will be bound with various offsets based on the + // current and previous pose, uvbuff "statically" bound as uvs are not + // animated by pose, and the same for ibuf: indices will never change for + // the mesh + size_t vert_count = numverts * hdr->numposes; + size_t vert_size = vert_count * sizeof (aliasvrt_t); + size_t uv_size = numverts * sizeof (aliasuv_t); + size_t ind_size = 3 * numtris * sizeof (uint32_t); + auto mesh = (qfv_alias_mesh_t *) ((byte *) hdr + hdr->commands); + mesh->resources = malloc (sizeof (qfv_resource_t) + + sizeof (qfv_resobj_t) + + sizeof (qfv_resobj_t) + + sizeof (qfv_resobj_t)); + mesh->resources[0] = (qfv_resource_t) { + .name = va (ctx->va_ctx, "alias:%s", alias_ctx->mod->name), + .va_ctx = ctx->va_ctx, + .memory_properties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .num_objects = 3, + .objects = (qfv_resobj_t *) &mesh->resources[1], }; - wr_barriers[0].buffer = vbuff; - wr_barriers[0].size = vert_size; - wr_barriers[1].buffer = uvbuff; - wr_barriers[1].size = uv_size; - wr_barriers[2].buffer = ibuff; - wr_barriers[2].size = ind_size; - dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages, - 0, 0, 0, 3, wr_barriers, 0, 0); - VkBufferCopy copy_region[] = { - { packet->offset, 0, vert_size }, - { packet->offset + vert_size, 0, uv_size }, - { packet->offset + vert_size + uv_size, 0, ind_size }, + auto vert_obj = mesh->resources->objects; + auto uv_obj = &vert_obj[1]; + auto index_obj = &uv_obj[1]; + + *vert_obj = (qfv_resobj_t) { + .name = "vertex", + .type = qfv_res_buffer, + .buffer = { + .size = vert_size, + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + }, }; - dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, - vbuff, 1, ©_region[0]); - dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, - uvbuff, 1, ©_region[1]); - dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer, - ibuff, 1, ©_region[2]); - // both qfv_BB_TransferWrite_to_VertexAttrRead and - // qfv_BB_TransferWrite_to_IndexRead have the same stage flags - bb = bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]; - VkBufferMemoryBarrier rd_barriers[] = { - bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead].barrier, - bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead].barrier, - bufferBarriers[qfv_BB_TransferWrite_to_IndexRead].barrier, + *uv_obj = (qfv_resobj_t) { + .name = "uv", + .type = qfv_res_buffer, + .buffer = { + .size = uv_size, + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + }, }; - rd_barriers[0].buffer = vbuff; - rd_barriers[0].size = vert_size; - rd_barriers[1].buffer = uvbuff; - rd_barriers[1].size = uv_size; - rd_barriers[2].buffer = ibuff; - rd_barriers[2].size = ind_size; - dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages, - 0, 0, 0, 3, rd_barriers, 0, 0); + *index_obj = (qfv_resobj_t) { + .name = "index", + .type = qfv_res_buffer, + .buffer = { + .size = ind_size, + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT + | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + }, + }; + QFV_CreateResource (device, mesh->resources); + mesh->vertex_buffer = vert_obj->buffer.buffer; + mesh->uv_buffer = uv_obj->buffer.buffer; + mesh->index_buffer = index_obj->buffer.buffer; + + size_t packet_size = vert_size + uv_size + ind_size; + auto packet = QFV_PacketAcquire (ctx->staging); + byte *packet_start = QFV_PacketExtend (packet, packet_size); + byte *packet_data = packet_start; + + qfv_scatter_t vert_scatter = { + .srcOffset = packet_data - packet_start, + .dstOffset = 0, + .length = vert_size, + }; + auto verts = (aliasvrt_t *) packet_data; + packet_data += vert_scatter.length; + build_verts (verts, hdr->numposes, numverts, &hdr->mdl, + indexmap, alias_ctx); + + qfv_scatter_t uv_scatter = { + .srcOffset = packet_data - packet_start, + .dstOffset = 0, + .length = uv_size, + }; + auto uv = (aliasuv_t *) packet_data; + packet_data += uv_scatter.length; + build_uvs (uv, &hdr->mdl, indexmap, alias_ctx); + + qfv_scatter_t ind_scatter = { + .srcOffset = packet_data - packet_start, + .dstOffset = 0, + .length = ind_size, + }; + auto indices = (uint32_t *) packet_data; + packet_data += ind_scatter.length; + build_inds (indices, hdr->mdl.numtris, indexmap, alias_ctx); + + QFV_PacketScatterBuffer (packet, mesh->vertex_buffer, 1, &vert_scatter, + &bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]); + QFV_PacketScatterBuffer (packet, mesh->uv_buffer, 1, &uv_scatter, + &bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead]); + QFV_PacketScatterBuffer (packet, mesh->index_buffer, 1, &ind_scatter, + &bufferBarriers[qfv_BB_TransferWrite_to_IndexRead]); QFV_PacketSubmit (packet); - QFV_DestroyStagingBuffer (stage); +} + +void +Vulkan_Mod_LoadExternalSkins (mod_alias_ctx_t *alias_ctx, vulkan_ctx_t *ctx) +{ +} + +void +Vulkan_Mod_MakeAliasModelDisplayLists (mod_alias_ctx_t *alias_ctx, void *_m, + int _s, int extra, vulkan_ctx_t *ctx) +{ + aliashdr_t *header = alias_ctx->header; + + if (header->mdl.ident == HEADER_MDL16) + VectorScale (header->mdl.scale, 1/256.0, header->mdl.scale); qfv_alias_mesh_t *mesh = Hunk_Alloc (0, sizeof (qfv_alias_mesh_t)); - mesh->vertex_buffer = vbuff; - mesh->uv_buffer = uvbuff; - mesh->index_buffer = ibuff; - mesh->memory = mem; header->commands = (byte *) mesh - (byte *) header; }