Blinking/flickering object during transformation using uniform buffer

Hi All,

I have some issue when I transform (e.g. rotate) object (e.g. cube) in the scene using uniform MVP matrix. Rotation is not linear and edges of object are flickering.

  1. I use 3 swapchain images/framebuffers/depth buffers, one command buffer per each framebuffer.
  2. I use one uniform buffer for all 3 command buffers
  3. Present mode is VK_PRESENT_MODE_IMMEDIATE_KHR
  4. Uniform buffer is updated asynch from submitting/presenting
  5. Command buffers are prepared only once per start program, because any data inside is constant (e.g. descriptor set to uniform buffer)
  6. uniform buffer is host visible and coherent, mapped during creation
  7. main drawing loop executes std operations
    a) vkAcquireNextImageKHR
    b) vkWaitForFences for swapchain image
    c) vkResetFences (b) fence
    d) vkWaitForFences for previous submitting
    e) vkResetFences (d) fence
    f) vkQueueSubmit with previously compilled cmd buffer
    g) vkQueuePresentKHR

Could someone know the reason of flickering?

Thanks!

[QUOTE=JiuShei;43784]Hi All,

I have some issue when I transform (e.g. rotate) object (e.g. cube) in the scene using uniform MVP matrix. Rotation is not linear and edges of object are flickering.

  1. I use one uniform buffer for all 3 command buffers
  2. Uniform buffer is updated asynch from submitting/presenting
  3. Command buffers are prepared only once per start program, because any data inside is constant (e.g. descriptor set to uniform buffer)

[/QUOTE]

Hey!

The command buffer may be constant, but your data is in fact not.

From what I can tell, you may be updating the data in a buffer that can be in use by one of your command buffers? This is not something you should do and could explain that kind of behaviour.

If you update the uniform buffer contents asynchronously you also need to synchronize between the rendering and the buffer writes, at least make sure the data will not be used while you write to it.

Typically, if you want to update the data every frame, you might want to have separate buffer memory for every frame you can have in flight. That way, you will make sure you will not update memory that is in use by the GPU.

Buxxy11, thanks.

I added the following synchronization:

  1. pause drawing thread (drawFrame call) by setting std::atomic draw_paused=true
  2. rotateDeltaAngle(glm::vec3(0.f, 30.f, 0.f))
  3. unpause drawing thread (draw_paused=false)

I added in drawing loop following instructions
a) start of loop: if (draw_paused) return;
b) end of loop after vkQueuePresentKHR: vkQueueWaitIdle(present_queue); (present_queue == graphics queue in my case)

Additional sync:

  1. Drawing loop uses draw_ready_mutex that locks on start of loop and unlocks in the end of loop
  2. draw_paused is set after draw_ready_mutex lock. So when I set pause I am sure that drawing loop has finished

I checked call sequence in the debug mode and made sure that drawFrame (drawing loop) is not called during rotateDeltaAngle call.

But I see the same flickering!

Also I added additional synchronization and get the same result - not linear shifts and the same flickering.

  1. added the following in command buffer

vkBeginCommandBuffer…

vkCmdWaitEvents(cmd_buf, 1, &m_data_update_event[image_number],
VK_PIPELINE_STAGE_HOST_BIT,
VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_HOST_BIT,
0, nullptr,
0, nullptr,
0, nullptr);

vkCmdSetEvent(cmd_buf, m_draw_progress_event[image_number], 
	VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);

vkCmdBeginRenderPass…
…
vkCmdEndRenderPass…

vkCmdResetEvent(cmd_buf, m_draw_progress_event[image_number], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);

  1. before update uniform buffer I do
    m_is_draw_paused = true;
    for (uint32_t i = 0; i < m_choosen_swap_chain_details.imagesCount; i++)
    {
    vkResetEvent(m_logical_device, m_data_update_event[i]);
    while (vkGetEventStatus(m_logical_device, m_draw_progress_event[i]) == VK_EVENT_SET)
    {
    boost::this_thread::sleep_for(boost::chrono::milliseconds(1));
    }
    }

  2. update uniform buffer with new MVP matrix (uniform is VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, VK_SHARING_MODE_EXCLUSIVE)

  3. allow rendering

