If the task in on_present() takes long time, game frame buffer will be wrong

  • SYX
  • Topic Author
More
1 year 7 months ago - 1 year 7 months ago #1 by SYX If the task in on_present() takes long time, game frame buffer will be wrong was created by SYX
Hi, 

I create a new Addon to hook present function and modify back buffer. The code looks like below:

static void on_present(reshade::api::command_queue *queue, reshade::api::swapchain *swapchain, const reshade::api::rect *, const reshade::api::rect *, uint32_t, const reshade::api::rect *)
{
    reshade::api::device *const device = queue->get_device();
    reshade::api::resource back_buffer = swapchain->get_current_back_buffer();
    reshade::api::resource_desc desc = device->get_resource_desc(back_buffer);

    reshade::api::command_list *const cmd_list = queue->get_immediate_command_list();
    {
        cmd_list->barrier(back_buffer, reshade::api::resource_usage::present, reshade::api::resource_usage::copy_source);
        cmd_list->barrier(host_resource, reshade::api::resource_usage::cpu_access, reshade::api::resource_usage::copy_dest);
        cmd_list->copy_resource(back_buffer, host_resource);
        cmd_list->barrier(host_resource, reshade::api::resource_usage::copy_dest, reshade::api::resource_usage::cpu_access);
        cmd_list->barrier(back_buffer, reshade::api::resource_usage::copy_source, reshade::api::resource_usage::present);
    }
    queue->flush_immediate_command_list();

    reshade::api::subresource_data host_data;
    device->map_texture_region(host_resource, 0, nullptr, reshade::api::map_access::read_write, &host_data)

    // Modify host_data, a long-time post-process task

  
 device->unmap_texture_region(host_resource, 0);

    //update FB
    reshade::api::command_list *const cmd_list2 = queue->get_immediate_command_list();
    {
        cmd_list2->barrier(host_resource, reshade::api::resource_usage::cpu_access, reshade::api::resource_usage::copy_source);
        cmd_list2->barrier(back_buffer, reshade::api::resource_usage::render_target, reshade::api::resource_usage::copy_dest);
        cmd_list2->copy_resource(host_resource, back_buffer);
        cmd_list2->barrier(host_resource, reshade::api::resource_usage::copy_source, reshade::api::resource_usage::cpu_access);
        cmd_list2->barrier(back_buffer, reshade::api::resource_usage::copy_dest, reshade::api::resource_usage::render_target);
    }
    queue->flush_immediate_command_list();
}

If the post-process code in the red part takes a short time (e.g. < 50ms), everything works well.
But if the post-process code in the red part takes a long time (e.g. > 500ms), the back_buffer will be wrong after several frames. I want to get the back_buffer which is rendered by the game. But in fact, the back_buffer contains the post-processed pixels.

Why this happens? How to avoid it? (I only care about the correctness, and don't care about the speed).
 
Last edit: 1 year 7 months ago by SYX.

Please Log in or Create an account to join the conversation.

  • crosire
More
1 year 7 months ago #2 by crosire Replied by crosire on topic If the task in on_present() takes long time, game frame buffer will be wrong
GPU and CPU run asynchronously from each other. "flush_immediate_command_list" only causes all commands that were queued up on the CPU until that point to be send to the GPU, but the GPU is nowhere near finishing that work by the time the call returns (it likely has not even started it yet in fact).
You will need to synchronize GPU and CPU for what you are trying to do, or else the data you are reading from the host resource is out-of-date. Though be aware that this is going to be EXTREMELY slow (the GPU pipeline is designed to be a fast one way street from CPU to GPU and this breaks that). To do so, insert a "queue->wait_idle()" after copying and flushing, before mapping.

Please Log in or Create an account to join the conversation.

  • SYX
  • Topic Author
More
1 year 7 months ago #3 by SYX Replied by SYX on topic If the task in on_present() takes long time, game frame buffer will be wrong
Thanks crosire, "queue->wait_idle()" works!

Please Log in or Create an account to join the conversation.

We use cookies
We use cookies on our website. Some of them are essential for the operation of the forum. You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.