[vulkan] Make push constant ranges structured

Being able to specify the types in the push constant ranges makes it a
lot easier to get the specification correct. I never did like having to
do the offsets and sizes by hand as it was quite error prone. Right now,
float, int, uint, vec3, vec4 and mat4 are supported, and adheres to
layout std430.
This commit is contained in:
Bill Currie 2023-06-16 19:05:53 +09:00
parent c1b85a3db7
commit b0d1c0e75b
4 changed files with 180 additions and 82 deletions

View file

@ -35,12 +35,35 @@ typedef struct qfv_descriptorsetlayoutinfo_s {
VkDescriptorSetLayout setLayout;
} qfv_descriptorsetlayoutinfo_t;
typedef enum qfv_type_t {
qfv_float,
qfv_int,
qfv_uint,
qfv_vec3,
qfv_vec4,
qfv_mat4,
} qfv_type_t;
typedef struct qfv_pushconstantinfo_s {
const char *name;
int line;
qfv_type_t type;
uint32_t offset;
uint32_t size;
} qfv_pushconstantinfo_t;
typedef struct qfv_pushconstantrangeinfo_s {
VkShaderStageFlags stageFlags;
uint32_t num_pushconstants;
qfv_pushconstantinfo_t *pushconstants;
} qfv_pushconstantrangeinfo_t;
typedef struct qfv_layoutinfo_s {
const char *name;
uint32_t num_sets;
qfv_reference_t *sets;
uint32_t num_ranges;
VkPushConstantRange *ranges;
uint32_t num_pushconstantranges;
qfv_pushconstantrangeinfo_t *pushconstantranges;
VkPipelineLayout layout;
} qfv_layoutinfo_t;

View file

@ -374,6 +374,61 @@ find_descriptorSet (const qfv_reference_t *ref, objstate_t *s)
s->rpi->name, s->spi->name, ref->line, ref->name);
}
#define RUP(x,a) (((x) + ((a) - 1)) & ~((a) - 1))
static uint32_t
parse_pushconstantrange (VkPushConstantRange *range,
qfv_pushconstantrangeinfo_t *pushconstantrange,
uint32_t offset, objstate_t *s)
{
uint32_t range_offset = ~0u;
for (uint32_t i = 0; i < pushconstantrange->num_pushconstants; i++) {
__auto_type pushconstant = & pushconstantrange->pushconstants[i];
uint32_t size = 0;
if (pushconstant->offset != ~0u) {
offset = pushconstant->offset;
}
if (pushconstant->size != ~0u) {
size = pushconstant->size;
} else {
switch (pushconstant->type) {
case qfv_float:
case qfv_int:
case qfv_uint:
size = sizeof (int32_t);
offset = RUP (offset, sizeof (int32_t));
break;
case qfv_vec3:
size = sizeof (vec3_t);
offset = RUP (offset, sizeof (vec4f_t));
break;
case qfv_vec4:
size = sizeof (vec4f_t);
offset = RUP (offset, sizeof (vec4f_t));
break;
case qfv_mat4:
size = sizeof (mat4f_t);
offset = RUP (offset, sizeof (vec4f_t));
break;
default:
Sys_Error ("%s.%s:%s:%d invalid type: %d",
s->rpi->name, s->spi->name, pushconstant->name,
pushconstant->line, pushconstant->type);
}
}
if (range_offset == ~0u) {
range_offset = offset;
}
offset += size;
}
*range = (VkPushConstantRange) {
.stageFlags = pushconstantrange->stageFlags,
.offset = range_offset,
.size = offset - range_offset,
};
return offset;
}
static qfv_layoutinfo_t *
find_layout (const qfv_reference_t *ref, objstate_t *s)
{
@ -393,12 +448,19 @@ find_layout (const qfv_reference_t *ref, objstate_t *s)
for (uint32_t i = 0; i < li->num_sets; i++) {
sets[i] = find_descriptorSet (&li->sets[i], s);
}
VkPushConstantRange ranges[li->num_pushconstantranges];
uint32_t offset = 0;
for (uint32_t i = 0; i < li->num_pushconstantranges; i++) {
offset = parse_pushconstantrange (&ranges[i],
&li->pushconstantranges[i],
offset, s);
}
VkPipelineLayoutCreateInfo cInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = li->num_sets,
.pSetLayouts = sets,
.pushConstantRangeCount = li->num_ranges,
.pPushConstantRanges = li->ranges,
.pushConstantRangeCount = li->num_pushconstantranges,
.pPushConstantRanges = ranges,
};
qfv_device_t *device = s->ctx->device;
qfv_devfuncs_t *dfunc = device->funcs;

View file