for (uint32_t i = 0; i < m_choosen_swap_chain_details.imagesCount; i++)
{
vkSetEvent(m_logical_device, m_data_update_event[i]);
}

So GPU should not use uniform memory when I update uniform data and I update data for all uniform buffers for each swapchain image.

I am fully confused how to correctly synchronize uniform data update with GPU execution and different swapchain images.

May be Windows caches uniform buffer memory?

If you always update after waiting for the device to be idle and before you submit the next frame then there is no possibility for a buffer update issue like that.

You have no warning or error messages from the validation layers?

Are you sure you are setting the correct data on your uniform buffer? What happens if you change it on a button press instead of every frame?

You can also try to debug with an application like RenderDoc to see if the uniform buffer that is being used is is correct.

1 Like

[QUOTE=Buxxy11;43799]If you always update after waiting for the device to be idle and before you submit the next frame then there is no possibility for a buffer update issue like that.
[/QUOTE]
I have tried debug, analyse, different threads sync. methods. I cannot find the reason of this behaviour.
My drawing loop executes in separate thread and I process window system events in main thread. (I have also tried to process rotation in one more separate thread that updates rotation angle by one degree with 10HZ speed). But as I mentioned above the command buffer is compilled only once in start and it is static further. Drawing loop executes standard pool of operations as I describe in first post.

Actually I see 2 issues

  1. flickering - it seems that smapchain images presents with different transformation angle +1degree, after that -1 degree, after that +1 degree (but data is the same for all uniform buffers/swapchain images)
  2. not linear rotation - rotation angles are different time depending - it seems that some frames don’t use updated uniform data

I use LunarG standard validation layer and warnings are absent (they occured during development but fixed)

During button press I increment Y angle by 1 degree after that call glm::rotate with new angle m_rot_prop.rotation = glm::rotate(glm::dmat4(1.0), glm::radians(angle.y), glm::dvec3(0., 1.0, 0.));
Calculate new model m_model = glm::mat4(m_rot_prop.rotation)m_trans_prop.transformm_scale_prop.scale;
After that this data copies by memcpy on uniform buffer pointer.

On one button press i.e. one degree change and one buffer update I see normal transformation on one degree without any strange behaviour.

I have tried but I don’t know how to capture the frames when flickering occurs

I added output in uniform update method and drawing loop. “drawFrame” in drawing loop. “start update scene” before uniform memory update, “end update scene” after uniform memory update. So “drawFrame” is not called before uniform update finished

start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene
drawFrame
drawFrame
start update scene
end update scene
start update scene
end update scene

Also atrtupdate wait I described in previous posts event in command buffer
while (vkGetEventStatus(m_logical_device, m_draw_progress_event[i]) == VK_EVENT_SET)
{
boost::this_thread::sleep_for(boost::chrono::milli seconds(1));
}

So uniform update starts after GPU had used it.

http://skyboy.ddns.net/flickering.webm

I combined window system event handler and drawing loop in one main thread and it didn’t resolve issue. I attached video with flickering. Looks only one edges flickering. Big shifts are absents (it is video issue)

example on intel uhd630 https://drive.google.com/open?id=1L1Dx-LUdTdqvCQ23-o-vlI_yQK_t7l2_
msaa 4
anisotrope 8x
sample shading 0.4

the latest update video https://drive.google.com/open?id=1J7KaVd2YTVUZEW1wviguf1Ogd58C7Vwb. I see 4Hz non linear shifts. Rotation update is 66Hz, FPS is 66 Hz

Try to record in 60 FPS. The Phi effect is weak. Your objects are very contrasting, and the displacement of the objects are large enough. Which can look like the edges are flickering.

Otherwisely the last video seems alright enough if viewed frame by frame.

Your log seems weird. Draws somehow happens in twos. And sometimes you update twice.

What I written on SO applies. Avoid using Events. Especially do not spin on them on host. They are not designed to be waited on on host. And avoid wait-before-signal situations (at least do not introduce that until you are in the optimization phase).

For simplicity just update by constant each frame (and get rid of keyboard input). That will eliminate one potential source of the problem.

>> Try to record in 60 FPS. The Phi effect is weak

