rt: add test previous frame blur
This commit is contained in:
parent
a5abde2162
commit
3a87934415
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue