Browse Source

vulkan: Make fewer assumptions about memory types on UMA systems

rdb 1 month ago
parent
commit
3e960cf388
1 changed files with 29 additions and 5 deletions
  1. 29 5
      panda/src/vulkandisplay/vulkanGraphicsStateGuardian.cxx

+ 29 - 5
panda/src/vulkandisplay/vulkanGraphicsStateGuardian.cxx

@@ -575,8 +575,19 @@ reset() {
   }
   _uniform_buffer_allocator = CircularAllocator(uniform_buffer_size, limits.minUniformBufferOffsetAlignment);
 
-  // If we have only one heap, it's safe to assume we're on a UMA system.
-  _has_unified_memory = (pipe->_memory_properties.memoryHeapCount == 1);
+  // If we have only one heap, it's safe to assume we're on a UMA system,
+  // but also double-check that there is a memory type which has device-local
+  // and host-visible access simultaneously.
+  _has_unified_memory = false;
+  if (pipe->_memory_properties.memoryHeapCount == 1) {
+    for (uint32_t i = 0; i < pipe->_memory_properties.memoryTypeCount; ++i) {
+      const VkMemoryType &mem_type = pipe->_memory_properties.memoryTypes[i];
+      if ((mem_type.propertyFlags & (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) == (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) {
+        _has_unified_memory = true;
+        break;
+      }
+    }
+  }
 
   // Create a staging buffer for CPU-to-GPU uploads.
   VkDeviceSize staging_buffer_size = vulkan_staging_buffer_size;
@@ -2185,11 +2196,17 @@ prepare_vertex_buffer(GeomVertexArrayData *array_data) {
   CPT(GeomVertexArrayDataHandle) handle = array_data->get_handle();
   VkDeviceSize data_size = handle->get_data_size_bytes();
 
+  VkMemoryPropertyFlagBits mem_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+  if (_has_unified_memory) {
+    // On UMA systems, we can write directly to device local buffers.
+    mem_flags = (VkMemoryPropertyFlagBits)(mem_flags | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+  }
+
   VkBuffer buffer;
   VulkanMemoryBlock block;
   if (!create_buffer(data_size, buffer, block,
                      VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
-                     VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
+                     mem_flags)) {
     vulkandisplay_cat.error()
       << "Failed to create vertex buffer.\n";
     return nullptr;
@@ -2334,11 +2351,17 @@ prepare_index_buffer(GeomPrimitive *primitive) {
     return nullptr;
   }
 
+  VkMemoryPropertyFlagBits mem_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+  if (_has_unified_memory) {
+    // On UMA systems, we can write directly to device local buffers.
+    mem_flags = (VkMemoryPropertyFlagBits)(mem_flags | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
+  }
+
   VkBuffer buffer;
   VulkanMemoryBlock block;
   if (!create_buffer(data_size, buffer, block,
                      VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
-                     VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
+                     mem_flags)) {
     vulkandisplay_cat.error()
       << "Failed to create index buffer.\n";
     return nullptr;
@@ -4458,6 +4481,7 @@ do_extract_buffer(VulkanBufferContext *bc, vector_uchar &data) {
     barrier.size = VK_WHOLE_SIZE;
     _transfer_cmd.add_barrier(barrier);
   } else {
+    // Actually, we can read the buffer directly.
     VkBufferMemoryBarrier2 barrier;
     barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2;
     barrier.pNext = nullptr;
@@ -4482,7 +4506,7 @@ do_extract_buffer(VulkanBufferContext *bc, vector_uchar &data) {
 
   data.resize(num_bytes);
   {
-    VulkanMemoryBlock &block = (_has_unified_memory ? bc->_block : tmp_block);
+    VulkanMemoryBlock &block = (bc->_host_visible ? bc->_block : tmp_block);
     VulkanMemoryMapping mapping = block.map();
     block.invalidate();
     memcpy(&data[0], mapping, num_bytes);