gpu: Allocate Vulkan descriptor pools dynamically

Instead of allocating one large descriptor pool and hoping we never run
out of descriptors, allocate small ones dynamically, so we know we never
run out.

Test incldued, though the test doesn't fail in CI, because llvmpipe
doesn't care about pool size limits. It does fail on my AMD though.

A fun side note about that test is that the GL renderer handles it best
in normal operationbecause it caches offscreens per node and we draw the
same node repeatedly.
But, the replay test expands them to duplicated unique nodes, and then
the GL renderer runs out of command queue length, so I had to disable
the test on it.
This commit is contained in:
Benjamin Otte 2024-07-22 12:55:47 +02:00
parent 67b9fb43d0
commit 9e27acb0a6
6 changed files with 188 additions and 48 deletions

View File

@ -12,6 +12,13 @@
#include "gdk/gdkvulkancontextprivate.h"
#include "gdk/gdkprofilerprivate.h"
#define GDK_ARRAY_NAME descriptor_pools
#define GDK_ARRAY_TYPE_NAME DescriptorPools
#define GDK_ARRAY_ELEMENT_TYPE VkDescriptorPool
#define GDK_ARRAY_PREALLOC 4
#define GDK_ARRAY_NO_MEMSET 1
#include "gdk/gdkarrayimpl.c"
struct _GskVulkanDevice
{
GskGpuDevice parent_instance;
@ -25,7 +32,8 @@ struct _GskVulkanDevice
GHashTable *pipeline_cache;
VkCommandPool vk_command_pool;
VkDescriptorPool vk_descriptor_pool;
DescriptorPools descriptor_pools;
gsize last_pool;
VkSampler vk_samplers[GSK_GPU_SAMPLER_N_SAMPLERS];
VkDescriptorSetLayout vk_image_set_layout;
VkPipelineLayout default_vk_pipeline_layout;
@ -318,9 +326,11 @@ gsk_vulkan_device_finalize (GObject *object)
vkDestroyDescriptorSetLayout (vk_device,
self->vk_image_set_layout,
NULL);
vkDestroyDescriptorPool (vk_device,
self->vk_descriptor_pool,
NULL);
for (i = 0; i < descriptor_pools_get_size (&self->descriptor_pools); i++)
vkDestroyDescriptorPool (vk_device,
descriptor_pools_get (&self->descriptor_pools, i),
NULL);
descriptor_pools_clear (&self->descriptor_pools);
vkDestroyCommandPool (vk_device,
self->vk_command_pool,
NULL);
@ -355,6 +365,8 @@ gsk_vulkan_device_init (GskVulkanDevice *self)
self->ycbcr_cache = g_hash_table_new (g_direct_hash, g_direct_equal);
self->render_pass_cache = g_hash_table_new (render_pass_cache_key_hash, render_pass_cache_key_equal);
self->pipeline_cache = g_hash_table_new (pipeline_cache_key_hash, pipeline_cache_key_equal);
descriptor_pools_init (&self->descriptor_pools);
}
static void
@ -372,21 +384,6 @@ gsk_vulkan_device_create_vk_objects (GskVulkanDevice *self)
},
NULL,
&self->vk_command_pool);
GSK_VK_CHECK (vkCreateDescriptorPool, vk_device,
&(VkDescriptorPoolCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
.maxSets = 10000,
.poolSizeCount = 1,
.pPoolSizes = (VkDescriptorPoolSize[1]) {
{
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 10000,
},
}
},
NULL,
&self->vk_descriptor_pool);
self->vk_image_set_layout = gsk_vulkan_device_create_vk_image_set_layout (self);
@ -509,10 +506,91 @@ gsk_vulkan_device_get_vk_command_pool (GskVulkanDevice *self)
return self->vk_command_pool;
}
VkDescriptorPool
gsk_vulkan_device_get_vk_descriptor_pool (GskVulkanDevice *self)
VkDescriptorSet
gsk_vulkan_device_allocate_descriptor (GskVulkanDevice *self,
const VkDescriptorSetLayout layout,
gsize *out_pool_id)
{
return self->vk_descriptor_pool;
VkDescriptorSet result;
VkDevice vk_device;
VkDescriptorPool new_pool;
gsize i, n;
vk_device = gsk_vulkan_device_get_vk_device (self);
n = descriptor_pools_get_size (&self->descriptor_pools);
for (i = 0; i < n; i++)
{
gsize pool_id = (i + self->last_pool) % n;
VkResult res = vkAllocateDescriptorSets (vk_device,
&(VkDescriptorSetAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = descriptor_pools_get (&self->descriptor_pools, pool_id),
.descriptorSetCount = 1,
.pSetLayouts = (VkDescriptorSetLayout[1]) {
layout,
},
},
&result);
if (res == VK_SUCCESS)
{
self->last_pool = pool_id;
*out_pool_id = self->last_pool;
return result;
}
else if (res == VK_ERROR_OUT_OF_POOL_MEMORY ||
res == VK_ERROR_FRAGMENTED_POOL)
{
continue;
}
else
{
gsk_vulkan_handle_result (res, "vkAllocateDescriptorSets");
}
}
GSK_VK_CHECK (vkCreateDescriptorPool, vk_device,
&(VkDescriptorPoolCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
.maxSets = 100,
.poolSizeCount = 1,
.pPoolSizes = (VkDescriptorPoolSize[1]) {
{
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 100,
},
}
},
NULL,
&new_pool);
descriptor_pools_append (&self->descriptor_pools, new_pool);
GSK_VK_CHECK (vkAllocateDescriptorSets, vk_device,
&(VkDescriptorSetAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = new_pool,
.descriptorSetCount = 1,
.pSetLayouts = (VkDescriptorSetLayout[1]) {
layout,
},
},
&result);
self->last_pool = descriptor_pools_get_size (&self->descriptor_pools) - 1;
*out_pool_id = self->last_pool;
return result;
}
void
gsk_vulkan_device_free_descriptor (GskVulkanDevice *self,
gsize pool_id,
VkDescriptorSet set)
{
vkFreeDescriptorSets (gsk_vulkan_device_get_vk_device (self),
descriptor_pools_get (&self->descriptor_pools, pool_id),
1,
&set);
}
static VkSampler

