New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Framerate is always twice than the monitor refresh #1407
Comments
I'm getting an strange behaviour of vkAcquireNextImageKHR, the pImageIndex that it returns has this shape Does this help? |
I see this same behavior in my toy engine. I have a very basic setup with standard CPU-GPU frame synchronization and default to 2 swap images for IMMEDIATE and 3 for FIFO presentation. I realize that the Vulkan spec states that the indices returned by acquireNextImage don't necessarily have any relationship, but I wouldn't expect to see repeats like 0, 0, 1, 1, etc. when all my CPU+GPU work takes much less than 16ms. Some basic debugging I did shows somewhat strange behavior:
In all the above cases I spend the majority of my time waiting (on the CPU) on my call to vkQueueSubmit, and not vkAcquireNextImage or vkQueuePresent. It's tough to verify what's going on on the GPU since timestamps don't seem to work in MoltenVK. My current setup:
|
I'm using SDL2 and I get this exact behaviour as @Valakor
Setup:
|
I can reproduce his issue as well. My code for frame synchronization is essentially the same as the one from vulkan-tutorial.com. It seems that MVK returns weird image ordering on my system as well (MBP 2019 15"), where it returns the same image twice after each other. It also does 120 frames a second whereas it should be 60. |
I see the exact same behavior in my engine as well as @ellipticaldoor and @Valakor. My setup: MacBook Air M1 |
Maybe this could be related but also VK_PRESENT_MODE_IMMEDIATE_KHR gets capped around 200 fps. Even if I don't do any draw call. |
@ellipticaldoor I just tested this on my implementation, and for me immediate mode doesn't cap it, but rather it's véry dependent on the window size I render to. Rendering 800x600 or some small resolution and i get 2K+ whereas if I maximize my window, and resize the swapchain accordingly, I get only 200-300 fps. This is without drawcalls. There seems to be no big difference between using igpu or dedicated gpu. Also, minimizing the window causes my framerate to jitter a lot. Oftentimes getting the same 200-300 fps or however much I got before depending on window size, and then suddenly drop to 2 fps or something like that. I doubt that has something to do with this issue of 120fps cap, but I thought i'd mention it. |
I tried different window sizes with For reference this is how I'm waiting for the render calls void VulkanFrame::draw()
{
VK_CHECK(
vkWaitForFences(vk.instance._device, 1, &_renderFence, true, UINT64_MAX));
VK_CHECK(vkResetFences(vk.instance._device, 1, &_renderFence));
uint32_t swapchainImageIndex;
VK_CHECK(vkAcquireNextImageKHR(
vk.instance._device,
vk.swapchain._swapchain,
UINT64_MAX,
_presentSemaphore,
nullptr,
&swapchainImageIndex));
VK_CHECK(vkResetCommandBuffer(_mainCommandBuffer, 0));
VkCommandBufferBeginInfo cmdBeginInfo = {};
cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
VK_CHECK(vkBeginCommandBuffer(_mainCommandBuffer, &cmdBeginInfo));
VkClearValue clearValue;
clearValue.color = {{0.0f, 0.0f, 0.0f, 1.0f}};
VkRenderPassBeginInfo rpInfo = {};
rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
rpInfo.renderPass = vk.renderPass._renderPass;
rpInfo.renderArea.offset.x = 0;
rpInfo.renderArea.offset.y = 0;
rpInfo.renderArea.extent = vk.swapchain._extent;
rpInfo.framebuffer = vk.renderPass._framebuffers[swapchainImageIndex];
rpInfo.clearValueCount = 1;
rpInfo.pClearValues = &clearValue;
vkCmdBeginRenderPass(_mainCommandBuffer, &rpInfo, VK_SUBPASS_CONTENTS_INLINE);
commands(_mainCommandBuffer);
vkCmdEndRenderPass(_mainCommandBuffer);
VK_CHECK(vkEndCommandBuffer(_mainCommandBuffer));
VkSubmitInfo submit = {};
submit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit.commandBufferCount = 1;
submit.pCommandBuffers = &_mainCommandBuffer;
VkPipelineStageFlags waitStage =
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit.pWaitDstStageMask = &waitStage;
submit.waitSemaphoreCount = 1;
submit.pWaitSemaphores = &_presentSemaphore;
submit.signalSemaphoreCount = 1;
submit.pSignalSemaphores = &_renderSemaphore;
submit.commandBufferCount = 1;
submit.pCommandBuffers = &_mainCommandBuffer;
VK_CHECK(vkQueueSubmit(vk.instance._graphicsQueue, 1, &submit, _renderFence));
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.pSwapchains = &vk.swapchain._swapchain;
presentInfo.swapchainCount = 1;
presentInfo.pWaitSemaphores = &_renderSemaphore;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pImageIndices = &swapchainImageIndex;
VK_CHECK(vkQueuePresentKHR(vk.instance._graphicsQueue, &presentInfo));
} |
It seems that the window size does not affect the frame rate on M1 Macs. Its always around 200-230 in my case. |
I see, maybe macos is doing some clever thing to avoid rendering too much fps? Seems like OpenGL doesn't have this limitation |
Same issue for me! I guess this ~200 FPS cap is due to power consumption. So the GPU doesn't push its limits if not needed. |
@hecaex I doubt that's the reason, as vkAcquireNextImageKHR should not return the same image twice sequentially. unless you work with 1 image or fifo with 2 images. |
@HindrikStegenga I agree with this. But I was talking about the ~200 FPS cap that seem to be related to power consumption. However... Edit: |
PR #1410 should fix this particular issue. |
@billhollings thank you, I just tried latest master and the issue with vkAcquireNextImageKHR it's fixed. Though I still get twice the fps from the refresh of the monitor. I guess this wasn't related to the issue |
I have more findings about this issue. Right now I'm setting an I'm really confused, is this expected? How it's possible that the game is rendering in the screen at 60fps but the game loop is running at 120fps? Anyone has a workaround for this? |
Okay, I just checked my vulkan backend on a windows machine, and it works fine there at 60fps. So I guess this is a bug in MoltenVK |
There is no news about this? I'm very puzzled by this... |
Yea me too. Is there anything we can do to help sorting out this issue? |
fixing this will make my game twice as fast on mac, now I have to run the render loop 2 times more than is needed |
To fix this you should decouple your game logic from the fps to make your game run on any fps rate. |
I already do by using delta time, but still, if I have some heavy cpu task is going to run more than needed increasing the cpu usage |
As a workaround, detect the monitor's refresh rate using system APIs (or SDL) and limit FPS to |
Interestingly on the macOS Ventura beta this issue does not seem to occur |
@char8t thats also my finding. When I tried the first public release of Ventura the issue seemed to be fixed and Vsync was tied to the actual monitor refresh rate. As soon as I reverted back to Monterey the issue of double FPS was present again. |
It looks like this got fixed in Ventura 13.0 |
I completed both tutorials for https://vulkan-tutorial.com/ and https://vkguide.dev/ and their code makes my render loop twice as fast as the monitor refresh rate.
If I'm at 60hz I get 120fps, if I'm at 30hz I get 60fps
I found a solution which is to call the draw function twice... though this seems wasteful.
Has someone else experienced this issue?
What is the code in the draw function to make vulkan to wait for the vsync? https://github.com/vblanco20-1/vulkan-guide/blob/all-chapters/chapter-4/vk_engine.cpp#L92
I tried passing vkWaitForFences twice the timeout but it seems to not be affected by it.
The text was updated successfully, but these errors were encountered: