Giter VIP home page Giter VIP logo

Comments (33)

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024 2

@billhollings After some more testing it definitely is a deadlock of some sort. I now have fences after the vkAcquireNextImageKHR call before submitting and it blocks on the next VkDeviceWaitIdle call. I resized the program after it only submitted around 300 command buffers. (Which I also waited on an it gives consistent results: wait for buffer 0, submit new buffer 0, wait buffer 1, submit new buffer 1 etc.) No matter how long I wait, it keeps stuck.

Also the Metal instruments profiler doesn't show any frames send out after this 'deadlock' either. In fact, the profiler shows that it is correctly waiting and sending frames for each vsync point. However, compared to the cube demo, where it waits on fences before acquiring the image my vkQueueSubmit calls take substantially longer (around 16ms each, which is weird since I only draw a triangle) followed by another small (few nanoseconds during) vkQueueSubmit which comes from MoltenVK itself. (Which the cube demo does not do??) The cube just pushes very short vkQueueSubmit calls and waits for the next interval.
The weird part is that my program still seems to eat a ton of memory that keeps growing.

The timeout parameter of vkAcquireNextImageKHR also seems to be ignored?

All my code works as expected on windows and linux, and doesn't grow in memory usage.
Also, I can't get CLion to debug MoltenVK. Any tips on that?

from moltenvk.

rextimmy avatar rextimmy commented on August 23, 2024 1

@billhollings here is another example if you need it for testing https://github.com/rextimmy/vma_sample_sdl ... everything is self contained, so just fire up cmake on ya mac and it should be good to go. You will see the problem when you either resize the window or quit the app, everything of interest will be in VulkanSample.cpp

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024 1

@Hindrik1997

You can also use to the demo_draw() function in cube.c in the Demos project in MoltenVK, as a template.

This code is intended to be a canonical example of a Vulkan render loop, and is part of the KhronosGroup/Vulkan-LoaderAndValidationLayers repository, which is part of the LunarG SDK.

from moltenvk.

olegyadrov avatar olegyadrov commented on August 23, 2024

I've run into this bug too while I was going through vulkan-tutorial.
Another way to reproduce this is to remove vkQueuePresentKHR call from drawFrame method, then, after you close the window, the app will stuck on vkDeviceWaitIdle call in mainLoop.

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024

I've tried to get VulkanTutorial working by following these instructions, so that I can start to investigate this issue...but I am having trouble getting the tutorial up and running. I am encountering a couple of runtime errors:

  • validation layers requested, but not available!, which I can bypass in 15_hello_triangle.cpp by setting enableValidationLayers to false.
  • failed to create window surface!, which seems to be coming from glfwCreateWindowSurface(). I'm not sure how to fix this.

Help with these issues would be appreciated...to allow me to look into this issue.

Thanks.

from moltenvk.

gemorin avatar gemorin commented on August 23, 2024

I think you can reproduce by taking my vulkantest example (since you got it running in #103). It was created using the same tutorial: https://github.com/gemorin/vulkantest

Then apply this patch:

--- a/vulkantest.cpp
+++ b/vulkantest.cpp
@@ -167,8 +167,8 @@ void VulkanApp::run()
 
 void VulkanApp::waitForIdle()
 {
-    for (auto & swpe : swapChain)
-        vkWaitForFences(device, 1, &swpe.fence, VK_TRUE, UINT64_MAX);
+    //for (auto & swpe : swapChain)
+    //    vkWaitForFences(device, 1, &swpe.fence, VK_TRUE, UINT64_MAX);
     vkDeviceWaitIdle(device);
 }
 
@@ -752,7 +752,7 @@ bool VulkanApp::createRenderPass()
     VkRenderPassCreateInfo renderPassInfo = {};
     renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
 #ifdef MSAA
-    renderPassInfo.attachmentCount = 2;
+    renderPassInfo.attachmentCount = 1;
 #else
     renderPassInfo.attachmentCount = 1;
 #endif
@@ -1055,8 +1055,7 @@ bool VulkanApp::renderFrame(uint32_t renderCount)
     // Draw
     const uint32_t idx = renderCount % swapChain.size();
 
-    vkWaitForFences(device, 1, &swapChain[idx].fence, VK_TRUE, UINT64_MAX);
-    vkResetFences(device, 1, &swapChain[idx].fence);
+    //vkWaitForFences(device, 1, &swapChain[idx].fence, VK_TRUE, UINT64_MAX);
 
     VkResult vkRet;
     uint32_t imageIndex;
@@ -1068,6 +1067,8 @@ bool VulkanApp::renderFrame(uint32_t renderCount)
         printf("vkAcquireNextImageKHR returned %d\n", vkRet);
     }
 
