rt: add test previous frame blur

This commit is contained in:
Ivan 'provod' Avdeev 2023-01-28 14:50:43 -08:00 committed by LifeKILLED
parent a5abde2162
commit 3a87934415
5 changed files with 103 additions and 15 deletions

View File

@ -1,13 +1,5 @@
# Real next
>=E223
- [ ] previous frame resources reference
- specification:
- [x] I: prev_ -> resource flag + pair index
- [ ] II: new section in json
- internals:
- [ ] I: create a new image for prev_, track its source; swap them each frame
- [ ] II: create tightly coupled image pair[2], read from [frame%2] write to [frame%2+1]
- [ ] III: like (I) but with more general resource management: i.e. resource object for prev_ points to its source
- [ ] what if new meatpipe has different image format for a creatable image?
# Programmable render
@ -505,3 +497,14 @@
# 2023-01-22 E222
- [x] refcount meatpipe created images
- [x] rake yuri primary ray
# 2023-01-28 E223
- [x] previous frame resources reference
- specification:
- [x] I: prev_ -> resource flag + pair index
- [ ] II: new section in json
- internals:
- [x] I: create a new image for prev_, track its source; swap them each frame
Result is meh: too much indirection, hard to follow, many things need manual fragile updates.
- [ ] II: create tightly coupled image pair[2], read from [frame%2] write to [frame%2+1]
- [ ] III: like (I) but with more general resource management: i.e. resource object for prev_ points to its source

View File

@ -495,20 +495,26 @@ class Binding:
STAGE_MESH_BIT_NV = 0x00000080
STAGE_SUBPASS_SHADING_BIT_HUAWEI = 0x00004000
# TODO same values for meatpipe.c too
WRITE_BIT = 0x80000000
CREATE_BIT = 0x40000000
def __init__(self, node):
self.write = node.name.startswith('out_')
self.create = self.write
self.index = node.binding
self.descriptor_set = node.descriptor_set
self.stages = 0
prev_name = removeprefix(node.name, 'prev_') if node.name.startswith('prev_') else None
prev_resource_index = resources.getIndex(self.prev, None) if prev_name else None
prev_resource_index = resources.getIndex(prev_name, None) if prev_name else None
resource_name = removeprefix(node.name, 'out_') if self.write else node.name
self.__resource_index = resources.getIndex(resource_name, node, prev_resource_index)
if prev_resource_index is not None:
self.create = True
assert(self.descriptor_set >= 0)
assert(self.descriptor_set < 255)
@ -541,7 +547,11 @@ class Binding:
return self.__str__()
def serialize(self, out):
header = (Binding.WRITE_BIT if self.write else 0) | (self.descriptor_set << 8) | self.index
header = (self.descriptor_set << 8) | self.index
if self.write:
header |= Binding.WRITE_BIT
if self.create:
header |= Binding.CREATE_BIT
out.writeU32(header)
out.writeU32(resources.getMappedIndex(self.__resource_index))
out.writeU32(self.stages)

View File

@ -7,6 +7,7 @@
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0, rgba16f) uniform image2D out_dest;
layout(set = 0, binding = 9, rgba16f) uniform readonly image2D prev_dest;
layout(set = 0, binding = 1, rgba8) uniform readonly image2D base_color_a;

View File

