[vulkan] Get IQM rendering working

The bones aren't animated yet (and I realized I made the mistake of
thinking the bone buffer was per-model when it's really per-instance (I
think this mistake is in the rest of QF, too)), skin rendering is a
mess, need to default vertex attributes that aren't in the model...
Still, it's quite satisfying seeing Mr Fixit on screen again :)

I wound up moving the pipeline spec in with the rest of the pipelines as
the system isn't really ready for separating them.
This commit is contained in:
Bill Currie 2022-05-07 10:08:46 +09:00
parent 3f7cbae4d0
commit 8795b8eb91
10 changed files with 274 additions and 303 deletions

View file

@ -65,6 +65,8 @@ typedef struct qfv_iqm_s {
qfv_iqm_skin_t *skins; qfv_iqm_skin_t *skins;
struct qfv_resource_s *mesh; struct qfv_resource_s *mesh;
struct qfv_resource_s *bones; struct qfv_resource_s *bones;
VkBuffer bones_buffer;
VkDescriptorSet *bones_descriptors; // one per frame FIXME per instance!!!
} qfv_iqm_t; } qfv_iqm_t;
typedef enum { typedef enum {
@ -91,15 +93,21 @@ typedef struct iqmctx_s {
VkPipeline gbuf; VkPipeline gbuf;
VkPipelineLayout layout; VkPipelineLayout layout;
VkSampler sampler; VkSampler sampler;
VkDescriptorPool bones_pool;
VkDescriptorSetLayout bones_setLayout;
} iqmctx_t; } iqmctx_t;
struct vulkan_ctx_s; struct vulkan_ctx_s;
struct qfv_renderframe_s; struct qfv_renderframe_s;
struct entity_s; struct entity_s;
struct mod_iqm_ctx_s; struct mod_iqm_ctx_s;
struct iqm_s;
void Vulkan_Mod_IQMFinish (struct model_s *mod, struct vulkan_ctx_s *ctx); void Vulkan_Mod_IQMFinish (struct model_s *mod, struct vulkan_ctx_s *ctx);
void Vulkan_IQMAddBones (struct vulkan_ctx_s *ctx, struct iqm_s *iqm);
void Vulkan_IQMRemoveBones (struct vulkan_ctx_s *ctx, struct iqm_s *iqm);
void Vulkan_IQMAddSkin (struct vulkan_ctx_s *ctx, qfv_iqm_skin_t *skin); void Vulkan_IQMAddSkin (struct vulkan_ctx_s *ctx, qfv_iqm_skin_t *skin);
void Vulkan_IQMRemoveSkin (struct vulkan_ctx_s *ctx, qfv_iqm_skin_t *skin); void Vulkan_IQMRemoveSkin (struct vulkan_ctx_s *ctx, qfv_iqm_skin_t *skin);

View file

@ -127,7 +127,7 @@ typedef struct {
byte weights[4]; byte weights[4];
} iqmblend_t; } iqmblend_t;
typedef struct { typedef struct iqm_s {
char *text; char *text;
int num_meshes; int num_meshes;
iqmmesh *meshes; iqmmesh *meshes;

View file

@ -81,6 +81,11 @@ vulkan_iqm_clear (model_t *mod, void *data)
mod->needload = true; mod->needload = true;
for (int i = 0; i < iqm->num_meshes; i++) {
Vulkan_IQMRemoveSkin (ctx, &mesh->skins[i]);
}
Vulkan_IQMRemoveBones (ctx, iqm);//FIXME doesn't belong here (per-instance)
QFV_DestroyResource (device, mesh->bones); QFV_DestroyResource (device, mesh->bones);
QFV_DestroyResource (device, mesh->mesh); QFV_DestroyResource (device, mesh->mesh);
free (mesh); free (mesh);
@ -162,6 +167,14 @@ iqm_transfer_texture (tex_t *tex, VkImage image, qfv_stagebuf_t *stage,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, &ib.barrier); 1, &ib.barrier);
memcpy (dst, tex->data, layer_size); memcpy (dst, tex->data, layer_size);
VkBufferImageCopy copy = {
packet->offset, 0, 0,
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
{0, 0, 0}, {tex->width, tex->height, 1},
};
dfunc->vkCmdCopyBufferToImage (packet->cmd, packet->stage->buffer,
image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &copy);
int mipLevels = QFV_MipLevels (tex->width, tex->height); int mipLevels = QFV_MipLevels (tex->width, tex->height);
if (mipLevels == 1) { if (mipLevels == 1) {
@ -225,6 +238,7 @@ vulkan_iqm_load_textures (model_t *mod, iqm_t *iqm, qfv_iqm_t *mesh,
tex = &null_tex; tex = &null_tex;
} }
iqm_transfer_texture (tex, image->image, stage, device); iqm_transfer_texture (tex, image->image, stage, device);
Vulkan_IQMAddSkin (ctx, skin);
} }
dstring_delete (str); dstring_delete (str);
QFV_DestroyStagingBuffer (stage); QFV_DestroyStagingBuffer (stage);
@ -236,6 +250,8 @@ vulkan_iqm_load_arrays (model_t *mod, iqm_t *iqm, qfv_iqm_t *mesh,
{ {
qfv_device_t *device = ctx->device; qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs; qfv_devfuncs_t *dfunc = device->funcs;
iqmctx_t *ictx = ctx->iqm_context;
size_t geom_size = iqm->num_verts * sizeof (iqmgvert_t); size_t geom_size = iqm->num_verts * sizeof (iqmgvert_t);
size_t rend_size = iqm->num_verts * sizeof (iqmrvert_t); size_t rend_size = iqm->num_verts * sizeof (iqmrvert_t);
size_t elem_size = iqm->num_elements * sizeof (uint16_t); size_t elem_size = iqm->num_elements * sizeof (uint16_t);
@ -350,7 +366,7 @@ vulkan_iqm_load_arrays (model_t *mod, iqm_t *iqm, qfv_iqm_t *mesh,
vec4f_t *bone_data; vec4f_t *bone_data;
dfunc->vkMapMemory (device->dev, mesh->bones->memory, 0, VK_WHOLE_SIZE, dfunc->vkMapMemory (device->dev, mesh->bones->memory, 0, VK_WHOLE_SIZE,
0, (void **)&bone_data); 0, (void **)&bone_data);
for (int i = 0; i < 3 * iqm->num_joints; i++) { for (size_t i = 0; i < ictx->frames.size * iqm->num_joints; i++) {
vec4f_t *bone = bone_data + i * 3; vec4f_t *bone = bone_data + i * 3;
bone[0] = (vec4f_t) {1, 0, 0, 0}; bone[0] = (vec4f_t) {1, 0, 0, 0};
bone[1] = (vec4f_t) {0, 1, 0, 0}; bone[1] = (vec4f_t) {0, 1, 0, 0};
@ -363,12 +379,15 @@ vulkan_iqm_load_arrays (model_t *mod, iqm_t *iqm, qfv_iqm_t *mesh,
dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range); dfunc->vkFlushMappedMemoryRanges (device->dev, 1, &range);
dfunc->vkUnmapMemory (device->dev, mesh->bones->memory); dfunc->vkUnmapMemory (device->dev, mesh->bones->memory);
Vulkan_IQMAddBones (ctx, iqm); //FIXME doesn't belong here (per-instance)
} }
void void
Vulkan_Mod_IQMFinish (model_t *mod, vulkan_ctx_t *ctx) Vulkan_Mod_IQMFinish (model_t *mod, vulkan_ctx_t *ctx)
{ {
qfv_device_t *device = ctx->device; qfv_device_t *device = ctx->device;
iqmctx_t *ictx = ctx->iqm_context;
iqm_t *iqm = (iqm_t *) mod->aliashdr; iqm_t *iqm = (iqm_t *) mod->aliashdr;
mod->clear = vulkan_iqm_clear; mod->clear = vulkan_iqm_clear;
mod->data = ctx; mod->data = ctx;
@ -378,10 +397,12 @@ Vulkan_Mod_IQMFinish (model_t *mod, vulkan_ctx_t *ctx)
// 2 is for image + image view // 2 is for image + image view
int num_objects = 4 + 2 * iqm->num_meshes; int num_objects = 4 + 2 * iqm->num_meshes;
qfv_iqm_t *mesh = calloc (1, sizeof (qfv_iqm_t) qfv_iqm_t *mesh = calloc (1, sizeof (qfv_iqm_t)
+ ictx->frames.size * sizeof (VkDescriptorSet)
+ 2 * sizeof (qfv_resource_t) + 2 * sizeof (qfv_resource_t)
+ num_objects * sizeof (qfv_resobj_t) + num_objects * sizeof (qfv_resobj_t)
+ iqm->num_meshes * sizeof (qfv_iqm_skin_t)); + iqm->num_meshes * sizeof (qfv_iqm_skin_t));
mesh->bones = (qfv_resource_t *) &mesh[1]; mesh->bones_descriptors = (VkDescriptorSet *) &mesh[1];
mesh->bones = (qfv_resource_t *)&mesh->bones_descriptors[ictx->frames.size];
mesh->mesh = &mesh->bones[1]; mesh->mesh = &mesh->bones[1];
mesh->bones[0] = (qfv_resource_t) { mesh->bones[0] = (qfv_resource_t) {
@ -395,9 +416,9 @@ Vulkan_Mod_IQMFinish (model_t *mod, vulkan_ctx_t *ctx)
.name = "bones", .name = "bones",
.type = qfv_res_buffer, .type = qfv_res_buffer,
.buffer = { .buffer = {
.size = 3 * iqm->num_joints * 3 * sizeof (vec4f_t), .size = ictx->frames.size * iqm->num_joints * 3 * sizeof (vec4f_t),
.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
| VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
}, },
}; };
@ -460,9 +481,10 @@ Vulkan_Mod_IQMFinish (model_t *mod, vulkan_ctx_t *ctx)
mesh->geom_buffer = mesh->mesh->objects[0].buffer.buffer; mesh->geom_buffer = mesh->mesh->objects[0].buffer.buffer;
mesh->rend_buffer = mesh->mesh->objects[1].buffer.buffer; mesh->rend_buffer = mesh->mesh->objects[1].buffer.buffer;
mesh->index_buffer = mesh->mesh->objects[2].buffer.buffer; mesh->index_buffer = mesh->mesh->objects[2].buffer.buffer;
mesh->bones_buffer = mesh->bones->objects[0].buffer.buffer;
iqm->extra_data = mesh;
vulkan_iqm_load_textures (mod, iqm, mesh, ctx); vulkan_iqm_load_textures (mod, iqm, mesh, ctx);
vulkan_iqm_load_arrays (mod, iqm, mesh, ctx); vulkan_iqm_load_arrays (mod, iqm, mesh, ctx);
iqm->extra_data = mesh;
} }

View file

@ -92,6 +92,7 @@ vulkan_R_Init (void)
Vulkan_Matrix_Init (vulkan_ctx); Vulkan_Matrix_Init (vulkan_ctx);
Vulkan_Alias_Init (vulkan_ctx); Vulkan_Alias_Init (vulkan_ctx);
Vulkan_Bsp_Init (vulkan_ctx); Vulkan_Bsp_Init (vulkan_ctx);
Vulkan_IQM_Init (vulkan_ctx);
Vulkan_Particles_Init (vulkan_ctx); Vulkan_Particles_Init (vulkan_ctx);
Vulkan_Sprite_Init (vulkan_ctx); Vulkan_Sprite_Init (vulkan_ctx);
Vulkan_Draw_Init (vulkan_ctx); Vulkan_Draw_Init (vulkan_ctx);
@ -686,16 +687,18 @@ vulkan_vid_render_shutdown (void)
df->vkDestroyFence (dev, vulkan_ctx->fence, 0); df->vkDestroyFence (dev, vulkan_ctx->fence, 0);
df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0); df->vkDestroyCommandPool (dev, vulkan_ctx->cmdpool, 0);
Mod_ClearAll ();
Vulkan_Compose_Shutdown (vulkan_ctx); Vulkan_Compose_Shutdown (vulkan_ctx);
Vulkan_Lighting_Shutdown (vulkan_ctx); Vulkan_Lighting_Shutdown (vulkan_ctx);
Vulkan_Draw_Shutdown (vulkan_ctx); Vulkan_Draw_Shutdown (vulkan_ctx);
Vulkan_Sprite_Shutdown (vulkan_ctx); Vulkan_Sprite_Shutdown (vulkan_ctx);
Vulkan_Particles_Shutdown (vulkan_ctx); Vulkan_Particles_Shutdown (vulkan_ctx);
Vulkan_IQM_Shutdown (vulkan_ctx);
Vulkan_Bsp_Shutdown (vulkan_ctx); Vulkan_Bsp_Shutdown (vulkan_ctx);
Vulkan_Alias_Shutdown (vulkan_ctx); Vulkan_Alias_Shutdown (vulkan_ctx);
Vulkan_Matrix_Shutdown (vulkan_ctx); Vulkan_Matrix_Shutdown (vulkan_ctx);
Mod_ClearAll ();
Vulkan_Texture_Shutdown (vulkan_ctx); Vulkan_Texture_Shutdown (vulkan_ctx);
Vulkan_DestroyRenderPasses (vulkan_ctx); Vulkan_DestroyRenderPasses (vulkan_ctx);
Vulkan_Shutdown_Common (vulkan_ctx); Vulkan_Shutdown_Common (vulkan_ctx);

View file

@ -1,254 +0,0 @@
{
setLayouts = {
texture_set = {
bindings = (
{
binding = 0;
descriptorType = combined_image_sampler;
descriptorCount = 1;
stageFlags = fragment;
},
);
};
};
pipelineLayouts = {
iqm_layout = {
setLayouts = (matrix_set, texture_set);
pushConstantRanges = (
{
stageFlags = vertex;
offset = 0;
size = "16 * 4 + 4";
},
{
stageFlags = fragment;
offset = 68;
size = "3 * 4 + 2 * 4 * 4 + 4";
},
);
};
};
depthStencil = {
test_and_write = {
depthTestEnable = true;
depthWriteEnable = true;
depthCompareOp = less_or_equal;
depthBoundsTestEnable = false;
stencilTestEnable = false;
};
test_only = {
depthTestEnable = true;
depthWriteEnable = false;
depthCompareOp = less_or_equal;
depthBoundsTestEnable = false;
stencilTestEnable = false;
};
disable = {
depthTestEnable = false;
depthWriteEnable = false;
depthCompareOp = less_or_equal;
depthBoundsTestEnable = false;
stencilTestEnable = false;
};
};
inputAssembly = {
iqm = {
topology = triangle_list;
primitiveRestartEnable = false;
};
};
vertexInput = {
iqm = {
bindings = (
{ binding = 0; stride = 20; inputRate = vertex; },
{ binding = 1; stride = 40; inputRate = vertex; },
);
attributes = (
{ location = 0; binding = 0; format = r32g32b32_sfloat; offset = 0; }, // position
{ location = 1; binding = 0; format = r8g8b8a8_uint; offset = 0; }, // bonindices
{ location = 2; binding = 0; format = r8g8b8a8_unorm; offset = 4; }, // boneweights
{ location = 3; binding = 1; format = r32g32_sfloat; offset = 0; }, // texcoord
{ location = 4; binding = 1; format = r32g32b32_sfloat; offset = 8; }, // normal
{ location = 5; binding = 1; format = r32g32b32a32_sfloat; offset = 20; }, // tangent
{ location = 6; binding = 1; format = r8g8b8a8_unorm; offset = 36; }, // color
);
};
};
rasterization = {
cw_cull_back = {
depthClampEnable = false;
rasterizerDiscardEnable = false;
polygonMode = fill;
cullMode = back;
frontFace = clockwise;
depthBiasEnable = false;
lineWidth = 1;
};
counter_cw_cull_back = {
depthClampEnable = false;
rasterizerDiscardEnable = false;
polygonMode = fill;
cullMode = back;
frontFace = counter_clockwise;
depthBiasEnable = false;
lineWidth = 1;
};
};
multisample = {
rasterizationSamples = $msaaSamples;
sampleShadingEnable = false;
minSampleShading = 0.5f;
alphaToCoverageEnable = false;
alphaToOneEnable = false;
};
viewport = {
viewports = (
{
x = 0; y = 0;
width = 640; height = 480;
minDepth = 0; maxDepth = 1;
}
);
scissors = (
{
offset = { x = 0; y = 0 };
extent = { width = 640; height = 480; };
},
);
};
attachmentBlendOp = {
disabled = {
blendEnable = false;
srcColorBlendFactor = src_alpha;
dstColorBlendFactor = one_minus_src_alpha;
colorBlendOp = add;
srcAlphaBlendFactor = src_alpha;
dstAlphaBlendFactor = one_minus_src_alpha;
alphaBlendOp = add;
colorWriteMask = r|g|b|a;
};
alpha_blend = {
blendEnable = true;
srcColorBlendFactor = src_alpha;
dstColorBlendFactor = one_minus_src_alpha;
colorBlendOp = add;
srcAlphaBlendFactor = src_alpha;
dstAlphaBlendFactor = one_minus_src_alpha;
alphaBlendOp = add;
colorWriteMask = r|g|b|a;
};
};
pipelines = {
iqm_shadow = {
subpass = 0;
stages = (
{
stage = vertex;
name = main;
module = $builtin/iqm_shadow.vert;
},
);
vertexInput = {
bindings = (
"$properties.vertexInput.iqm.bindings[0]",
"$properties.vertexInput.iqm.bindings[1]",
);
attributes = (
"$properties.vertexInput.iqm.attributes[0]",
"$properties.vertexInput.iqm.attributes[1]",
"$properties.vertexInput.iqm.attributes[2]",
"$properties.vertexInput.iqm.attributes[3]",
);
};
inputAssembly = $properties.inputAssembly.iqm;
viewport = $properties.viewport;
rasterization = $properties.rasterization.cw_cull_back;
multisample = $properties.multisample;
depthStencil = $properties.depthStencil.test_and_write;
colorBlend = $properties.pipelines.iqm_gbuf.colorBlend;
dynamic = {
dynamicState = ( viewport, scissor );
};
layout = iqm_layout;
};
iqm_depth = {
subpass = 0;
stages = (
{
stage = vertex;
name = main;
module = $builtin/iqm_depth.vert;
},
);
vertexInput = {
// depth pass doesn't use UVs
bindings = (
"$properties.vertexInput.iqm.bindings[0]",
"$properties.vertexInput.iqm.bindings[1]",
);
attributes = (
"$properties.vertexInput.iqm.attributes[0]",
"$properties.vertexInput.iqm.attributes[1]",
"$properties.vertexInput.iqm.attributes[2]",
"$properties.vertexInput.iqm.attributes[3]",
);
};
inputAssembly = $properties.inputAssembly.iqm;
viewport = $properties.viewport;
rasterization = $properties.rasterization.cw_cull_back;
multisample = $properties.multisample;
depthStencil = $properties.depthStencil.test_and_write;
colorBlend = $properties.pipelines.iqm_gbuf.colorBlend;
dynamic = {
dynamicState = ( viewport, scissor );
};
layout = iqm_layout;
renderPass = renderpass;
};
iqm_gbuf = {
subpass = 2;
stages = (
{
stage = vertex;
name = main;
module = $builtin/iqm.vert;
},
{
stage = fragment;
name = main;
module = $builtin/iqm_gbuf.frag;
},
);
vertexInput = $properties.vertexInput.iqm;
inputAssembly = $properties.inputAssembly.iqm;
viewport = $properties.viewport;
rasterization = $properties.rasterization.cw_cull_back;
multisample = $properties.multisample;
depthStencil = $properties.depthStencil.test_only;
colorBlend = {
logicOpEnable = false;
attachments = (
$properties.attachmentBlendOp.disabled,
$properties.attachmentBlendOp.disabled,
$properties.attachmentBlendOp.disabled,
$properties.attachmentBlendOp.disabled,
);
};
dynamic = {
dynamicState = ( viewport, scissor, blend_constants );
};
layout = iqm_layout;
renderPass = renderpass;
};
};
}

View file

@ -97,6 +97,16 @@
}, },
); );
}; };
bone_pool = {
flags = free_descriptor_set;
maxSets = 512;
bindings = (
{
type = storage_buffer;
descriptorCount = $properties.descriptorPools.bone_pool.maxSets;
},
);
};
texture_pool = { texture_pool = {
flags = free_descriptor_set; flags = free_descriptor_set;
maxSets = 512; maxSets = 512;
@ -206,6 +216,16 @@
}, },
); );
}; };
bone_set = {
bindings = (
{
binding = 0;
descriptorType = storage_buffer;
descriptorCount = 1;
stageFlags = vertex;
},
);
};
sprite_set = { sprite_set = {
bindings = ( bindings = (
{ {
@ -349,6 +369,21 @@
}, },
); );
}; };
iqm_layout = {
setLayouts = (matrix_set, texture_set, bone_set);
pushConstantRanges = (
{
stageFlags = vertex;
offset = 0;
size = "16 * 4 + 4";
},
{
stageFlags = fragment;
offset = 68;
size = "3 * 4 + 2 * 4 * 4 + 4";
},
);
};
sprite_layout = { sprite_layout = {
setLayouts = (matrix_set, sprite_set); setLayouts = (matrix_set, sprite_set);
pushConstantRanges = ( pushConstantRanges = (
@ -428,6 +463,10 @@
topology = triangle_fan; topology = triangle_fan;
primitiveRestartEnable = true; primitiveRestartEnable = true;
}; };
iqm = {
topology = triangle_list;
primitiveRestartEnable = false;
};
twod = { twod = {
topology = triangle_strip; topology = triangle_strip;
primitiveRestartEnable = true; primitiveRestartEnable = true;
@ -466,6 +505,23 @@
{ location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; }, { location = 1; binding = 0; format = r32g32b32a32_sfloat; offset = 16; },
); );
}; };
iqm = {
bindings = (
{ binding = 0; stride = 20; inputRate = vertex; },
{ binding = 1; stride = 40; inputRate = vertex; },
);
attributes = (
{ location = 0; binding = 0; format = r32g32b32_sfloat; offset = 0; }, // position
{ location = 1; binding = 0; format = r8g8b8a8_uint; offset = 12; }, // bonindices
{ location = 2; binding = 0; format = r8g8b8a8_unorm; offset = 16; }, // boneweights
{ location = 3; binding = 1; format = r32g32_sfloat; offset = 0; }, // texcoord
{ location = 4; binding = 1; format = r32g32b32_sfloat; offset = 8; }, // normal
{ location = 5; binding = 1; format = r32g32b32a32_sfloat; offset = 20; }, // tangent
{ location = 6; binding = 1; format = r8g8b8a8_unorm; offset = 36; }, // color
);
};
particle = { particle = {
bindings = ( bindings = (
{ binding = 0; stride = "4 * 4 * 4"; inputRate = vertex; }, { binding = 0; stride = "4 * 4 * 4"; inputRate = vertex; },
@ -833,6 +889,61 @@
inputAssembly = $properties.inputAssembly.brush; inputAssembly = $properties.inputAssembly.brush;
layout = quakebsp_layout; layout = quakebsp_layout;
}; };
iqm_depth = {
@inherit = $properties.pipelines.depth_base;
stages = (
{
stage = vertex;
name = main;
module = $builtin/iqm.vert;
specializationInfo = {
mapEntries = (
// IQMDepthOnly
{ size = 4; offset = 0; constantID = 0; },
);
data = "array(1)";
};
},
);
vertexInput = $properties.vertexInput.iqm;
/*vertexInput = {
bindings = (
"$properties.vertexInput.iqm.bindings[0]",
);
attributes = (
"$properties.vertexInput.iqm.attributes[0]",
"$properties.vertexInput.iqm.attributes[1]",
"$properties.vertexInput.iqm.attributes[2]",
);
};*/
inputAssembly = $properties.inputAssembly.iqm;
layout = iqm_layout;
};
iqm_gbuf = {
@inherit = $properties.pipelines.gbuf_base;
stages = (
{
stage = vertex;
name = main;
module = $builtin/iqm.vert;
specializationInfo = {
mapEntries = (
// !IQMDepthOnly
{ size = 4; offset = 0; constantID = 0; },
);
data = "array(0)";
};
},
{
stage = fragment;
name = main;
module = $builtin/iqm.frag;
},
);
vertexInput = $properties.vertexInput.iqm;
inputAssembly = $properties.inputAssembly.iqm;
layout = iqm_layout;
};
partdraw = { partdraw = {
@inherit = $properties.pipelines.trans_base; @inherit = $properties.pipelines.trans_base;
stages = ( stages = (

View file

@ -1,6 +1,6 @@
#version 450 #version 450
layout (set = 1, binding = 0) uniform sampler2DArray Skin; layout (set = 1, binding = 0) uniform sampler2D Skin;
layout (push_constant) uniform PushConstants { layout (push_constant) uniform PushConstants {
layout (offset = 68) layout (offset = 68)
@ -15,7 +15,7 @@ layout (location = 1) in vec4 position;
layout (location = 2) in vec3 normal; layout (location = 2) in vec3 normal;
layout (location = 3) in vec3 tangent; layout (location = 3) in vec3 tangent;
layout (location = 4) in vec3 bitangent; layout (location = 4) in vec3 bitangent;
layout (location = 5) in vec3 color; layout (location = 5) in vec4 color;
layout (location = 0) out vec4 frag_color; layout (location = 0) out vec4 frag_color;
layout (location = 1) out vec4 frag_emission; layout (location = 1) out vec4 frag_emission;
@ -27,18 +27,19 @@ main (void)
{ {
vec4 c; vec4 c;
vec4 e; vec4 e;
vec3 n; //vec3 n;
int i; int i;
mat3 tbn = mat3 (tangent, bitangent, normal); //mat3 tbn = mat3 (tangent, bitangent, normal);
c = texture (Skin, vec3 (texcoord, 0)) * base_color; c = texture (Skin, texcoord);// * color;
c += texture (Skin, vec3 (texcoord, 1)) * unpackUnorm4x8(colorA); //c = texture (Skin, vec3 (texcoord, 0)) * color;
c += texture (Skin, vec3 (texcoord, 2)) * unpackUnorm4x8(colorB); //c += texture (Skin, vec3 (texcoord, 1)) * unpackUnorm4x8(colorA);
e = texture (Skin, vec3 (texcoord, 3)); //c += texture (Skin, vec3 (texcoord, 2)) * unpackUnorm4x8(colorB);
n = texture (Skin, vec3 (texcoord, 4)).xyz * 2 - 1; //e = texture (Skin, vec3 (texcoord, 3));
//n = texture (Skin, vec3 (texcoord, 4)).xyz * 2 - 1;
frag_color = c; frag_color = c;
frag_emission = e; frag_emission = vec4(0,0,0,1);//e;
frag_normal = vec4(tbn * n, 1); frag_normal = vec4(normal,1);//vec4(tbn * n, 1);
frag_position = position; frag_position = position;
} }

View file

@ -1,5 +1,7 @@
#version 450 #version 450
layout (constant_id = 0) const bool IQMDepthOnly = false;
layout (set = 0, binding = 0) uniform Matrices { layout (set = 0, binding = 0) uniform Matrices {
mat4 Projection3d; mat4 Projection3d;
mat4 View; mat4 View;
@ -7,7 +9,7 @@ layout (set = 0, binding = 0) uniform Matrices {
mat4 Projection2d; mat4 Projection2d;
}; };
layout (set = 3, binding = 0) buffer Bones { layout (set = 2, binding = 0) buffer Bones {
// NOTE these are transposed, so v * m // NOTE these are transposed, so v * m
mat3x4 bones[]; mat3x4 bones[];
}; };
@ -18,7 +20,7 @@ layout (push_constant) uniform PushConstants {
}; };
layout (location = 0) in vec3 vposition; layout (location = 0) in vec3 vposition;
layout (location = 1) in ivec4 vbones; layout (location = 1) in uvec4 vbones;
layout (location = 2) in vec4 vweights; layout (location = 2) in vec4 vweights;
layout (location = 3) in vec2 vtexcoord; layout (location = 3) in vec2 vtexcoord;
layout (location = 4) in vec3 vnormal; layout (location = 4) in vec3 vnormal;
@ -41,12 +43,16 @@ main (void)
m += bones[vbones.w] * vweights.w; m += bones[vbones.w] * vweights.w;
vec4 pos = vec4 (Model * vec4(vposition, 1) * m, 1); vec4 pos = vec4 (Model * vec4(vposition, 1) * m, 1);
gl_Position = Projection3d * (View * pos); gl_Position = Projection3d * (View * pos);
position = pos;
mat3 adjTrans = mat3 (cross(m[1].xyz, m[2].xyz), cross(m[2].xyz, m[0].xyz), if (!IQMDepthOnly) {
cross(m[0].xyz, m[1].xyz)); position = pos;
normal = mat3 (Model) * vnormal * adjTrans; mat3 adjTrans = mat3 (cross(m[1].xyz, m[2].xyz),
tangent = mat3 (Model) * vtangent.xyz * adjTrans; cross(m[2].xyz, m[0].xyz),
bitangent = cross (normal, tangent) * vtangent.w; cross(m[0].xyz, m[1].xyz));
texcoord = vtexcoord; normal = mat3 (Model) * vnormal * adjTrans;
color = vcolor; tangent = mat3 (Model) * vtangent.xyz * adjTrans;
bitangent = cross (normal, tangent) * vtangent.w;
texcoord = vtexcoord;
color = vcolor;
}
} }

View file

@ -34,6 +34,7 @@
#include <string.h> #include <string.h>
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/iqm.h"
#include "QF/va.h" #include "QF/va.h"
#include "QF/scene/entity.h" #include "QF/scene/entity.h"
@ -42,6 +43,7 @@
#include "QF/Vulkan/qf_matrices.h" #include "QF/Vulkan/qf_matrices.h"
#include "QF/Vulkan/qf_texture.h" #include "QF/Vulkan/qf_texture.h"
#include "QF/Vulkan/debug.h" #include "QF/Vulkan/debug.h"
#include "QF/Vulkan/descriptor.h"
#include "QF/Vulkan/device.h" #include "QF/Vulkan/device.h"
#include "QF/Vulkan/instance.h" #include "QF/Vulkan/instance.h"
#include "QF/Vulkan/renderpass.h" #include "QF/Vulkan/renderpass.h"
@ -72,7 +74,7 @@ static QFV_Subpass subpass_map[] = {
static void static void
emit_commands (VkCommandBuffer cmd, int pose1, int pose2, emit_commands (VkCommandBuffer cmd, int pose1, int pose2,
qfv_iqm_skin_t **skins, qfv_iqm_skin_t *skins,
uint32_t numPC, qfv_push_constants_t *constants, uint32_t numPC, qfv_push_constants_t *constants,
iqm_t *iqm, qfv_renderframe_t *rFrame) iqm_t *iqm, qfv_renderframe_t *rFrame)
{ {
@ -88,20 +90,28 @@ emit_commands (VkCommandBuffer cmd, int pose1, int pose2,
mesh->geom_buffer, mesh->geom_buffer,
mesh->rend_buffer, mesh->rend_buffer,
}; };
int bindingCount = skins ? 2 : 1; int bindingCount = 2;//skins ? 2 : 1;
dfunc->vkCmdBindVertexBuffers (cmd, 0, bindingCount, buffers, offsets); dfunc->vkCmdBindVertexBuffers (cmd, 0, bindingCount, buffers, offsets);
dfunc->vkCmdBindIndexBuffer (cmd, mesh->index_buffer, 0, dfunc->vkCmdBindIndexBuffer (cmd, mesh->index_buffer, 0,
VK_INDEX_TYPE_UINT32); VK_INDEX_TYPE_UINT16);
QFV_PushConstants (device, cmd, ictx->layout, numPC, constants); QFV_PushConstants (device, cmd, ictx->layout, numPC, constants);
for (int i = 0; i < iqm->num_meshes; i++) { for (int i = 0; i < iqm->num_meshes; i++) {
if (skins) { if (skins) {
VkDescriptorSet sets[] = { VkDescriptorSet sets[] = {
skins[i]->descriptor, skins[i].descriptor,
mesh->bones_descriptors[ctx->curFrame],
}; };
dfunc->vkCmdBindDescriptorSets (cmd, dfunc->vkCmdBindDescriptorSets (cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS, VK_PIPELINE_BIND_POINT_GRAPHICS,
ictx->layout, 1, 1, sets, 0, 0); ictx->layout, 1, 2, sets, 0, 0);
} else {
VkDescriptorSet sets[] = {
mesh->bones_descriptors[ctx->curFrame],
};
dfunc->vkCmdBindDescriptorSets (cmd,
VK_PIPELINE_BIND_POINT_GRAPHICS,
ictx->layout, 2, 1, sets, 0, 0);
} }
dfunc->vkCmdDrawIndexed (cmd, 3 * iqm->meshes[i].num_triangles, 1, dfunc->vkCmdDrawIndexed (cmd, 3 * iqm->meshes[i].num_triangles, 1,
3 * iqm->meshes[i].first_triangle, 0, 0); 3 * iqm->meshes[i].first_triangle, 0, 0);
@ -117,7 +127,7 @@ Vulkan_DrawIQM (entity_t *ent, qfv_renderframe_t *rFrame)
model_t *model = ent->renderer.model; model_t *model = ent->renderer.model;
iqm_t *iqm = (iqm_t *) model->aliashdr; iqm_t *iqm = (iqm_t *) model->aliashdr;
qfv_iqm_t *mesh = iqm->extra_data; qfv_iqm_t *mesh = iqm->extra_data;
qfv_iqm_skin_t **skins = &mesh->skins; qfv_iqm_skin_t *skins = mesh->skins;
iqm_push_constants_t constants = {}; iqm_push_constants_t constants = {};
constants.blend = R_IQMGetLerpedFrames (ent, iqm); constants.blend = R_IQMGetLerpedFrames (ent, iqm);
@ -144,8 +154,8 @@ Vulkan_DrawIQM (entity_t *ent, qfv_renderframe_t *rFrame)
}; };
QuatCopy (ent->renderer.colormod, constants.base_color); QuatCopy (ent->renderer.colormod, constants.base_color);
QuatCopy (skins[0]->colora, constants.colorA); QuatCopy (skins[0].colora, constants.colorA);
QuatCopy (skins[0]->colorb, constants.colorB); QuatCopy (skins[0].colorb, constants.colorB);
QuatZero (constants.fog); QuatZero (constants.fog);
emit_commands (aframe->cmdSet.a[QFV_iqmDepth], emit_commands (aframe->cmdSet.a[QFV_iqmDepth],
@ -157,8 +167,8 @@ Vulkan_DrawIQM (entity_t *ent, qfv_renderframe_t *rFrame)
} }
static void static void
alias_begin_subpass (QFV_IQMSubpass subpass, VkPipeline pipeline, iqm_begin_subpass (QFV_IQMSubpass subpass, VkPipeline pipeline,
qfv_renderframe_t *rFrame) qfv_renderframe_t *rFrame)
{ {
vulkan_ctx_t *ctx = rFrame->vulkan_ctx; vulkan_ctx_t *ctx = rFrame->vulkan_ctx;
qfv_device_t *device = ctx->device; qfv_device_t *device = ctx->device;
@ -200,7 +210,7 @@ alias_begin_subpass (QFV_IQMSubpass subpass, VkPipeline pipeline,
} }
static void static void
alias_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx) iqm_end_subpass (VkCommandBuffer cmd, vulkan_ctx_t *ctx)
{ {
qfv_device_t *device = ctx->device; qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs; qfv_devfuncs_t *dfunc = device->funcs;
@ -222,8 +232,8 @@ Vulkan_IQMBegin (qfv_renderframe_t *rFrame)
DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passGBuffer], DARRAY_APPEND (&rFrame->subpassCmdSets[QFV_passGBuffer],
aframe->cmdSet.a[QFV_iqmGBuffer]); aframe->cmdSet.a[QFV_iqmGBuffer]);
alias_begin_subpass (QFV_iqmDepth, ictx->depth, rFrame); iqm_begin_subpass (QFV_iqmDepth, ictx->depth, rFrame);
alias_begin_subpass (QFV_iqmGBuffer, ictx->gbuf, rFrame); iqm_begin_subpass (QFV_iqmGBuffer, ictx->gbuf, rFrame);
} }
void void
@ -233,8 +243,69 @@ Vulkan_IQMEnd (qfv_renderframe_t *rFrame)
iqmctx_t *ictx = ctx->iqm_context; iqmctx_t *ictx = ctx->iqm_context;
iqm_frame_t *aframe = &ictx->frames.a[ctx->curFrame]; iqm_frame_t *aframe = &ictx->frames.a[ctx->curFrame];
alias_end_subpass (aframe->cmdSet.a[QFV_iqmDepth], ctx); iqm_end_subpass (aframe->cmdSet.a[QFV_iqmDepth], ctx);
alias_end_subpass (aframe->cmdSet.a[QFV_iqmGBuffer], ctx); iqm_end_subpass (aframe->cmdSet.a[QFV_iqmGBuffer], ctx);
}
static VkWriteDescriptorSet base_buffer_write = {
VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, 0, 0,
0, 0, 1,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
0, 0, 0
};
void
Vulkan_IQMAddBones (vulkan_ctx_t *ctx, iqm_t *iqm)
{
qfvPushDebug (ctx, "Vulkan_IQMAddBones");
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
iqmctx_t *ictx = ctx->iqm_context;
__auto_type mesh = (qfv_iqm_t *) iqm->extra_data;
int num_sets = ictx->frames.size;
//FIXME kinda dumb
__auto_type layouts = QFV_AllocDescriptorSetLayoutSet (num_sets, alloca);
for (size_t i = 0; i < layouts->size; i++) {
layouts->a[i] = ictx->bones_setLayout;
}
__auto_type sets = QFV_AllocateDescriptorSet (device, ictx->bones_pool,
layouts);
for (size_t i = 0; i < sets->size; i++) {
mesh->bones_descriptors[i] = sets->a[i];
}
free (sets);
VkDescriptorBufferInfo bufferInfo[num_sets];
size_t bones_size = iqm->num_joints * 3 * sizeof (vec4f_t);
for (int i = 0; i < num_sets; i++) {
bufferInfo[i].buffer = mesh->bones_buffer;
bufferInfo[i].offset = i * bones_size;
bufferInfo[i].range = bones_size;
};
VkWriteDescriptorSet write[num_sets];
for (int i = 0; i < num_sets; i++) {
write[i] = base_buffer_write;
write[i].dstSet = mesh->bones_descriptors[i];
write[i].pBufferInfo = &bufferInfo[i];
}
dfunc->vkUpdateDescriptorSets (device->dev, num_sets, write, 0, 0);
qfvPopDebug (ctx);
}
void
Vulkan_IQMRemoveBones (vulkan_ctx_t *ctx, iqm_t *iqm)
{
qfv_device_t *device = ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;
iqmctx_t *ictx = ctx->iqm_context;
__auto_type mesh = (qfv_iqm_t *) iqm->extra_data;
int num_sets = ictx->frames.size;
dfunc->vkFreeDescriptorSets (device->dev, ictx->bones_pool, num_sets,
mesh->bones_descriptors);
} }
void void
@ -267,11 +338,14 @@ Vulkan_IQM_Init (vulkan_ctx_t *ctx)
DARRAY_RESIZE (&ictx->frames, frames); DARRAY_RESIZE (&ictx->frames, frames);
ictx->frames.grow = 0; ictx->frames.grow = 0;
ictx->depth = Vulkan_CreateGraphicsPipeline (ctx, "alias_depth"); ictx->depth = Vulkan_CreateGraphicsPipeline (ctx, "iqm_depth");
ictx->gbuf = Vulkan_CreateGraphicsPipeline (ctx, "alias_gbuf"); ictx->gbuf = Vulkan_CreateGraphicsPipeline (ctx, "iqm_gbuf");
ictx->layout = Vulkan_CreatePipelineLayout (ctx, "alias_layout"); ictx->layout = Vulkan_CreatePipelineLayout (ctx, "iqm_layout");
ictx->sampler = Vulkan_CreateSampler (ctx, "alias_sampler"); ictx->sampler = Vulkan_CreateSampler (ctx, "alias_sampler");
ictx->bones_pool = Vulkan_CreateDescriptorPool (ctx, "bone_pool");
ictx->bones_setLayout = Vulkan_CreateDescriptorSetLayout (ctx, "bone_set");
for (size_t i = 0; i < frames; i++) { for (size_t i = 0; i < frames; i++) {
__auto_type aframe = &ictx->frames.a[i]; __auto_type aframe = &ictx->frames.a[i];

View file

@ -51,7 +51,7 @@
#include "QF/Vulkan/qf_vid.h" #include "QF/Vulkan/qf_vid.h"
#include "QF/Vulkan/qf_alias.h" #include "QF/Vulkan/qf_alias.h"
#include "QF/Vulkan/qf_bsp.h" #include "QF/Vulkan/qf_bsp.h"
//#include "QF/Vulkan/qf_iqm.h" #include "QF/Vulkan/qf_iqm.h"
#include "QF/Vulkan/qf_lighting.h" #include "QF/Vulkan/qf_lighting.h"
#include "QF/Vulkan/qf_lightmap.h" #include "QF/Vulkan/qf_lightmap.h"
#include "QF/Vulkan/qf_main.h" #include "QF/Vulkan/qf_main.h"
@ -95,7 +95,7 @@ Vulkan_RenderEntities (entqueue_t *queue, qfv_renderframe_t *rFrame)
} while (0) } while (0)
RE_LOOP (alias, Alias); RE_LOOP (alias, Alias);
//RE_LOOP (iqm, IQM); RE_LOOP (iqm, IQM);
RE_LOOP (sprite, Sprite); RE_LOOP (sprite, Sprite);
} }