mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-09-13 09:16:14 -07:00
vkd3d: Use mutable descriptors if available.
The mutable descriptor type allows six descriptor sets to be replaced with one set for CBV/SRV/UAV heaps.
This commit is contained in:
parent
bb64bfff63
commit
b0d1fb7d98
Notes:
Alexandre Julliard
2024-01-09 23:37:22 +01:00
Approved-by: Henri Verbeet (@hverbeet) Approved-by: Alexandre Julliard (@julliard) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/523
2
README
2
README
@ -9,7 +9,7 @@ similar, but not identical, to Direct3D 12.
|
|||||||
Building vkd3d
|
Building vkd3d
|
||||||
==============
|
==============
|
||||||
|
|
||||||
Vkd3d depends on SPIRV-Headers and Vulkan-Headers (>= 1.2.148).
|
Vkd3d depends on SPIRV-Headers and Vulkan-Headers (>= 1.3.228).
|
||||||
|
|
||||||
Vkd3d generates some of its headers from IDL files. If you are using the
|
Vkd3d generates some of its headers from IDL files. If you are using the
|
||||||
release tarballs, then these headers are pre-generated and are included. If
|
release tarballs, then these headers are pre-generated and are included. If
|
||||||
|
@ -86,7 +86,7 @@ AS_IF([test "x$ac_cv_header_spirv_unified1_GLSL_std_450_h" != "xyes" \
|
|||||||
-a "x$ac_cv_header_vulkan_GLSL_std_450_h" != "xyes"],
|
-a "x$ac_cv_header_vulkan_GLSL_std_450_h" != "xyes"],
|
||||||
[AC_MSG_ERROR([GLSL.std.450.h not found.])])
|
[AC_MSG_ERROR([GLSL.std.450.h not found.])])
|
||||||
|
|
||||||
VKD3D_CHECK_VULKAN_HEADER_VERSION([148], [AC_MSG_ERROR([Vulkan headers are too old, 1.2.148 is required.])])
|
VKD3D_CHECK_VULKAN_HEADER_VERSION([228], [AC_MSG_ERROR([Vulkan headers are too old, 1.3.228 is required.])])
|
||||||
|
|
||||||
AC_CHECK_DECL([SpvCapabilityDemoteToHelperInvocationEXT],, [AC_MSG_ERROR([SPIR-V headers are too old.])], [
|
AC_CHECK_DECL([SpvCapabilityDemoteToHelperInvocationEXT],, [AC_MSG_ERROR([SPIR-V headers are too old.])], [
|
||||||
#ifdef HAVE_SPIRV_UNIFIED1_SPIRV_H
|
#ifdef HAVE_SPIRV_UNIFIED1_SPIRV_H
|
||||||
|
@ -3270,7 +3270,8 @@ static void d3d12_command_list_bind_descriptor_heap(struct d3d12_command_list *l
|
|||||||
{
|
{
|
||||||
VkDescriptorSet vk_descriptor_set = heap->vk_descriptor_sets[set].vk_set;
|
VkDescriptorSet vk_descriptor_set = heap->vk_descriptor_sets[set].vk_set;
|
||||||
|
|
||||||
if (!vk_descriptor_set)
|
/* Null vk_set_layout means set 0 uses mutable descriptors, and this set is unused. */
|
||||||
|
if (!vk_descriptor_set || !list->device->vk_descriptor_heap_layouts[set].vk_set_layout)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point, rs->vk_pipeline_layout,
|
VK_CALL(vkCmdBindDescriptorSets(list->vk_command_buffer, bindings->vk_bind_point, rs->vk_pipeline_layout,
|
||||||
|
@ -94,6 +94,7 @@ static const struct vkd3d_optional_extension_info optional_device_extensions[] =
|
|||||||
VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker),
|
VK_EXTENSION(EXT_DEBUG_MARKER, EXT_debug_marker),
|
||||||
VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable),
|
VK_EXTENSION(EXT_DEPTH_CLIP_ENABLE, EXT_depth_clip_enable),
|
||||||
VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing),
|
VK_EXTENSION(EXT_DESCRIPTOR_INDEXING, EXT_descriptor_indexing),
|
||||||
|
VK_EXTENSION(EXT_MUTABLE_DESCRIPTOR_TYPE, EXT_mutable_descriptor_type),
|
||||||
VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2),
|
VK_EXTENSION(EXT_ROBUSTNESS_2, EXT_robustness2),
|
||||||
VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation),
|
VK_EXTENSION(EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION, EXT_shader_demote_to_helper_invocation),
|
||||||
VK_EXTENSION(EXT_SHADER_STENCIL_EXPORT, EXT_shader_stencil_export),
|
VK_EXTENSION(EXT_SHADER_STENCIL_EXPORT, EXT_shader_stencil_export),
|
||||||
@ -106,13 +107,32 @@ static HRESULT vkd3d_create_vk_descriptor_heap_layout(struct d3d12_device *devic
|
|||||||
{
|
{
|
||||||
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
||||||
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags_info;
|
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flags_info;
|
||||||
|
VkMutableDescriptorTypeCreateInfoEXT mutable_info;
|
||||||
|
VkMutableDescriptorTypeListEXT type_list;
|
||||||
VkDescriptorSetLayoutCreateInfo set_desc;
|
VkDescriptorSetLayoutCreateInfo set_desc;
|
||||||
VkDescriptorBindingFlagsEXT set_flags;
|
VkDescriptorBindingFlagsEXT set_flags;
|
||||||
VkDescriptorSetLayoutBinding binding;
|
VkDescriptorSetLayoutBinding binding;
|
||||||
VkResult vr;
|
VkResult vr;
|
||||||
|
|
||||||
|
static const VkDescriptorType descriptor_types[] =
|
||||||
|
{
|
||||||
|
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
|
||||||
|
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||||
|
VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
|
||||||
|
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (device->vk_info.EXT_mutable_descriptor_type && index && index != VKD3D_SET_INDEX_UAV_COUNTER
|
||||||
|
&& device->vk_descriptor_heap_layouts[index].applicable_heap_type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV)
|
||||||
|
{
|
||||||
|
device->vk_descriptor_heap_layouts[index].vk_set_layout = VK_NULL_HANDLE;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
binding.binding = 0;
|
binding.binding = 0;
|
||||||
binding.descriptorType = device->vk_descriptor_heap_layouts[index].type;
|
binding.descriptorType = (device->vk_info.EXT_mutable_descriptor_type && !index)
|
||||||
|
? VK_DESCRIPTOR_TYPE_MUTABLE_EXT : device->vk_descriptor_heap_layouts[index].type;
|
||||||
binding.descriptorCount = device->vk_descriptor_heap_layouts[index].count;
|
binding.descriptorCount = device->vk_descriptor_heap_layouts[index].count;
|
||||||
binding.stageFlags = VK_SHADER_STAGE_ALL;
|
binding.stageFlags = VK_SHADER_STAGE_ALL;
|
||||||
binding.pImmutableSamplers = NULL;
|
binding.pImmutableSamplers = NULL;
|
||||||
@ -132,6 +152,17 @@ static HRESULT vkd3d_create_vk_descriptor_heap_layout(struct d3d12_device *devic
|
|||||||
flags_info.bindingCount = 1;
|
flags_info.bindingCount = 1;
|
||||||
flags_info.pBindingFlags = &set_flags;
|
flags_info.pBindingFlags = &set_flags;
|
||||||
|
|
||||||
|
if (binding.descriptorType == VK_DESCRIPTOR_TYPE_MUTABLE_EXT)
|
||||||
|
{
|
||||||
|
type_list.descriptorTypeCount = ARRAY_SIZE(descriptor_types);
|
||||||
|
type_list.pDescriptorTypes = descriptor_types;
|
||||||
|
mutable_info.sType = VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT;
|
||||||
|
mutable_info.pNext = NULL;
|
||||||
|
mutable_info.mutableDescriptorTypeListCount = 1;
|
||||||
|
mutable_info.pMutableDescriptorTypeLists = &type_list;
|
||||||
|
flags_info.pNext = &mutable_info;
|
||||||
|
}
|
||||||
|
|
||||||
if ((vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL,
|
if ((vr = VK_CALL(vkCreateDescriptorSetLayout(device->vk_device, &set_desc, NULL,
|
||||||
&device->vk_descriptor_heap_layouts[index].vk_set_layout))) < 0)
|
&device->vk_descriptor_heap_layouts[index].vk_set_layout))) < 0)
|
||||||
{
|
{
|
||||||
@ -763,6 +794,7 @@ struct vkd3d_physical_device_info
|
|||||||
VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features;
|
VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features;
|
||||||
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features;
|
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features;
|
||||||
VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore_features;
|
VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline_semaphore_features;
|
||||||
|
VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT mutable_features;
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures2 features2;
|
VkPhysicalDeviceFeatures2 features2;
|
||||||
};
|
};
|
||||||
@ -780,6 +812,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
|
|||||||
VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features;
|
VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT *buffer_alignment_features;
|
||||||
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT *demote_features;
|
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT *demote_features;
|
||||||
VkPhysicalDeviceTimelineSemaphoreFeaturesKHR *timeline_semaphore_features;
|
VkPhysicalDeviceTimelineSemaphoreFeaturesKHR *timeline_semaphore_features;
|
||||||
|
VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT *mutable_features;
|
||||||
VkPhysicalDeviceDepthClipEnableFeaturesEXT *depth_clip_features;
|
VkPhysicalDeviceDepthClipEnableFeaturesEXT *depth_clip_features;
|
||||||
VkPhysicalDeviceMaintenance3Properties *maintenance3_properties;
|
VkPhysicalDeviceMaintenance3Properties *maintenance3_properties;
|
||||||
VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb_properties;
|
VkPhysicalDeviceTransformFeedbackPropertiesEXT *xfb_properties;
|
||||||
@ -800,6 +833,7 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
|
|||||||
vertex_divisor_features = &info->vertex_divisor_features;
|
vertex_divisor_features = &info->vertex_divisor_features;
|
||||||
vertex_divisor_properties = &info->vertex_divisor_properties;
|
vertex_divisor_properties = &info->vertex_divisor_properties;
|
||||||
timeline_semaphore_features = &info->timeline_semaphore_features;
|
timeline_semaphore_features = &info->timeline_semaphore_features;
|
||||||
|
mutable_features = &info->mutable_features;
|
||||||
xfb_features = &info->xfb_features;
|
xfb_features = &info->xfb_features;
|
||||||
xfb_properties = &info->xfb_properties;
|
xfb_properties = &info->xfb_properties;
|
||||||
|
|
||||||
@ -823,6 +857,8 @@ static void vkd3d_physical_device_info_init(struct vkd3d_physical_device_info *i
|
|||||||
vk_prepend_struct(&info->features2, vertex_divisor_features);
|
vk_prepend_struct(&info->features2, vertex_divisor_features);
|
||||||
timeline_semaphore_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR;
|
timeline_semaphore_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR;
|
||||||
vk_prepend_struct(&info->features2, timeline_semaphore_features);
|
vk_prepend_struct(&info->features2, timeline_semaphore_features);
|
||||||
|
mutable_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT;
|
||||||
|
vk_prepend_struct(&info->features2, mutable_features);
|
||||||
|
|
||||||
if (vulkan_info->KHR_get_physical_device_properties2)
|
if (vulkan_info->KHR_get_physical_device_properties2)
|
||||||
VK_CALL(vkGetPhysicalDeviceFeatures2KHR(physical_device, &info->features2));
|
VK_CALL(vkGetPhysicalDeviceFeatures2KHR(physical_device, &info->features2));
|
||||||
@ -1594,6 +1630,8 @@ static HRESULT vkd3d_init_device_caps(struct d3d12_device *device,
|
|||||||
vulkan_info->EXT_shader_demote_to_helper_invocation = false;
|
vulkan_info->EXT_shader_demote_to_helper_invocation = false;
|
||||||
if (!physical_device_info->texel_buffer_alignment_features.texelBufferAlignment)
|
if (!physical_device_info->texel_buffer_alignment_features.texelBufferAlignment)
|
||||||
vulkan_info->EXT_texel_buffer_alignment = false;
|
vulkan_info->EXT_texel_buffer_alignment = false;
|
||||||
|
if (!physical_device_info->mutable_features.mutableDescriptorType)
|
||||||
|
vulkan_info->EXT_mutable_descriptor_type = false;
|
||||||
if (!physical_device_info->timeline_semaphore_features.timelineSemaphore)
|
if (!physical_device_info->timeline_semaphore_features.timelineSemaphore)
|
||||||
vulkan_info->KHR_timeline_semaphore = false;
|
vulkan_info->KHR_timeline_semaphore = false;
|
||||||
|
|
||||||
|
@ -2470,12 +2470,14 @@ static void d3d12_desc_write_vk_heap_null_descriptor(struct d3d12_descriptor_hea
|
|||||||
{
|
{
|
||||||
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
||||||
struct d3d12_descriptor_heap_vk_set *descriptor_set;
|
struct d3d12_descriptor_heap_vk_set *descriptor_set;
|
||||||
enum vkd3d_vk_descriptor_set_index set;
|
enum vkd3d_vk_descriptor_set_index set, end;
|
||||||
unsigned int i = writes->count;
|
unsigned int i = writes->count;
|
||||||
|
|
||||||
|
end = device->vk_info.EXT_mutable_descriptor_type ? VKD3D_SET_INDEX_UNIFORM_BUFFER
|
||||||
|
: VKD3D_SET_INDEX_STORAGE_IMAGE;
|
||||||
/* Binding a shader with the wrong null descriptor type works in Windows.
|
/* Binding a shader with the wrong null descriptor type works in Windows.
|
||||||
* To support that here we must write one to all applicable Vulkan sets. */
|
* To support that here we must write one to all applicable Vulkan sets. */
|
||||||
for (set = VKD3D_SET_INDEX_UNIFORM_BUFFER; set <= VKD3D_SET_INDEX_STORAGE_IMAGE; ++set)
|
for (set = VKD3D_SET_INDEX_UNIFORM_BUFFER; set <= end; ++set)
|
||||||
{
|
{
|
||||||
descriptor_set = &descriptor_heap->vk_descriptor_sets[set];
|
descriptor_set = &descriptor_heap->vk_descriptor_sets[set];
|
||||||
writes->vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
writes->vk_descriptor_writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
@ -4220,9 +4222,11 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_pool(struct d3d12_descrip
|
|||||||
|
|
||||||
for (set = 0, pool_desc.poolSizeCount = 0; set < ARRAY_SIZE(device->vk_descriptor_heap_layouts); ++set)
|
for (set = 0, pool_desc.poolSizeCount = 0; set < ARRAY_SIZE(device->vk_descriptor_heap_layouts); ++set)
|
||||||
{
|
{
|
||||||
if (device->vk_descriptor_heap_layouts[set].applicable_heap_type == desc->Type)
|
if (device->vk_descriptor_heap_layouts[set].applicable_heap_type == desc->Type
|
||||||
|
&& device->vk_descriptor_heap_layouts[set].vk_set_layout)
|
||||||
{
|
{
|
||||||
pool_sizes[pool_desc.poolSizeCount].type = device->vk_descriptor_heap_layouts[set].type;
|
pool_sizes[pool_desc.poolSizeCount].type = (device->vk_info.EXT_mutable_descriptor_type && !set)
|
||||||
|
? VK_DESCRIPTOR_TYPE_MUTABLE_EXT : device->vk_descriptor_heap_layouts[set].type;
|
||||||
pool_sizes[pool_desc.poolSizeCount++].descriptorCount = desc->NumDescriptors;
|
pool_sizes[pool_desc.poolSizeCount++].descriptorCount = desc->NumDescriptors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4248,6 +4252,16 @@ static HRESULT d3d12_descriptor_heap_create_descriptor_set(struct d3d12_descript
|
|||||||
VkDescriptorSetAllocateInfo set_desc;
|
VkDescriptorSetAllocateInfo set_desc;
|
||||||
VkResult vr;
|
VkResult vr;
|
||||||
|
|
||||||
|
if (!device->vk_descriptor_heap_layouts[set].vk_set_layout)
|
||||||
|
{
|
||||||
|
/* Set 0 uses mutable descriptors, and this set is unused. */
|
||||||
|
if (!descriptor_heap->vk_descriptor_sets[0].vk_set)
|
||||||
|
d3d12_descriptor_heap_create_descriptor_set(descriptor_heap, device, 0);
|
||||||
|
descriptor_set->vk_set = descriptor_heap->vk_descriptor_sets[0].vk_set;
|
||||||
|
descriptor_set->vk_type = device->vk_descriptor_heap_layouts[set].type;
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
set_desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
set_desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||||
set_desc.pNext = &set_size;
|
set_desc.pNext = &set_size;
|
||||||
set_desc.descriptorPool = descriptor_heap->vk_descriptor_pool;
|
set_desc.descriptorPool = descriptor_heap->vk_descriptor_pool;
|
||||||
|
@ -848,7 +848,20 @@ static void vkd3d_descriptor_heap_binding_from_descriptor_range(const struct d3d
|
|||||||
const struct vkd3d_device_descriptor_limits *descriptor_limits = &root_signature->device->vk_info.descriptor_limits;
|
const struct vkd3d_device_descriptor_limits *descriptor_limits = &root_signature->device->vk_info.descriptor_limits;
|
||||||
unsigned int descriptor_set_size;
|
unsigned int descriptor_set_size;
|
||||||
|
|
||||||
switch (range->type)
|
if (root_signature->device->vk_info.EXT_mutable_descriptor_type)
|
||||||
|
{
|
||||||
|
if (range->type == VKD3D_SHADER_DESCRIPTOR_TYPE_SAMPLER)
|
||||||
|
{
|
||||||
|
binding->set = VKD3D_SET_INDEX_SAMPLER;
|
||||||
|
descriptor_set_size = descriptor_limits->sampler_max_descriptors;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
binding->set = 0;
|
||||||
|
descriptor_set_size = descriptor_limits->sampled_image_max_descriptors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else switch (range->type)
|
||||||
{
|
{
|
||||||
case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV:
|
case VKD3D_SHADER_DESCRIPTOR_TYPE_SRV:
|
||||||
binding->set = is_buffer ? VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER : VKD3D_SET_INDEX_SAMPLED_IMAGE;
|
binding->set = is_buffer ? VKD3D_SET_INDEX_UNIFORM_TEXEL_BUFFER : VKD3D_SET_INDEX_SAMPLED_IMAGE;
|
||||||
@ -1368,8 +1381,14 @@ static unsigned int d3d12_root_signature_copy_descriptor_set_layouts(const struc
|
|||||||
|
|
||||||
if (device->use_vk_heaps)
|
if (device->use_vk_heaps)
|
||||||
{
|
{
|
||||||
|
VkDescriptorSetLayout mutable_layout = device->vk_descriptor_heap_layouts[0].vk_set_layout;
|
||||||
|
|
||||||
for (set = 0; set < ARRAY_SIZE(device->vk_descriptor_heap_layouts); ++set)
|
for (set = 0; set < ARRAY_SIZE(device->vk_descriptor_heap_layouts); ++set)
|
||||||
vk_set_layouts[i++] = device->vk_descriptor_heap_layouts[set].vk_set_layout;
|
{
|
||||||
|
VkDescriptorSetLayout vk_set_layout = device->vk_descriptor_heap_layouts[set].vk_set_layout;
|
||||||
|
/* All layouts must be valid, so if null, just set it to the mutable one. */
|
||||||
|
vk_set_layouts[i++] = vk_set_layout ? vk_set_layout : mutable_layout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
|
@ -133,6 +133,7 @@ struct vkd3d_vulkan_info
|
|||||||
bool EXT_debug_marker;
|
bool EXT_debug_marker;
|
||||||
bool EXT_depth_clip_enable;
|
bool EXT_depth_clip_enable;
|
||||||
bool EXT_descriptor_indexing;
|
bool EXT_descriptor_indexing;
|
||||||
|
bool EXT_mutable_descriptor_type;
|
||||||
bool EXT_robustness2;
|
bool EXT_robustness2;
|
||||||
bool EXT_shader_demote_to_helper_invocation;
|
bool EXT_shader_demote_to_helper_invocation;
|
||||||
bool EXT_shader_stencil_export;
|
bool EXT_shader_stencil_export;
|
||||||
|
Loading…
Reference in New Issue
Block a user