I use embedded MS Windows recorder. It doesn’t record 60fps

>> Your log seems weird. Draws somehow happens in twos.And sometimes you update twice.

It was one from many attempts. It seems that printf did output randomly when used some threads.

>> Avoid using Events.

Currently I reproduce the following
a) deleted all events waiting, signaling. Events are fully excluded from cmd buffers.
b) added drawing and rotating in one thread. Excluded any keyboard events.

the thread loop is:

if ((current_time - previous_time) >= expected_cycle_delay)
{
previous_time = current_time;
m_selected_scene->rotateStepAngle(XVIEW::Axis::Y, XVIEW::RotationDirection::CLOCKWISE);
m_vk->nextFrame();
current_time2 = boost::chrono::high_resolution_clock::now();
printf(">> %lld
", (current_time2 - previous_time2).count() / 1’000’000);
previous_time2 = current_time2;
}

and nextFrame() wait queue idle ate the end

vkQueueWaitIdle(m_queue);

I vage got the following timings in the console

>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 15
>> 14
>> 15
>> 15
>> 14
>> 15
>> 15
>> 14
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 15
>> 14
>> 15
>> 14
>> 14
>> 14
>> 15
>> 15
>> 14
>> 15
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 15
>> 15
>> 17
>> 12
>> 14
>> 15
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 14
>> 15
>> 15
>> 15
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 15
>> 14
>> 14
>> 15
>> 15
>> 14
>> 15
>> 14
>> 15
>> 15
>> 15
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 15
>> 15
>> 14
>> 15
>> 14
>> 15
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 14
>> 14
>> 14
>> 15
>> 14
>> 14
>> 14
>> 15
>> 15
>> 15
>> 14
>> 14
>> 15
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 14
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 15
>> 15
>> 14
>> 15
>> 15
>> 14
>> 15
>> 14
>> 15
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 15
>> 14
>> 14
>> 15
>> 15
>> 14
>> 14
>> 15
>> 14
>> 15
>> 15
>> 14
>> 14
>> 15
>> 15
>> 14
>> 14

So the all timings are 15+/-1ms. But I got the same 4Hz big shifts

I use embedded MS Windows recorder. It doesn’t record 60fps

Weird, it does offer 30 or 60 to me in the Settings.

Might be worth trying to disable the MS Game Panel, as well as other things that may interfere (e.g. AV, and also the Steam Implicit Layer is quite notorious). If you are using MSVS might be worth pausing the exe (or opening minidump), and checking which dlls are loaded – there should ideally not be any parasitic ones like the Steam layer, or mouse software, or notebook keys overlay and such. And I am assuming this is in Release build without Validation Layers.

BTW, does vkcube behave the same way?

Well, I am outa ideas. You would need to provide minimal example…

krOoze, thanks for your help! It is very hard to find any vulkan info/support now

>>Weird, it does offer 30 or 60 to me in the Settings.

Yes, I found this option and changed to 60fps. New video for “Release build without Validation Layers”
https://drive.google.com/open?id=12ushBzi880PioaqlTB2MHEyA8E93c8ZG (Video is played normal locally, web browser plays it incorrectly)

>> Might be worth trying to disable the MS Game Panel

I am going to try

>>as well as other things that may interfere (e.g. AV, and also the Steam Implicit Layer is quite notorious). If you are using MSVS might be worth pausing the exe (or opening minidump), and checking which dlls are loaded – there should ideally not be any parasitic ones like the Steam layer, or mouse software, or notebook keys overlay and such. And I am assuming this is in Release build without Validation Layers.

The modules tab the MSVC release build is paused
https://drive.google.com/open?id=1T9FJE8BocUuZcn9C6bMvMpXlt3CI8H-M
>> BTW, does vkcube behave the same way?
It rotates correctly
https://drive.google.com/open?id=1jhkikYK4WHULVbZXtQ7XEVSYAyHavEj1

May be I have errors in the shaders?

vertex shader:

https://drive.google.com/open?id=1q0FQ5Iwz2stdGhdsiEiYg--8DE9MTK5t

fragment shader:

https://drive.google.com/open?id=19UjSXgN82bAZWV5NwdZqgTwnRMvEA4ib