+    //vkResetFences(device, 1, &swapChain[idx].fence);
+
     VkSubmitInfo submitInfo = {};
     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
 
@@ -1084,7 +1085,7 @@ bool VulkanApp::renderFrame(uint32_t renderCount)
     submitInfo.signalSemaphoreCount = 1;
     submitInfo.pSignalSemaphores = signalSemaphores;
 
-    vkRet = vkQueueSubmit(graphicsQueue, 1, &submitInfo, swapChain[idx].fence);
+    vkRet = vkQueueSubmit(graphicsQueue, 1, &submitInfo, nullptr); //swapChain[idx].fence);
     if (vkRet != VK_SUCCESS) {
         printf("vkQueueSubmit failed with %d\n", vkRet);
         return false;

When you run, resize the window like @Hindrik1997 said and the program deadlocks

* thread #1: tid = 0x25b44, 0x00007fff6afc0a1e libsystem_kernel.dylib`__psynch_cvwait + 10, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  thread #2: tid = 0x25b7b, 0x00007fff6afc1292 libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #3: tid = 0x25b7c, 0x00007fff6afc1292 libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #5: tid = 0x25b8f, 0x00007fff6afb720a libsystem_kernel.dylib`mach_msg_trap + 10, name = 'com.apple.NSEventThread'
  thread #7: tid = 0x25ba6, 0x00007fff6afb725e libsystem_kernel.dylib`semaphore_timedwait_trap + 10, queue = 'MoltenVKDispatchQueue--1555659392-0-1.0'
  thread #8: tid = 0x25ba7, 0x00007fff6afc1292 libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #10: tid = 0x25ba9, 0x00007fff6afc1292 libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #13: tid = 0x25bac, 0x00007fff6afc1292 libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #16: tid = 0x25baf, 0x00007fff6afc1292 libsystem_kernel.dylib`__workq_kernreturn + 10
  thread #18: tid = 0x25bb1, 0x0000000000000000

 thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
  * frame #0: 0x00007fff6afc0a1e libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00007fff6b189589 libsystem_pthread.dylib`_pthread_cond_wait + 732
    frame #2: 0x00007fff68dcecb0 libc++.1.dylib`std::__1::condition_variable::wait(std::__1::unique_lock<std::__1::mutex>&) + 18
    frame #3: 0x000000010a0452db libMoltenVK.dylib`MVKSemaphore::wait() + 75
    frame #4: 0x000000010a031f6e libMoltenVK.dylib`MVKQueue::waitIdle(MVKCommandUse) + 478
    frame #5: 0x000000010a02bfbd libMoltenVK.dylib`MVKDevice::waitIdle() + 45
    frame #6: 0x0000000100118eb7 libvulkan.1.dylib`vkDeviceWaitIdle(device=0x00000001007598f0) at trampoline.c:1026

  * frame #0: 0x00007fff6afb725e libsystem_kernel.dylib`semaphore_timedwait_trap + 10
    frame #1: 0x00007fff6ae4699f libdispatch.dylib`_dispatch_sema4_timedwait + 72
    frame #2: 0x00007fff6ae3e99e libdispatch.dylib`_dispatch_semaphore_wait_slow + 58
    frame #3: 0x00007fff4dfdc4a7 QuartzCore`-[CAMetalLayer nextDrawable] + 891
    frame #4: 0x000000010a03e93a libMoltenVK.dylib`MVKSwapchain::getNextCAMetalDrawable() + 42
    frame #5: 0x000000010a017856 libMoltenVK.dylib`MVKSwapchainImage::newMTLTexture() + 54
    frame #6: 0x000000010a0168ee libMoltenVK.dylib`MVKImageView::getMTLTexture() + 174
    frame #7: 0x000000010a016935 libMoltenVK.dylib`MVKImageView::populateMTLRenderPassAttachmentDescriptorResolve(MTLRenderPassAttachmentDescriptor*) + 21
    frame #8: 0x000000010a0340cf libMoltenVK.dylib`MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*, MVKFramebuffer*, std::__1::vector<VkClearValue, std::__1::allocator<VkClearValue> >&, bool) + 255
    frame #9: 0x000000010a02355a libMoltenVK.dylib`MVKCommandEncoder::beginMetalRenderPass() + 202

HTH

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024

@gemorin Thanks for the suggestion.

However...I am not able to replicate the issue using that approach. After applying the patch to vulkantest.cpp...and even after commenting out vkDeviceWaitIdle(), I am able to resize the window like a madman without encountering any issues. All seems to be working.

Can you reconfirm with latest MoltenVK, please?

Any idea why I am able to run vulkantest...but not 15_hello_triangle.cpp ?

from moltenvk.

gemorin avatar gemorin commented on August 23, 2024

@billhollings I have not tried to reproduce with the latest Molten VK (I am assuming you mean the current HEAD of master branch). I am going to try that and let you know.

But to be 100% clear though, you do not want to comment out the vkDeviceWaitIdle(device); in waitIdle() since this is where it's deadlocking.

No idea why 15_hello_triangle.cpp is not working for you. It does work for me completely unmodified with a similar Makefile as the one I use for vulkantest (so using custom HEAD glfw 3.3 etc) and setting VK_ICD_FILENAMES and VK_LAYER_PATH properly

from moltenvk.

gemorin avatar gemorin commented on August 23, 2024

@billhollings I have just tried with the MoltenVK HEAD and I can still reproduce the problem with vulktantest+patch.

from moltenvk.

gemorin avatar gemorin commented on August 23, 2024

@billhollings fwiw the issue is still present even after your last commits (MoltenVK 1.0.2)

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

@billhollings If you need a source package to reproduce the problem I can share some code with you if you want? The only thing required with it is to use homebrew to checkout the latest GLFW (HEAD), and install the Vulkan SDK.

@gemorin How exactly do you compile MoltenVK? I've been trying to get it working in Xcode but can't find any output binaries I can link to? (I'm using CLion + CMake)

from moltenvk.

gemorin avatar gemorin commented on August 23, 2024

@Hindrik1997 I build it in a Vulkan-LoaderAndValidationLayers clone (so I can use the validation layers): https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers
The build process of Vulkan-LoaderAndValidationLayers will pull MoltenVK and build it.

Note though that their update_external_sources.sh needs an update to call the new fetchDependencies instead of makeAll:

--- a/update_external_sources.sh
+++ b/update_external_sources.sh
@@ -72,11 +72,12 @@ function update_moltenvk () {
 function build_moltenvk () {
    echo "Building ${BASEDIR}/MoltenVK"
    cd "${BASEDIR}"/MoltenVK/External
-   ./makeAll
+   #./makeAll
+   ./fetchDependencies
    cd "${BASEDIR}"/MoltenVK
    xcodebuild -project MoltenVKPackaging.xcodeproj \
-    GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS MVK_LOGGING_ENABLED=0' \
-    -scheme "MoltenVK (Release)" build
+    GCC_PREPROCESSOR_DEFINITIONS='$GCC_PREPROCESSOR_DEFINITIONS MVK_LOGGING_ENABLED=1' \
+    -scheme "MoltenVK (Debug)" build
 }
 
 INCLUDE_GLSLANG=false

Note that the 2nd change is only because I want to build the Debug version of MoltenVK and not necessary in general (I was just too lazy to edit the patch)

Then I just link against libvulkan produced in $(VULKANDIR)/build/loader: https://github.com/gemorin/vulkantest/blob/master/Makefile (VULKANDIR is the location of my Vulkan-LoaderAndValidationLayers clone)

Then I set in my environment VK_ICD_FILENAMES to $(VULKANDIR)/external/MoltenVK/Package/Debug/MoltenVK/macOS/MoltenVK_icd.json and VK_LAYER_PATHto $(VULKANDIR)/build/layers. This is how libvulkan finds the libMoltenVK produced during the build process.

Replace Debug with Release in the variables above if you did not patch update_external_sources.sh to do a Debug build.

When I want to update MoltenVK, I simply go to external/MoltenVK in my clone, pull the code then run the xcodebuild command directly.

If you want to point libvulkan to a completely different libMoltenVK, it should be enough to put the right path in the VK_ICD_FILENAMES json. But I have not tried it.

from moltenvk.

karl-lunarg avatar karl-lunarg commented on August 23, 2024

Note though that their update_external_sources.sh needs an update to call the new fetchDependencies instead of makeAll:

Yes, the entire handling of Externals in this repo has been changing a lot lately.
(It changed again since you posted this - fetchDependencies is now in the root dir.)
I'm working with @billhollings to finish this up and I will update the Vulkan-LoaderAndValidationLayers when it is ready.

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024

@Hindrik1997 @olegyadrov @gemorin

I've replicated what you are all seeing now (thanks @gemorin).

The vkDeviceWaitIdle() is not actually deadlocking or blocking forever.

What is happening is that your apps are using very tight runloops and are not using fences or calls to queue idle to meter how fast the CPU cycles through the run loop. The result is that tens of thousands of command buffer and presentation submits are piling up on the queue. You can watch the app memory grow as this happens. The CPU is submitting them way to fast for the GPU to drain them because the GPU itself is metered by the swapchain image acquire and present semaphores.

Semaphores are used for syncing tasks running on the GPU. They do not block or meter the CPU. Typically you would use fences to meter the CPU...although simple apps sometimes use the cruder vkQueueWaitIdle().

In your app...when the window size event occurs...the vkDeviceWaitIdle() waits for the queue to drain (as it should). It does actually come back once the queue has drained...but it can take minutes for that to happen. In the meantime...you can see the periodic performance logging that indicates that rendering is still occurring.

The Vulkan spec is somewhat vague on whether vkAcquireNextImageKHR() should block until an image is completely free to be rendered to...and the conditions under which blocking will occur are not well defined in the spec. But the key guideline in in the spec is (Sec 30.8):

Applications should not rely on vkAcquireNextImageKHR blocking in order to meter their rendering speed, as the various conditions described above may lead to the call returning early. Instead, applications can use fence to meter their frame generation work to match the presentation rate.

So...you should use fences before the call to vkAcquireNextImageKHR()...or before you submit command buffers at least. Have a look at the demo_draw() function in the cube.c demo in the latest version of MoltenVK for an example of that design pattern.

Is this app working with other versions of Vulkan drivers?

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

@billhollings The app does in fact work with other vulkan drivers.

However, I was under the assumption that the vkAqcuireNextImageKHR() call would simply block, but this is apparently not the case here if I only use a semaphore.

This would mean I would need to keep an array of fences per swapchain image which need to be checked right before submitting the command buffer for the frame you are sending to, or in the vkAqcuireNextImageKHR() call?

from moltenvk.

karl-lunarg avatar karl-lunarg commented on August 23, 2024

You might look at the usage of the fences member in the demo struct in cube.c.
It uses an array of fences which are checked before acquiring the next image.
This program is set up to have no more than FRAME_LAG queued submits and presents.
It supplies a fence on each queue submit and then waits on that fence before calling vkAcquireNextImageKHR the next time the buffer is used for a new frame.

from moltenvk.

rextimmy avatar rextimmy commented on August 23, 2024

I am seeing the exact same thing with my app when calling vkDeviceWaitIdle(). The code runs perfectly fine on window using nvidia & also intel drivers, works ok on linux using nvidia drivers. I tested it with a rendering loop pretty much identical to this https://github.com/SaschaWillems/Vulkan/blob/master/examples/triangle/triangle.cpp#L330-L359. I am using LunarG macOS SDK 1.0.69, linked against vulkan-1 loader library.

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

@billhollings I have implemented a set of fences for each swapchain image which get signaled by the corresponding queue submit call. My code is now practically identical to the code @rextimmy has. (So basically identical to Sascha Willems' code) I also wait on my fence right after the vkAcquireNextImageKHR call, since there is no way to know on which fence I have to wait for otherwise.

The memory now grows much less quicker, but the problem still persists. I verified my fences are being waited on, and this seemed to be okay. The correct fence was signaled and waited on, yet somehow there still were too many submissions getting my app stuck.

EDIT: I implemented fences according to this Khronos presentation:
https://www.khronos.org/assets/uploads/developers/library/2016-vulkan-devday-uk/7-Keeping-your-GPU-fed.pdf

It doesn't work. It keeps submitting and keeps getting stuck.
Also adding a fence on vkAcquireNextImageKHR and waiting on it in the next line does nothing.

from moltenvk.

rextimmy avatar rextimmy commented on August 23, 2024

I forgot to mention in my other post, i also ported the AMD GPUOpen VMA sample to use glfw and tested it with the mac lunarg sdk, the exact same thing happens with vkDeviceWaitIdle(), this is the rendering loop for it https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/blob/master/src/VulkanSample.cpp#L1524

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024

@Hindrik1997 @rextimmy

Okay...let's see if we can get to the bottom of this.

Is it possible for one of you to ZIP up your project and post it somewhere so I can download it and test it out directly, please?

I have GLFW and the SDK...so I just need your app content.

Thanks.

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

@billhollings I added you as contributor to a clone of my repository.

Yesterday I managed to get a bit of code working based on the cube.c example, which doesn't deadlock. However, it seems to me that this only works when present mode is FIFO_KHR, since only then the ordering of swapchain images is guaranteed. This is commit 48719700329284245cc9dddaa0c0295190808274.

My fence based code as I would expect it to work is commit e605b2fe73ec25d5e872ae33fd35cb48663c4281. This one simply waits for the previous operations for the specific frame to finish executing.

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024

@Hindrik1997

Thanks.

I want to make sure I get a build that hits the issue. If I understand your comments above correctly...commit 48719700329284245cc9dddaa0c0295190808274 works as expected...but commit e605b2fe73ec25d5e872ae33fd35cb48663c4281 hits the issue you have been describing?

Edit: And what is your repo?

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

@billhollings That is correct. The commit messages will tell you which one to pick too. You can just checkout the appropriate commit.
The repository is called VKRenderer-clone. It should be in your Github invitations.

Edit: The code you are probably looking for is inside Swapchain.cpp line 328 and VulkanRenderer.cpp line 187.

from moltenvk.

smellslikedonkey avatar smellslikedonkey commented on August 23, 2024

For what it's worth, I'm also running into this in a fairly large project. vkDeviceWaitIdle is hanging forever.

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024

@Hindrik1997 @rextimmy @smellslikedonkey

This is fixed in PR #131. Please see if it resolves your issues.

I have tested it against @rextimmy 's code...and @Hindrik1997 's code seems to have a structure that would cause it as well.

The deadlock arose because a single semaphore is being used for all swapchain images:

VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);

As discussed above...by design vkAcquireNextImageKHR() does not block on the semaphore. The semaphore is passed to vkQueueSubmit(), where the GPU waits for the semaphore to complete before committing the submits.

Allowing the driver to execute vkQueueSubmit() allows a lot of processing to occur before the surface is actually available. As soon as the surface is available...the GPU can start rendering to it. If the purpose of the semaphore was to block on vkAcquireNextImageKHR(), then there would be no point in passing it to vkQueueSubmit().

What is happening then is that, again, by design, the rendering loops are allowed to overlap...and the 'vkAcquireNextImageKHR()' will grab the semaphore before the previous frame is done with it. The effect is that the semaphore is being singled by overlapping frames...and it gets out of sync.

Specifically...because the CPU and GPU run independently...it is possible for the semaphore to be signaled twice before a single vkQueueSubmit() is finished. That works...as long as the render loop continues and signals keep coming in. But once the loop is broken by the vkDeviceWaitIdle()/vkQueueWaitIdle(), the final vkQueueSubmit() has no unsignaled semaphore remaining to allow it to proceed. The vkQueueSubmit() never finishes...and the vkDeviceWaitIdle()/vkQueueWaitIdle() waits in vain forever.

To avoid the deadlock in MoltenVK...I inserted a work-around to force a second singling of the last semaphore that was grabbed while an image was available and not already blocked by a semaphore.

In Section 6.4.2, the Vulkan spec's perspective on semaphore signaling is:

Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore. If two operations are separately specified to wait for the same semaphore, and there are no other execution dependencies between those operations, behaviour is undefined. An execution dependency must be present that guarantees that the semaphore unsignal operation for the first of those waits, happens-before the semaphore is signalled again, and before the second unsignal operation. Semaphore waits and signals should thus occur in discrete 1:1 pairs.

Typically...this is enforced by having a different semaphore for each swap chain image...either through an indexed array of semaphores...or by creating a new semaphore on each iteration of the render loop. For example...the following code comes from cube.c in the Vulkan SDK (also in MoltenVK demos):

    err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX,
                                      demo->image_acquired_semaphores[demo->frame_index],
                                      VK_NULL_HANDLE, &demo->current_buffer);

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

@billhollings Awesome! It works now. Before I close the issue though, this means that except fences, we also have to keep a circular buffer of semaphores around?

The problem I'm seeing with that is that when you use MAILBOX_KHR, it is possible for the swapchain to return the same image multiple times after each other, how can we know which semaphore/fence to use? Because if we use a circular buffer, it will block on the previous frames, whereas with mailbox it is supposed to keep going and going while presenting a third image. This would cause a problem because it would block on the presenting image because there is no way to determine which semaphore to use before calling vkAcquireNextImageKHR. The cube.c demo just hard codes FIFO_KHR, in which case it indeed is possible to use a circular buffer, because it's guaranteed to present in order. Any ideas?

from moltenvk.

rextimmy avatar rextimmy commented on August 23, 2024

@billhollings i can confirm that last PR does fix the problem, i should also point out that changing my code to use your recommendation of separate semaphores per swapchain image also fixes the problem without any changes to the moltenvk lib.

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

@rextimmy How exactly did you implement seperate semaphores per image?

from moltenvk.

rextimmy avatar rextimmy commented on August 23, 2024

@Hindrik1997 some pseudo code https://hastebin.com/nekofefutu.cpp

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024

@Hindrik1997 @rextimmy Glad the suggestions (and MoltenVK fix) helped with the problem.

@Hindrik1997 For now...MoltenVK only supports VK_PRESENT_MODE_FIFO_KHR. We can look at supporting additional presentation modes if needed.

What is the reason for wanting VK_PRESENT_MODE_MAILBOX_KHR?

Edit: But when using VK_PRESENT_MODE_MAILBOX_KHR...it would likely not change the order in which images are returned to the app...so the same indexed semaphore mechanism should work.

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

@billhollings It's not that I need it, but I prefer it over FIFO, especially on windows/linux, since it allows me to let the game keep updating while still keeping V-Sync enabled. In FIFO image ordering is guaranteed indeed, but is it in MAILBOX?

Isn't the whole point of MAILBOX that it keeps a single frame presenting, and swaps 2 other frames continously until it reaches another V-Sync point, swaps the most recent image in the queue, and puts that as the presenting one? So then the ordering would change, right?

Say image 0 is currently presenting, image 1 is in the queue, and the app gets image 2 and renders to it. After it is done, image 0 is still waiting for V-Sync, so it replaces image 1 with image 2, and returns image 1 to render to. This keeps going until image 0 is done. It takes the current image in the queue, say image 1, and presents it. The app pushes the image it was working on, image 2, and puts it in the queue. The next image it gets is image 0. Now the ordering is changed and a circular buffer would break, since it would wait on the wrong image. Right?

from moltenvk.

billhollings avatar billhollings commented on August 23, 2024

@Hindrik1997

Hmmm...I don't necessarily think that would cause a problem.

With reference to the demo_draw() function in cube.c mentioned above, the semaphores and fences all operate on a cyclical frame index (a cycle of 3 in your example).

It's the fence's job to ensure that no more than 3 frames worth of command buffers are executing at any one time.

The semaphores and fences will blindly cycle through 0->1->2->0->1->2...but the swapchain images don't necessarily follow the same pattern.

vkAcquireNextImageKHR() associates the image semaphore for the frame with an image from the pool...which the driver selects...and effectively tells the app...I'll signal this frame's semaphore when the swapchain image I'm giving you comes available.

So...the indices might start out lined up...but might not stay that way...and in your example we might see:

frame-0 -> image-0 (presenting)
frame-1 -> image-1 
frame-2 -> image-2 (image 1 freed)
frame-0 -> image-1 (image 2 freed)
frame-1 -> image-2 (image 1 freed)
<vsync> (image 0 freed & image 2 presenting)
frame-2 -> image-1 
frame-0 -> image-0 
frame-1 -> image-1 (image 0 freed)
frame-2 -> image-0 (image 1 freed)

One note about the cube.c implementation. I'm not sure that the swapchain_image_resources should have been associated with the swapchain index. It seems to me that it should be called frame_image_resources and associated with the frame index.

from moltenvk.

HindrikStegenga avatar HindrikStegenga commented on August 23, 2024

I finally managed to get it all working correctly. Thank you very much!

from moltenvk.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.