@ -190,7 +190,9 @@ static qboolean readBindings(load_context_t *ctx, VkDescriptorSetLayoutBinding *
vk_meatpipe_resource_t *res = ctx->meatpipe.resources + res_index;
#define BINDING_WRITE_BIT 0x80000000u
#define BINDING_CREATE_BIT 0x40000000u
const qboolean write = !!(header & BINDING_WRITE_BIT);
const qboolean create = !!(header & BINDING_CREATE_BIT);
const uint32_t descriptor_set = (header >> 8) & 0xffu;
const uint32_t binding = header & 0xffu;
@ -216,7 +218,10 @@ static qboolean readBindings(load_context_t *ctx, VkDescriptorSetLayoutBinding *
pass->resource_map[i] = res_index;
if (write)
res->flags |= MEATPIPE_RES_WRITE | MEATPIPE_RES_CREATE; // TODO distinguish between write and create
res->flags |= MEATPIPE_RES_WRITE;
if (create)
res->flags |= MEATPIPE_RES_CREATE;
gEngine.Con_Reportf("Binding %d: %s ds=%d b=%d s=%08x res=%d type=%d write=%d\n",
i, name, descriptor_set, binding, stages, res_index, res->descriptor_type, write);
@ -300,7 +305,6 @@ static qboolean readResources(load_context_t *ctx) {
if (is_image) {
res->image_format = READ_U32("Couldn't read image format for res %d:%s", i, res->name);
res->prev_frame_index = READ_U32("Couldn't read resource %d:%s previous frame index", i, res->name);
res->prev_frame_index -= 1;
}
gEngine.Con_Reportf("Resource %d:%s = %08x is_image=%d image_format=%08x count=%d\n",

View File

@ -64,6 +64,7 @@ typedef struct {
vk_resource_t resource;
xvk_image_t image;
int refcount;
int source_index;
} rt_resource_t;
static struct {
@ -236,10 +237,40 @@ static void performTracing(VkCommandBuffer cmdbuf, const perform_tracing_args_t*
0, 0, NULL, ARRAYSIZE(bmb), bmb, 0, NULL);
}
// Transfer previous frames before they had a chance of their resource-barrier metadata overwritten (as there's no guaranteed order for them)
for (int i = ExternalResource_COUNT; i < MAX_RESOURCES; ++i) {
rt_resource_t* const res = g_rtx.res + i;
if (!res->name[0] || !res->image.image || res->source_index <= 0)
continue;
ASSERT(res->source_index <= COUNTOF(g_rtx.res));
rt_resource_t *const src = g_rtx.res + res->source_index - 1;
// Swap resources
const vk_resource_t tmp_res = res->resource;
const xvk_image_t tmp_img = res->image;
res->resource = src->resource;
res->image = src->image;
// TODO this is slightly incorrect, as they technically can have different resource->type values
src->resource = tmp_res;
src->image = tmp_img;
// If there was no initial state, prepare it. (this should happen only for the first frame)
if (res->resource.write.pipelines == 0) {
// TODO is there a better way? Can image be cleared w/o explicit clear op?
R_VkImageClear( cmdbuf, res->image.image );
res->resource.write.pipelines = VK_PIPELINE_STAGE_TRANSFER_BIT;
res->resource.write.image_layout = VK_IMAGE_LAYOUT_GENERAL;
res->resource.write.access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
}
}
// Clear intra-frame resources
for (int i = ExternalResource_COUNT; i < MAX_RESOURCES; ++i) {
rt_resource_t* const res = g_rtx.res + i;
if (!res->name[0] || !res->image.image)
if (!res->name[0] || !res->image.image || res->source_index > 0)
continue;
res->resource.read = res->resource.write = (ray_resource_state_t){0};
@ -282,6 +313,20 @@ static void performTracing(VkCommandBuffer cmdbuf, const perform_tracing_args_t*
0, 0, NULL, ARRAYSIZE(bmb), bmb, 0, NULL);
}
// Update image resource links after the prev_-related swap above
// TODO Preserve the indexes somewhere to avoid searching
for (int i = 0; i < g_rtx.mainpipe->resources_count; ++i) {
const vk_meatpipe_resource_t *mr = g_rtx.mainpipe->resources + i;
const int index = findResource(mr->name);
ASSERT(index >= 0);
ASSERT(index < MAX_RESOURCES);
rt_resource_t *const res = g_rtx.res + index;
const qboolean create = !!(mr->flags & MEATPIPE_RES_CREATE);
if (create && mr->descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
//ASSERT(g_rtx.mainpipe_resources[i]->value.image_object == &res->image);
g_rtx.mainpipe_resources[i]->value.image_object = &res->image;
}
R_VkMeatpipePerform(g_rtx.mainpipe, cmdbuf, (vk_meatpipe_perfrom_args_t) {
.frame_set_slot = args->frame_index,
.width = FRAME_WIDTH,
@ -309,6 +354,8 @@ static void performTracing(VkCommandBuffer cmdbuf, const perform_tracing_args_t*
};
R_VkImageBlit( cmdbuf, &blit_args );
g_rtx.mainpipe_out->resource.write.image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
}
DEBUG_END(cmdbuf);
}
@ -368,7 +415,6 @@ static void reloadMainpipe(void) {
const qboolean create = !!(mr->flags & MEATPIPE_RES_CREATE);
// FIXME no assert, just complain
if (create && mr->descriptor_type != VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
gEngine.Con_Printf(S_ERROR "Only storage image creation is supported for meatpipes\n");
goto fail;
@ -398,7 +444,9 @@ static void reloadMainpipe(void) {
.layers = 1,
.format = mr->image_format,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_STORAGE_BIT | (output ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT : 0),
// TODO figure out how to detect this need properly. prev_dest is not defined as "output"
//.usage = VK_IMAGE_USAGE_STORAGE_BIT | (output ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT : 0),
.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.has_alpha = true,
.is_cubemap = false,
};
@ -428,6 +476,28 @@ static void reloadMainpipe(void) {
goto fail;
}
// Resolve prev_ frame resources
for (int i = 0; i < newpipe->resources_count; ++i) {
const vk_meatpipe_resource_t *mr = newpipe->resources + i;
if (mr->prev_frame_index <= 0)
continue;
ASSERT(mr->prev_frame_index < newpipe->resources_count);
const int index = findResource(mr->name);
ASSERT(index >= 0);
const vk_meatpipe_resource_t *pr = newpipe->resources + (mr->prev_frame_index - 1);
const int dest_index = findResource(pr->name);
if (dest_index < 0) {
gEngine.Con_Printf(S_ERROR "Couldn't find prev_ resource/slot %s for resource %s\n", pr->name, mr->name);
goto fail;
}
g_rtx.res[index].source_index = dest_index + 1;
}
// Loading successful
// Update refcounts
for (int i = 0; i < newpipe->resources_count; ++i) {