Parcourir la source

vulkan: Add support for texture sampler border color

This necessitated the use of a bunch of extensions to query and enable the feature, but this mechanism may also be needed for other extensions in the future
rdb il y a 2 ans
Parent
commit
cfeaf2ac6e

+ 44 - 11
panda/src/vulkandisplay/vulkanGraphicsPipe.cxx

@@ -125,9 +125,11 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
   }
   }
 #endif
 #endif
 
 
+  bool has_props2_ext = false;
   if (inst_version < VK_MAKE_VERSION(1, 1, 0) &&
   if (inst_version < VK_MAKE_VERSION(1, 1, 0) &&
-      has_instance_extension("VK_KHR_get_physical_device_properties2")) {
-    extensions.push_back("VK_KHR_get_physical_device_properties2");
+      has_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+    extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
+    has_props2_ext = true;
   }
   }
 
 
   VkApplicationInfo app_info;
   VkApplicationInfo app_info;
@@ -262,11 +264,6 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
     }
     }
   }
   }
 
 
-  // Query device limits and memory properties.
-  vkGetPhysicalDeviceFeatures(_gpu, &_gpu_features);
-  vkGetPhysicalDeviceProperties(_gpu, &_gpu_properties);
-  vkGetPhysicalDeviceMemoryProperties(_gpu, &_memory_properties);
-
   // Query queue information, used by find_queue_family_for_surface.
   // Query queue information, used by find_queue_family_for_surface.
   uint32_t num_families;
   uint32_t num_families;
   vkGetPhysicalDeviceQueueFamilyProperties(_gpu, &num_families, nullptr);
   vkGetPhysicalDeviceQueueFamilyProperties(_gpu, &num_families, nullptr);
@@ -285,6 +282,42 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
     _device_extensions[std::string(dev_extensions[i].extensionName)] = dev_extensions[i].specVersion;
     _device_extensions[std::string(dev_extensions[i].extensionName)] = dev_extensions[i].specVersion;
   }
   }
 
 