View File

@ -29,7 +29,12 @@ VkPhysicalDevice gsk_vulkan_device_get_vk_physical_device (GskVulk
VkQueue gsk_vulkan_device_get_vk_queue (GskVulkanDevice *self) G_GNUC_PURE;
uint32_t gsk_vulkan_device_get_vk_queue_family_index (GskVulkanDevice *self) G_GNUC_PURE;
VkCommandPool gsk_vulkan_device_get_vk_command_pool (GskVulkanDevice *self) G_GNUC_PURE;
VkDescriptorPool gsk_vulkan_device_get_vk_descriptor_pool (GskVulkanDevice *self) G_GNUC_PURE;
VkDescriptorSet gsk_vulkan_device_allocate_descriptor (GskVulkanDevice *self,
const VkDescriptorSetLayout layout,
gsize *out_pool_id);
void gsk_vulkan_device_free_descriptor (GskVulkanDevice *self,
gsize pool_id,
VkDescriptorSet set);
VkDescriptorSetLayout gsk_vulkan_device_get_vk_image_set_layout (GskVulkanDevice *self) G_GNUC_PURE;
VkPipelineLayout gsk_vulkan_device_create_vk_pipeline_layout (GskVulkanDevice *self,
VkDescriptorSetLayout image1_layout,

View File

@ -34,7 +34,10 @@ struct _GskVulkanImage
VkImageView vk_framebuffer_image_view;
GskVulkanYcbcr *ycbcr;
VkSemaphore vk_semaphore;
VkDescriptorSet vk_descriptor_sets[GSK_GPU_SAMPLER_N_SAMPLERS];
struct {
VkDescriptorSet vk_descriptor_set;
gsize pool_id;
} descriptor_sets[GSK_GPU_SAMPLER_N_SAMPLERS];
VkPipelineStageFlags vk_pipeline_stage;
VkImageLayout vk_image_layout;
@ -1288,22 +1291,19 @@ static void
gsk_vulkan_image_finalize (GObject *object)
{
GskVulkanImage *self = GSK_VULKAN_IMAGE (object);
VkDescriptorPool vk_descriptor_pool;
VkDevice vk_device;
gsize i;
vk_device = gsk_vulkan_device_get_vk_device (self->device);
vk_descriptor_pool = gsk_vulkan_device_get_vk_descriptor_pool (self->device);
g_clear_pointer (&self->ycbcr, gsk_vulkan_ycbcr_unref);
for (i = 0; i < GSK_GPU_SAMPLER_N_SAMPLERS; i++)
{
if (self->vk_descriptor_sets[i])
vkFreeDescriptorSets (vk_device,
vk_descriptor_pool,
1,
&self->vk_descriptor_sets[i]);
if (self->descriptor_sets[i].vk_descriptor_set)
gsk_vulkan_device_free_descriptor (self->device,
self->descriptor_sets[i].pool_id,
self->descriptor_sets[i].vk_descriptor_set);
}
if (self->vk_framebuffer != VK_NULL_HANDLE)
@ -1406,27 +1406,19 @@ VkDescriptorSet
gsk_vulkan_image_get_vk_descriptor_set (GskVulkanImage *self,
GskGpuSampler sampler)
{
if (self->vk_descriptor_sets[sampler] == NULL)
if (!self->descriptor_sets[sampler].vk_descriptor_set)
{
VkDevice vk_device = gsk_vulkan_device_get_vk_device (self->device);
self->descriptor_sets[sampler].vk_descriptor_set =
gsk_vulkan_device_allocate_descriptor (self->device,
self->ycbcr ? gsk_vulkan_ycbcr_get_vk_descriptor_set_layout (self->ycbcr)
: gsk_vulkan_device_get_vk_image_set_layout (self->device),
&self->descriptor_sets[sampler].pool_id);
GSK_VK_CHECK (vkAllocateDescriptorSets, vk_device,
&(VkDescriptorSetAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = gsk_vulkan_device_get_vk_descriptor_pool (self->device),
.descriptorSetCount = 1,
.pSetLayouts = (VkDescriptorSetLayout[1]) {
self->ycbcr ? gsk_vulkan_ycbcr_get_vk_descriptor_set_layout (self->ycbcr)
: gsk_vulkan_device_get_vk_image_set_layout (self->device),
},
},
&self->vk_descriptor_sets[sampler]);
g_assert (self->vk_descriptor_sets[sampler]);
vkUpdateDescriptorSets (vk_device,
vkUpdateDescriptorSets (gsk_vulkan_device_get_vk_device (self->device),
1,
&(VkWriteDescriptorSet) {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = self->vk_descriptor_sets[sampler],
.dstSet = self->descriptor_sets[sampler].vk_descriptor_set,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
@ -1442,7 +1434,7 @@ gsk_vulkan_image_get_vk_descriptor_set (GskVulkanImage *self,
NULL);
}
return self->vk_descriptor_sets[sampler];
return self->descriptor_sets[sampler].vk_descriptor_set;
}
GskVulkanYcbcr *

View File

@ -0,0 +1,64 @@
cross-fade {
start: cross-fade "foo15" {
start: cross-fade "foo14" {
start: cross-fade "foo13" {
start: cross-fade "foo12" {
start: cross-fade "foo11" {
start: cross-fade "foo10" {
start: cross-fade "foo9" {
start: cross-fade "foo8" {
start: cross-fade "foo7" {
start: cross-fade "foo6" {
start: cross-fade "foo5" {
start: cross-fade "foo4" {
start: cross-fade "foo3" {
start: cross-fade "foo2" {
start: color "foo1" {
bounds: 0 0 10 10;
color: red;
}
end: "foo1";
progress: 0.4;
}
end: "foo2";
progress: 0.4;
}
end: "foo3";
progress: 0.8;
}
end: "foo4";
progress: 0.6;
}
end: "foo5";
progress: 0.4;
}
end: "foo6";
progress: 0.2;
}
end: "foo7";
progress: 0.6;
}
end: "foo8";
progress: 0.6;
}
end: "foo9";
progress: 0.8;
}
end: "foo10";
progress: 0.6;
}
end: "foo11";
progress: 0.4;
}
end: "foo12";
progress: 0.6;
}
end: "foo13";
progress: 0.2;
}
end: "foo14";
progress: 0.4;
}
end: "foo15";
progress: 0.2;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 B

View File

@ -99,6 +99,7 @@ compare_render_tests = [
'linear-gradient-3d-nocairo',
'linear-gradient-nonorthogonal-scale-nogl',
'linear-gradient-with-64-colorstops',
'lots-of-offscreens-nogl',
'mask',
'mask-clipped-inverted-alpha',
'mask-empty-mask',