anv/wsi: Throttle rendering to no more than 2 frames ahead
authorJason Ekstrand <jason.ekstrand@intel.com>
Fri, 11 Mar 2016 02:35:00 +0000 (18:35 -0800)
committerJason Ekstrand <jason.ekstrand@intel.com>
Fri, 11 Mar 2016 19:31:13 +0000 (11:31 -0800)
Right now, Vulkan apps can pretty easily DOS the GPU by simply submitting a
lot of batches.  This commit makes us wait until the rendering for earlier
frames is comlete before continuing.  By waiting 2 frames out, we can still
keep the pipe reasonably full but without taking the entire system down.
This is similar to what the GL driver does today.

src/intel/vulkan/anv_wsi.c
src/intel/vulkan/anv_wsi.h

index c5911a3635b111be549f856fc2c08cfb9f683c2f..c2938f3836fd79da765cc7f5f5d0eb8ad1cf122d 100644 (file)
@@ -132,6 +132,14 @@ VkResult anv_CreateSwapchainKHR(
    if (result != VK_SUCCESS)
       return result;
 
+   if (pAllocator)
+      swapchain->alloc = *pAllocator;
+   else
+      swapchain->alloc = device->alloc;
+
+   for (unsigned i = 0; i < ARRAY_SIZE(swapchain->fences); i++)
+      swapchain->fences[i] = VK_NULL_HANDLE;
+
    *pSwapchain = anv_swapchain_to_handle(swapchain);
 
    return VK_SUCCESS;
@@ -144,6 +152,11 @@ void anv_DestroySwapchainKHR(
 {
    ANV_FROM_HANDLE(anv_swapchain, swapchain, _swapchain);
 
+   for (unsigned i = 0; i < ARRAY_SIZE(swapchain->fences); i++) {
+      if (swapchain->fences[i] != VK_NULL_HANDLE)
+         anv_DestroyFence(device, swapchain->fences[i], pAllocator);
+   }
+
    swapchain->destroy(swapchain, pAllocator);
 }
 
@@ -185,11 +198,36 @@ VkResult anv_QueuePresentKHR(
 
       assert(swapchain->device == queue->device);
 
+      if (swapchain->fences[0] == VK_NULL_HANDLE) {
+         result = anv_CreateFence(anv_device_to_handle(queue->device),
+            &(VkFenceCreateInfo) {
+               .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+               .flags = 0,
+            }, &swapchain->alloc, &swapchain->fences[0]);
+         if (result != VK_SUCCESS)
+            return result;
+      } else {
+         anv_ResetFences(anv_device_to_handle(queue->device),
+                         1, &swapchain->fences[0]);
+      }
+
+      anv_QueueSubmit(_queue, 0, NULL, swapchain->fences[0]);
+
       result = swapchain->queue_present(swapchain, queue,
                                         pPresentInfo->pImageIndices[i]);
       /* TODO: What if one of them returns OUT_OF_DATE? */
       if (result != VK_SUCCESS)
          return result;
+
+      VkFence last = swapchain->fences[2];
+      swapchain->fences[2] = swapchain->fences[1];
+      swapchain->fences[1] = swapchain->fences[0];
+      swapchain->fences[0] = last;
+
+      if (last != VK_NULL_HANDLE) {
+         anv_WaitForFences(anv_device_to_handle(queue->device),
+                           1, &last, true, 1);
+      }
    }
 
    return VK_SUCCESS;
index 6e9ff9b8447700cd1a37cba984a0ea17807cee96..bf17f0331731b4592b0574b4fece6f9bd39a7e2a 100644 (file)
@@ -53,6 +53,10 @@ struct anv_wsi_interface {
 struct anv_swapchain {
    struct anv_device *device;
 
+   VkAllocationCallbacks alloc;
+
+   VkFence fences[3];
+
    VkResult (*destroy)(struct anv_swapchain *swapchain,
                        const VkAllocationCallbacks *pAllocator);
    VkResult (*get_images)(struct anv_swapchain *swapchain,