@ -244,14 +244,16 @@ properties = {
primitiveRestartEnable = true;
};
layout = {
descriptorSets = (matrix_set, entity_set, oit_set, texture_set, texture_set);
pushConstantRanges = (
{
stageFlags = fragment;
offset = 0;
size = "4 * 4 + 4 + 4 + 4";
},
);
descriptorSets = (matrix_set, entity_set, oit_set, texture_set,
texture_set);
pushConstants = {
fragment = {
fog = vec4;
time = float;
alpha = float;
turb_scale = float;
};
};
};
};
alias = {
@ -292,18 +294,10 @@ properties = {
};
layout = {
descriptorSets = (matrix_set, texture_set, texture_set);
pushConstantRanges = (
{
stageFlags = vertex;
offset = 0;
size = "16 * 4 + 4";
},
{
stageFlags = fragment;
offset = 68;
size = "3 * 4 + 2 * 4 * 4";
},
);
pushConstants = {
vertex = { Model = mat4; blend = float; };
fragment = { colors = uint; base_color = vec4; fog = vec4; };
};
};
};
iqm = {
@ -363,18 +357,18 @@ properties = {
};
layout = {
descriptorSets = (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";
},
);
pushConstants = {
vertex = {
Model = mat4;
blend = float;
};
fragment = {
colorA = uint;
colorB = uint;
base_color = vec4;
fog = vec4;
};
};
};
};
sprite = {
@ -411,20 +405,18 @@ properties = {
};
layout = {
descriptorSets = (matrix_set, sprite_set);
pushConstantRanges = (
{
stageFlags = vertex;
offset = 0;
// note: overlap with fragment is for the frame number
size = "16 * 4 + 4";
},
{
stageFlags = fragment;
offset = 64;
// note: overlap with vertex to share frame number
size = "2 * 4 + 2 * 4 + 4";
},
);
pushConstants = {
vertex = {
Model = mat4;
frame = int;
};
fragment = {
overlap = { offset = 64; type = int; };
frame = int;
spriteind = int;
fog = vec4;
};
};
};
};
particle = {
@ -463,23 +455,15 @@ properties = {
layout = {
draw = {
descriptorSets = (matrix_set, texture_set, oit_set);
pushConstantRanges = (
{
stageFlags = vertex;
offset = 0;
size = "16 * 4";
},
);
pushConstants = {
vertex = { Model = mat4; };
};
};
physics = {
descriptorSets = (particle_set);
pushConstantRanges = (
{
stageFlags = compute;
offset = 0;
size = "4 * 4 + 4";
},
);
pushConstants = {
compute = { gravity = vec4; dT = float; };
};
};
update = {
descriptorSets = (particle_set, particle_set, particle_set);
@ -544,13 +528,9 @@ properties = {
};
layout = {
descriptorSets = (matrix_set, output_set);
pushConstantRanges = (
{
stageFlags = fragment;
offset = 0;
size = "4";
}
);
pushConstants = {
fragment = { time = float; };
};
};
};
fisheye = {
@ -564,13 +544,9 @@ properties = {
};
layout = {
descriptorSets = (matrix_set, output_set);
pushConstantRanges = (
{
stageFlags = fragment;
offset = 0;
size = "2 * 4";
}
);
pushConstants = {
fragment = { fov = float; aspect = float; };
};
};
};
};

View file

@ -43,6 +43,8 @@ search = (
qfv_attachmentrefinfo_t,
qfv_attachmentsetinfo_t,
qfv_taskinfo_t,
qfv_pushconstantinfo_t,
qfv_pushconstantrangeinfo_t,
qfv_layoutinfo_t,
qfv_pipelineinfo_t,
qfv_subpassinfo_t,
@ -485,6 +487,41 @@ parse = {
values = preserve;
};
};
qfv_pushconstantinfo_s = {
.name = qfv_pushconstantinfo_t;
.type = (QFString, QFDictionary);
.dictionary = {
offset = -1;
size = -1;
.parse = auto;
name = $name;
line = $item.line;
};
.string = {
offset = -1;
size = -1;
name = $name;
line = $item.line;
type = $auto;
};
type = auto;
//stageFlags = auto;
offset = auto;
size = auto;
};
qfv_pushconstantrangeinfo_s = {
.name = qfv_pushconstantrangeinfo_t;
.type = (QFDictionary);
.dictionary = {
.parse = {
type = (labeledarray, qfv_pushconstantinfo_t, name);
size = num_pushconstants;
values = pushconstants;
};
stageFlags = $name.auto;
};
stageFlags = auto;
};
qfv_layoutinfo_s = {
.name = qfv_layoutinfo_t;
descriptorSets = {
@ -492,10 +529,10 @@ parse = {
size = num_sets;
values = sets;
};
pushConstantRanges = {
type = (array, VkPushConstantRange);
size = num_ranges;
values = ranges;
pushConstants = {
type = (labeledarray, qfv_pushconstantrangeinfo_t, stageFlags);
size = num_pushconstantranges;
values = pushconstantranges;
};
};
qfv_pipelineinfo_s = {