mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 06:10:56 +00:00
[vulkan] Load sprite model data
The vertices and frame images are loaded into the one memory object, with the vertices first followed by the images. The vertices are 2D xy+uv sets meant to be applied to the model transform frame, and are pre-computed for the sprite size (this part does support sprites with varying frame image sizes). The frame images are loaded into one image with each frame on its own layer. This will cause some problems if any sprites with varying frame image sizes are found, but the three sprites in quake are all uniform size.
This commit is contained in:
parent
c5cfcc7bfd
commit
0eb556b8f9
3 changed files with 301 additions and 0 deletions
98
include/QF/Vulkan/qf_sprite.h
Normal file
98
include/QF/Vulkan/qf_sprite.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
qf_sprite.h
|
||||||
|
|
||||||
|
Vulkan specific sprite model stuff
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef __QF_Vulkan_qf_sprite_h
|
||||||
|
#define __QF_Vulkan_qf_sprite_h
|
||||||
|
|
||||||
|
#include "QF/darray.h"
|
||||||
|
#include "QF/model.h"
|
||||||
|
#include "QF/modelgen.h"
|
||||||
|
#include "QF/Vulkan/qf_vid.h"
|
||||||
|
#include "QF/Vulkan/command.h"
|
||||||
|
|
||||||
|
typedef struct spritevrt_s {
|
||||||
|
float x, y, u, v;
|
||||||
|
} spritevrt_t;
|
||||||
|
|
||||||
|
typedef struct qfv_sprite_s {
|
||||||
|
VkDeviceMemory memory;
|
||||||
|
VkBuffer verts;
|
||||||
|
VkImage image;
|
||||||
|
VkImageView view;
|
||||||
|
} qfv_sprite_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
QFV_spriteDepth,
|
||||||
|
QFV_spriteGBuffer,
|
||||||
|
QFV_spriteTranslucent,
|
||||||
|
|
||||||
|
QFV_spriteNumPasses
|
||||||
|
} QFV_SpriteSubpass;
|
||||||
|
|
||||||
|
typedef struct spriteframe_s {
|
||||||
|
qfv_cmdbufferset_t cmdSet;
|
||||||
|
} spriteframe_t;
|
||||||
|
|
||||||
|
typedef struct spriteframeset_s
|
||||||
|
DARRAY_TYPE (spriteframe_t) spriteframeset_t;
|
||||||
|
|
||||||
|
typedef struct spriteindset_s
|
||||||
|
DARRAY_TYPE (unsigned) spriteindset_t;
|
||||||
|
|
||||||
|
typedef struct spritectx_s {
|
||||||
|
spriteframeset_t frames;
|
||||||
|
VkPipeline depth;
|
||||||
|
VkPipeline gbuf;
|
||||||
|
VkDescriptorSet descriptors;
|
||||||
|
VkDescriptorPool pool;
|
||||||
|
VkDescriptorSetLayout setLayout;
|
||||||
|
VkPipelineLayout layout;
|
||||||
|
unsigned maxImages;
|
||||||
|
VkSampler sampler;
|
||||||
|
spriteindset_t texindices;
|
||||||
|
} spritectx_t;
|
||||||
|
|
||||||
|
struct vulkan_ctx_s;
|
||||||
|
struct qfv_renderframe_s;
|
||||||
|
struct entity_s;
|
||||||
|
struct mod_sprite_ctx_s;
|
||||||
|
|
||||||
|
void Vulkan_Mod_SpriteLoadFrames (struct mod_sprite_ctx_s *sprite_ctx,
|
||||||
|
struct vulkan_ctx_s *ctx);
|
||||||
|
|
||||||
|
void Vulkan_SpriteBegin (struct qfv_renderframe_s *rFrame);
|
||||||
|
void Vulkan_DrawSprite (struct entity_s *ent, struct qfv_renderframe_s *rFrame);
|
||||||
|
void Vulkan_SpriteEnd (struct qfv_renderframe_s *rFrame);
|
||||||
|
|
||||||
|
void Vulkan_Sprite_Init (struct vulkan_ctx_s *ctx);
|
||||||
|
void Vulkan_Sprite_Shutdown (struct vulkan_ctx_s *ctx);
|
||||||
|
|
||||||
|
#endif//__QF_Vulkan_qf_sprite_h
|
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
vulkan_model_sprite.c
|
||||||
|
|
||||||
|
Sprite model mesh processing for Vulkan
|
||||||
|
|
||||||
|
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
|
||||||
|
|
||||||
|
Author: Bill Currie <bill@taniwha.org>
|
||||||
|
Date: 2021/12/13
|
||||||
|
|
||||||
|
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 "QF/cvar.h"
|
||||||
|
#include "QF/darray.h"
|
||||||
|
#include "QF/image.h"
|
||||||
|
#include "QF/quakefs.h"
|
||||||
|
#include "QF/va.h"
|
||||||
|
#include "QF/Vulkan/qf_sprite.h"
|
||||||
|
#include "QF/Vulkan/qf_texture.h"
|
||||||
|
#include "QF/Vulkan/barrier.h"
|
||||||
|
#include "QF/Vulkan/buffer.h"
|
||||||
|
#include "QF/Vulkan/debug.h"
|
||||||
|
#include "QF/Vulkan/device.h"
|
||||||
|
#include "QF/Vulkan/image.h"
|
||||||
|
#include "QF/Vulkan/instance.h"
|
||||||
|
#include "QF/Vulkan/staging.h"
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
|
#include "mod_internal.h"
|
||||||
|
#include "r_internal.h"
|
||||||
|
#include "vid_vulkan.h"
|
||||||
|
|
||||||
|
static void
|
||||||
|
vulkan_sprite_clear (model_t *m, void *data)
|
||||||
|
{
|
||||||
|
vulkan_ctx_t *ctx = data;
|
||||||
|
qfv_device_t *device = ctx->device;
|
||||||
|
qfv_devfuncs_t *dfunc = device->funcs;
|
||||||
|
msprite_t *msprite = m->cache.data;
|
||||||
|
__auto_type sprite = (qfv_sprite_t *) ((byte *) msprite + msprite->data);
|
||||||
|
|
||||||
|
dfunc->vkDestroyBuffer (device->dev, sprite->verts, 0);
|
||||||
|
dfunc->vkDestroyImageView (device->dev, sprite->view, 0);
|
||||||
|
dfunc->vkDestroyImage (device->dev, sprite->image, 0);
|
||||||
|
dfunc->vkFreeMemory (device->dev, sprite->memory, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Vulkan_Mod_SpriteLoadFrames (mod_sprite_ctx_t *sprite_ctx, vulkan_ctx_t *ctx)
|
||||||
|
{
|
||||||
|
qfvPushDebug (ctx, va (ctx->va_ctx, "sprite.load_frames: %s",
|
||||||
|
sprite_ctx->mod->name));
|
||||||
|
|
||||||
|
qfv_device_t *device = ctx->device;
|
||||||
|
qfv_devfuncs_t *dfunc = device->funcs;
|
||||||
|
model_t *mod = sprite_ctx->mod;
|
||||||
|
dsprite_t *dsprite = sprite_ctx->dsprite;
|
||||||
|
mod->clear = vulkan_sprite_clear;
|
||||||
|
mod->data = ctx;
|
||||||
|
|
||||||
|
qfv_sprite_t *sprite = Hunk_AllocName (0, sizeof (*sprite), mod->name);
|
||||||
|
int mipLevels = QFV_MipLevels (dsprite->width, dsprite->height);
|
||||||
|
VkExtent3D extent = { dsprite->width, dsprite->height, 1 };
|
||||||
|
sprite->image = QFV_CreateImage (device, 0, VK_IMAGE_TYPE_2D,
|
||||||
|
VK_FORMAT_R8G8B8A8_UNORM, extent,
|
||||||
|
mipLevels, sprite_ctx->numframes,
|
||||||
|
VK_SAMPLE_COUNT_1_BIT,
|
||||||
|
VK_IMAGE_USAGE_SAMPLED_BIT
|
||||||
|
| VK_IMAGE_USAGE_TRANSFER_DST_BIT
|
||||||
|
| VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
||||||
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE, sprite->image,
|
||||||
|
va (ctx->va_ctx, "image:%s", mod->name));
|
||||||
|
|
||||||
|
int numverts = 4 * sprite_ctx->numframes;
|
||||||
|
sprite->verts = QFV_CreateBuffer (device, numverts * sizeof (spritevrt_t),
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||||
|
| VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
||||||
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_BUFFER, sprite->verts,
|
||||||
|
va (ctx->va_ctx, "buffer:sprite:vertex:%s",
|
||||||
|
mod->name));
|
||||||
|
|
||||||
|
VkMemoryRequirements ireq;
|
||||||
|
dfunc->vkGetImageMemoryRequirements (device->dev, sprite->image, &ireq);
|
||||||
|
VkMemoryRequirements vreq;
|
||||||
|
dfunc->vkGetBufferMemoryRequirements (device->dev, sprite->verts, &vreq);
|
||||||
|
size_t size = QFV_NextOffset (QFV_NextOffset (0, 1, &vreq), 1, &ireq);
|
||||||
|
|
||||||
|
sprite->memory = QFV_AllocBufferMemory (device, sprite->verts,
|
||||||
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||||
|
size, 0);
|
||||||
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_DEVICE_MEMORY, sprite->memory,
|
||||||
|
va (ctx->va_ctx, "memory:sprite:%s",
|
||||||
|
sprite_ctx->mod->name));
|
||||||
|
|
||||||
|
QFV_BindBufferMemory (device, sprite->verts, sprite->memory, 0);
|
||||||
|
QFV_BindImageMemory (device, sprite->image, sprite->memory,
|
||||||
|
QFV_NextOffset (0, 1, &vreq));
|
||||||
|
sprite->view = QFV_CreateImageView (device, sprite->image,
|
||||||
|
VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
||||||
|
VK_FORMAT_R8G8B8A8_UNORM,
|
||||||
|
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
|
QFV_duSetObjectName (device, VK_OBJECT_TYPE_IMAGE_VIEW, sprite->view,
|
||||||
|
va (ctx->va_ctx, "view:sprite:%s",
|
||||||
|
sprite_ctx->mod->name));
|
||||||
|
|
||||||
|
qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device,
|
||||||
|
va (ctx->va_ctx,
|
||||||
|
"sprite:%s",
|
||||||
|
sprite_ctx->mod->name),
|
||||||
|
size, ctx->cmdpool);
|
||||||
|
qfv_packet_t *packet = QFV_PacketAcquire (stage);
|
||||||
|
spritevrt_t *verts = QFV_PacketExtend (packet,
|
||||||
|
numverts * sizeof (spritevrt_t));
|
||||||
|
int texsize = 4 * dsprite->width * dsprite->height;
|
||||||
|
byte *pixels = QFV_PacketExtend (packet,
|
||||||
|
sprite_ctx->numframes * texsize);
|
||||||
|
|
||||||
|
for (int i = 0; i < sprite_ctx->numframes; i++) {
|
||||||
|
__auto_type dframe = sprite_ctx->dframes[i];
|
||||||
|
mspriteframe_t f;
|
||||||
|
Mod_LoadSpriteFrame (&f, dframe);
|
||||||
|
verts[i * 4 + 0] = (spritevrt_t) { f.left, f.up, 0, 0 };
|
||||||
|
verts[i * 4 + 1] = (spritevrt_t) { f.right, f.up, 1, 0 };
|
||||||
|
verts[i * 4 + 2] = (spritevrt_t) { f.right, f.down, 1, 1 };
|
||||||
|
verts[i * 4 + 3] = (spritevrt_t) { f.left, f.down, 0, 1 };
|
||||||
|
Vulkan_ExpandPalette (pixels + i * texsize, (const byte *)(dframe + 1),
|
||||||
|
vid.palette32, 2, texsize / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
qfv_bufferbarrier_t bb = bufferBarriers[qfv_BB_Unknown_to_TransferWrite];
|
||||||
|
bb.barrier.buffer = sprite->verts;
|
||||||
|
bb.barrier.size = numverts * sizeof (spritevrt_t);
|
||||||
|
dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages,
|
||||||
|
0, 0, 0, 1, &bb.barrier, 0, 0);
|
||||||
|
VkBufferCopy copy_region[] = {
|
||||||
|
{ packet->offset, 0, numverts * sizeof (spritevrt_t) },
|
||||||
|
};
|
||||||
|
dfunc->vkCmdCopyBuffer (packet->cmd, stage->buffer,
|
||||||
|
sprite->verts, 1, ©_region[0]);
|
||||||
|
bb = bufferBarriers[qfv_BB_TransferWrite_to_VertexAttrRead];
|
||||||
|
bb.barrier.buffer = sprite->verts;
|
||||||
|
bb.barrier.size = numverts * sizeof (spritevrt_t);
|
||||||
|
dfunc->vkCmdPipelineBarrier (packet->cmd, bb.srcStages, bb.dstStages,
|
||||||
|
0, 0, 0, 1, &bb.barrier, 0, 0);
|
||||||
|
|
||||||
|
qfv_imagebarrier_t ib = imageBarriers[qfv_LT_Undefined_to_TransferDst];
|
||||||
|
ib.barrier.image = sprite->image;
|
||||||
|
ib.barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
|
||||||
|
ib.barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
||||||
|
dfunc->vkCmdPipelineBarrier (packet->cmd, ib.srcStages, ib.dstStages,
|
||||||
|
0, 0, 0, 0, 0,
|
||||||
|
1, &ib.barrier);
|
||||||
|
|
||||||
|
VkBufferImageCopy copy = {
|
||||||
|
packet->offset + numverts * sizeof (spritevrt_t), 0, 0,
|
||||||
|
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, sprite_ctx->numframes},
|
||||||
|
{0, 0, 0}, {dsprite->width, dsprite->height, 1},
|
||||||
|
};
|
||||||
|
dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer,
|
||||||
|
sprite->image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
1, ©);
|
||||||
|
QFV_GenerateMipMaps (device, packet->cmd, sprite->image,
|
||||||
|
mipLevels, dsprite->width, dsprite->height,
|
||||||
|
sprite_ctx->numframes);
|
||||||
|
|
||||||
|
QFV_PacketSubmit (packet);
|
||||||
|
QFV_DestroyStagingBuffer (stage);
|
||||||
|
|
||||||
|
sprite_ctx->sprite->data = (byte *) sprite - (byte *) sprite_ctx->sprite;
|
||||||
|
|
||||||
|
qfvPopDebug (ctx);
|
||||||
|
}
|
|
@ -49,6 +49,7 @@
|
||||||
#include "QF/Vulkan/qf_main.h"
|
#include "QF/Vulkan/qf_main.h"
|
||||||
#include "QF/Vulkan/qf_matrices.h"
|
#include "QF/Vulkan/qf_matrices.h"
|
||||||
#include "QF/Vulkan/qf_particles.h"
|
#include "QF/Vulkan/qf_particles.h"
|
||||||
|
#include "QF/Vulkan/qf_sprite.h"
|
||||||
#include "QF/Vulkan/qf_texture.h"
|
#include "QF/Vulkan/qf_texture.h"
|
||||||
#include "QF/Vulkan/qf_vid.h"
|
#include "QF/Vulkan/qf_vid.h"
|
||||||
#include "QF/Vulkan/capture.h"
|
#include "QF/Vulkan/capture.h"
|
||||||
|
@ -507,6 +508,7 @@ vulkan_Mod_IQMFinish (model_t *mod)
|
||||||
static void
|
static void
|
||||||
vulkan_Mod_SpriteLoadFrames (mod_sprite_ctx_t *sprite_ctx)
|
vulkan_Mod_SpriteLoadFrames (mod_sprite_ctx_t *sprite_ctx)
|
||||||
{
|
{
|
||||||
|
Vulkan_Mod_SpriteLoadFrames (sprite_ctx, vulkan_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in a new issue