quakeforge/libs/video/renderer/vulkan/vulkan_sprite.c
Bill Currie 5140346c22 [vulkan] Nuke the old render pass code from orbit
Gotta be sure :)

With the new system mostly up and running (just bsp rendering and
descriptor sets/layout handling to go, and they're independent of the
old render pass system), the old system can finally be cleared out.
2023-06-24 10:42:27 +09:00

256 lines
7 KiB
C

/*
vulkan_sprite.c
Vulkan sprite model pipeline
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/12/14
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"
#include "QF/image.h"
#include "QF/render.h"
#include "QF/skin.h"
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/scene/entity.h"
#include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_sprite.h"
#include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/buffer.h"
#include "QF/Vulkan/command.h"
#include "QF/Vulkan/debug.h"
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h"
#include "QF/Vulkan/render.h"
#include "r_internal.h"
#include "vid_vulkan.h"
static void
emit_commands (VkCommandBuffer cmd, qfv_sprite_t *sprite,
int numPC, qfv_push_constants_t *constants,
vulkan_ctx_t *ctx, entity_t ent)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
spritectx_t *sctx = ctx->sprite_context;
Vulkan_BeginEntityLabel (ctx, cmd, ent);
QFV_PushConstants (device, cmd, sctx->layout, numPC, constants);
VkDescriptorSet sets[] = {
sprite->descriptors,
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
sctx->layout, 1, 1, sets, 0, 0);
dfunc->vkCmdDraw (cmd, 4, 1, 0, 0);
QFV_CmdEndLabel (device, cmd);
}
static VkDescriptorBufferInfo base_buffer_info = {
.range = VK_WHOLE_SIZE,
};
static VkDescriptorImageInfo base_image_info = {
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
};
static VkWriteDescriptorSet base_buffer_write = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstBinding = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
};
static VkWriteDescriptorSet base_image_write = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstBinding = 1,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
};
void
Vulkan_Sprite_DescriptorSet (vulkan_ctx_t *ctx, qfv_sprite_t *sprite)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
spritectx_t *sctx = ctx->sprite_context;
//FIXME kinda dumb
__auto_type layouts = QFV_AllocDescriptorSetLayoutSet (1, alloca);
for (size_t i = 0; i < layouts->size; i++) {
layouts->a[i] = sctx->setLayout;
}
__auto_type sets = QFV_AllocateDescriptorSet (device, sctx->pool, layouts);
sprite->descriptors = sets->a[0];
free (sets);
VkDescriptorBufferInfo bufferInfo[1];
bufferInfo[0] = base_buffer_info;
bufferInfo[0].buffer = sprite->verts;
VkDescriptorImageInfo imageInfo[1];
imageInfo[0] = base_image_info;
imageInfo[0].sampler = sctx->sampler;
imageInfo[0].imageView = sprite->view;
VkWriteDescriptorSet write[2];
write[0] = base_buffer_write;
write[0].dstSet = sprite->descriptors;
write[0].pBufferInfo = bufferInfo;
write[1] = base_image_write;
write[1].dstSet = sprite->descriptors;
write[1].pImageInfo = imageInfo;
dfunc->vkUpdateDescriptorSets (device->dev, 2, write, 0, 0);
}
void
Vulkan_Sprint_FreeDescriptors (vulkan_ctx_t *ctx, qfv_sprite_t *sprite)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
spritectx_t *sctx = ctx->sprite_context;
dfunc->vkFreeDescriptorSets (device->dev, sctx->pool, 1,
&sprite->descriptors);
}
static void
sprite_draw_ent (qfv_taskctx_t *taskctx, entity_t ent)
{
auto ctx = taskctx->ctx;
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg);
auto model = renderer->model;
msprite_t *sprite = model->cache.data;
mat4f_t mat = {};
uint32_t frame;
qfv_push_constants_t push_constants[] = {
{ VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof (mat), mat },
{ VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
64, sizeof (frame), &frame },
};
animation_t *animation = Ent_GetComponent (ent.id, scene_animation,
ent.reg);
frame = (ptrdiff_t) R_GetSpriteFrame (sprite, animation);
transform_t transform = Entity_Transform (ent);
mat[3] = Transform_GetWorldPosition (transform);
vec4f_t cameravec = r_refdef.frame.position - mat[3];
R_BillboardFrame (transform, sprite->type, cameravec,
&mat[2], &mat[1], &mat[0]);
mat[0] = -mat[0];
emit_commands (taskctx->cmd,
(qfv_sprite_t *) ((byte *) sprite + sprite->data),
2, push_constants, ctx, ent);
}
static void
sprite_draw (const exprval_t **params, exprval_t *result, exprctx_t *ectx)
{
auto taskctx = (qfv_taskctx_t *) ectx;
auto ctx = taskctx->ctx;
auto device = ctx->device;
auto dfunc = device->funcs;
auto sctx = ctx->sprite_context;
auto cmd = taskctx->cmd;
VkDescriptorSet sets[] = {
Vulkan_Matrix_Descriptors (ctx, ctx->curFrame),
};
dfunc->vkCmdBindDescriptorSets (cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
sctx->layout, 0, 1, sets, 0, 0);
auto queue = r_ent_queue; //FIXME fetch from scene
for (size_t i = 0; i < queue->ent_queues[mod_sprite].size; i++) {
entity_t ent = queue->ent_queues[mod_sprite].a[i];
sprite_draw_ent (taskctx, ent);
}
}
static exprfunc_t sprite_draw_func[] = {
{ .func = sprite_draw },
{}
};
static exprsym_t sprite_task_syms[] = {
{ "sprite_draw", &cexpr_function, sprite_draw_func },
{}
};
void
Vulkan_Sprite_Init (vulkan_ctx_t *ctx)
{
qfvPushDebug (ctx, "sprite init");
QFV_Render_AddTasks (ctx, sprite_task_syms);
spritectx_t *sctx = calloc (1, sizeof (spritectx_t));
ctx->sprite_context = sctx;
auto rctx = ctx->render_context;
size_t frames = rctx->frames.size;
DARRAY_INIT (&sctx->frames, frames);
DARRAY_RESIZE (&sctx->frames, frames);
sctx->frames.grow = 0;
sctx->layout = Vulkan_CreatePipelineLayout (ctx, "sprite_layout");
sctx->sampler = Vulkan_CreateSampler (ctx, "sprite_sampler");
sctx->pool = Vulkan_CreateDescriptorPool (ctx, "sprite_pool");
sctx->setLayout = Vulkan_CreateDescriptorSetLayout (ctx, "sprite_set");
qfvPopDebug (ctx);
}
void
Vulkan_Sprite_Shutdown (vulkan_ctx_t *ctx)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
spritectx_t *sctx = ctx->sprite_context;
dfunc->vkDestroyPipeline (device->dev, sctx->depth, 0);
dfunc->vkDestroyPipeline (device->dev, sctx->gbuf, 0);
free (sctx->frames.a);
free (sctx);
}