+  // Query device limits and memory properties.
+  vkGetPhysicalDeviceProperties(_gpu, &_gpu_properties);
+  vkGetPhysicalDeviceMemoryProperties(_gpu, &_memory_properties);
+
+  PFN_vkGetPhysicalDeviceFeatures2 pVkGetPhysicalDeviceFeatures2 = nullptr;
+
+  if (_gpu_properties.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
+    pVkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)
+      vkGetInstanceProcAddr(_instance, "vkGetPhysicalDeviceFeatures2");
+  }
+  else if (has_props2_ext) {
+    pVkGetPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)
+      vkGetInstanceProcAddr(_instance, "vkGetPhysicalDeviceFeatures2KHR");
+  }
+
+  if (pVkGetPhysicalDeviceFeatures2 != nullptr) {
+    VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
+
+    VkPhysicalDeviceCustomBorderColorFeaturesEXT cbc_features;
+    cbc_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT;
+    cbc_features.pNext = nullptr;
+    cbc_features.customBorderColors = VK_FALSE;
+    cbc_features.customBorderColorWithoutFormat = VK_FALSE;
+    if (has_device_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME)) {
+      features2.pNext = &cbc_features;
+    }
+
+    pVkGetPhysicalDeviceFeatures2(_gpu, &features2);
+    _gpu_features = features2.features;
+    _gpu_supports_custom_border_colors = cbc_features.customBorderColors
+                                      && cbc_features.customBorderColorWithoutFormat;
+  } else {
+    vkGetPhysicalDeviceFeatures(_gpu, &_gpu_features);
+    _gpu_supports_custom_border_colors = false;
+  }
+
   // Default the maximum allocation size to the largest of the heaps.
   // Default the maximum allocation size to the largest of the heaps.
   for (uint32_t i = 0; i < _memory_properties.memoryHeapCount; ++i) {
   for (uint32_t i = 0; i < _memory_properties.memoryHeapCount; ++i) {
     VkMemoryHeap &heap = _memory_properties.memoryHeaps[i];
     VkMemoryHeap &heap = _memory_properties.memoryHeaps[i];
@@ -297,9 +330,8 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
     maint3_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
     maint3_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
     maint3_props.maxMemoryAllocationSize = _max_allocation_size;
     maint3_props.maxMemoryAllocationSize = _max_allocation_size;
 
 
-    VkPhysicalDeviceProperties2 props2 = {};
-    props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
-    props2.pNext = &maint3_props;
+    VkPhysicalDeviceProperties2 props2 =
+      {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &maint3_props};
 
 
     if (_gpu_properties.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
     if (_gpu_properties.apiVersion >= VK_MAKE_VERSION(1, 1, 0)) {
       PFN_vkGetPhysicalDeviceProperties2 pVkGetPhysicalDeviceProperties2 =
       PFN_vkGetPhysicalDeviceProperties2 pVkGetPhysicalDeviceProperties2 =
@@ -309,7 +341,8 @@ VulkanGraphicsPipe() : _max_allocation_size(0) {
         pVkGetPhysicalDeviceProperties2(_gpu, &props2);
         pVkGetPhysicalDeviceProperties2(_gpu, &props2);
         _max_allocation_size = maint3_props.maxMemoryAllocationSize;
         _max_allocation_size = maint3_props.maxMemoryAllocationSize;
       }
       }
-    } else if (has_instance_extension("VK_KHR_get_physical_device_properties2")) {
+    }
+    else if (has_props2_ext) {
       PFN_vkGetPhysicalDeviceProperties2KHR pVkGetPhysicalDeviceProperties2KHR =
       PFN_vkGetPhysicalDeviceProperties2KHR pVkGetPhysicalDeviceProperties2KHR =
         (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(_instance, "vkGetPhysicalDeviceProperties2KHR");
         (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(_instance, "vkGetPhysicalDeviceProperties2KHR");
 
 

+ 1 - 0
panda/src/vulkandisplay/vulkanGraphicsPipe.h

@@ -74,6 +74,7 @@ public:
   VkPhysicalDevice _gpu;
   VkPhysicalDevice _gpu;
   VkPhysicalDeviceFeatures _gpu_features;
   VkPhysicalDeviceFeatures _gpu_features;
   VkPhysicalDeviceProperties _gpu_properties;
   VkPhysicalDeviceProperties _gpu_properties;
+  bool _gpu_supports_custom_border_colors = false;
   VkPhysicalDeviceMemoryProperties _memory_properties;
   VkPhysicalDeviceMemoryProperties _memory_properties;
   pvector<VkQueueFamilyProperties> _queue_families;
   pvector<VkQueueFamilyProperties> _queue_families;
   VkDeviceSize _max_allocation_size;
   VkDeviceSize _max_allocation_size;

+ 51 - 2
panda/src/vulkandisplay/vulkanGraphicsStateGuardian.cxx

@@ -80,6 +80,19 @@ VulkanGraphicsStateGuardian(GraphicsEngine *engine, VulkanGraphicsPipe *pipe,
     extensions.push_back("VK_KHR_swapchain");
     extensions.push_back("VK_KHR_swapchain");
   }
   }
 
 
+  VkPhysicalDeviceFeatures2 enabled_features = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
+
+  VkPhysicalDeviceCustomBorderColorFeaturesEXT cbc_features =
+    {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT};
+  if (pipe->_gpu_supports_custom_border_colors) {
+    cbc_features.customBorderColors = VK_TRUE;
+    cbc_features.customBorderColorWithoutFormat = VK_TRUE;
+    enabled_features.pNext = &cbc_features;
+
+    extensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
+    _supports_custom_border_colors = true;
+  }
+
   // Create a queue in the given queue family.  For now, we assume NVIDIA,
   // Create a queue in the given queue family.  For now, we assume NVIDIA,
   // which has only one queue family, but we want to separate this out for
   // which has only one queue family, but we want to separate this out for
   // the sake of AMD cards.
   // the sake of AMD cards.
@@ -109,6 +122,13 @@ VulkanGraphicsStateGuardian(GraphicsEngine *engine, VulkanGraphicsPipe *pipe,
   device_info.ppEnabledExtensionNames = &extensions[0];
   device_info.ppEnabledExtensionNames = &extensions[0];
   device_info.pEnabledFeatures = nullptr;
   device_info.pEnabledFeatures = nullptr;
 
 
+  if (pipe->_gpu_properties.apiVersion >= VK_MAKE_VERSION(1, 1, 0) ||
+      pipe->has_instance_extension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+    device_info.pNext = &enabled_features;
+  } else {
+    device_info.pEnabledFeatures = &enabled_features.features;
+  }
+
   VkResult
   VkResult
   err = vkCreateDevice(pipe->_gpu, &device_info, nullptr, &_device);
   err = vkCreateDevice(pipe->_gpu, &device_info, nullptr, &_device);
   if (err) {
   if (err) {
@@ -1603,7 +1623,6 @@ prepare_sampler(const SamplerState &sampler) {
                                      VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,
                                      VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE,
                                      VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
                                      VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
                                      VK_SAMPLER_ADDRESS_MODE_REPEAT};
                                      VK_SAMPLER_ADDRESS_MODE_REPEAT};
-  //TODO: support border color.
   VkSamplerCreateInfo sampler_info;
   VkSamplerCreateInfo sampler_info;
   sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
   sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
   sampler_info.pNext = nullptr;
   sampler_info.pNext = nullptr;
@@ -1630,9 +1649,39 @@ prepare_sampler(const SamplerState &sampler) {
   sampler_info.maxAnisotropy = sampler.get_effective_anisotropic_degree();
   sampler_info.maxAnisotropy = sampler.get_effective_anisotropic_degree();
   sampler_info.minLod = sampler.get_min_lod();
   sampler_info.minLod = sampler.get_min_lod();
   sampler_info.maxLod = sampler.get_max_lod();
   sampler_info.maxLod = sampler.get_max_lod();
-  sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
   sampler_info.unnormalizedCoordinates = VK_FALSE;
   sampler_info.unnormalizedCoordinates = VK_FALSE;
 
 
+  LColor border_color = sampler.get_border_color();
+  VkSamplerCustomBorderColorCreateInfoEXT custom_border_color;
+  if (border_color == LColor(0.0, 0.0, 0.0, 0.0)) {
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+  }
+  else if (border_color == LColor(0.0, 0.0, 0.0, 1.0)) {
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
+  }
+  else if (border_color == LColor(1.0, 1.0, 1.0, 1.0)) {
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
+  }
+  else if (_supports_custom_border_colors) {
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT;
+
+    custom_border_color.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT;
+    custom_border_color.pNext = nullptr;
+    custom_border_color.customBorderColor.float32[0] = border_color[0];
+    custom_border_color.customBorderColor.float32[1] = border_color[1];
+    custom_border_color.customBorderColor.float32[2] = border_color[2];
+    custom_border_color.customBorderColor.float32[3] = border_color[3];
+    custom_border_color.format = VK_FORMAT_UNDEFINED;
+
+    sampler_info.pNext = &custom_border_color;
+  }
+  else if (border_color[3] >= 0.5f) {
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
+  }
+  else {
+    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
+  }
+
   VkResult err;
   VkResult err;
   VkSampler vk_sampler;
   VkSampler vk_sampler;
   err = vkCreateSampler(_device, &sampler_info, nullptr, &vk_sampler);
   err = vkCreateSampler(_device, &sampler_info, nullptr, &vk_sampler);

+ 3 - 0
panda/src/vulkandisplay/vulkanGraphicsStateGuardian.h

@@ -274,6 +274,9 @@ private:
   uint64_t _frame_counter = 0;
   uint64_t _frame_counter = 0;
   uint64_t _last_finished_frame = 0;
   uint64_t _last_finished_frame = 0;
 
 
+  // Feature checks.
+  bool _supports_custom_border_colors = false;
+
   // Function pointers.
   // Function pointers.
   PFN_vkCmdBindIndexBuffer _vkCmdBindIndexBuffer;
   PFN_vkCmdBindIndexBuffer _vkCmdBindIndexBuffer;
   PFN_vkCmdBindPipeline _vkCmdBindPipeline;
   PFN_vkCmdBindPipeline _vkCmdBindPipeline;