gpu: Make PipelineLayout objects do more things

Let the objects track the number of samplers or buffers needed.

This is a required step for making Vulkan work with less featureful
(read: mobile) implementations.
This commit is contained in:
Benjamin Otte 2023-11-03 01:59:24 +01:00
parent a301f18ebf
commit 47a13e601f
3 changed files with 113 additions and 80 deletions

View File

@ -20,12 +20,14 @@ struct _GskVulkanDevice
GskVulkanAllocator *external_allocator; GskVulkanAllocator *external_allocator;
GdkVulkanFeatures features; GdkVulkanFeatures features;
guint max_samplers;
guint max_buffers;
GHashTable *conversion_cache; GHashTable *conversion_cache;
GHashTable *render_pass_cache; GHashTable *render_pass_cache;
GHashTable *pipeline_layouts; GHashTable *pipeline_layouts;
GskVulkanPipelineLayout *pipeline_layout_cache; GskVulkanPipelineLayout *pipeline_layout_cache;
VkDescriptorSetLayout vk_buffer_set_layout;
VkCommandPool vk_command_pool; VkCommandPool vk_command_pool;
VkSampler vk_samplers[GSK_GPU_SAMPLER_N_SAMPLERS]; VkSampler vk_samplers[GSK_GPU_SAMPLER_N_SAMPLERS];
}; };
@ -40,16 +42,26 @@ G_DEFINE_TYPE (GskVulkanDevice, gsk_vulkan_device, GSK_TYPE_GPU_DEVICE)
typedef struct _ConversionCacheEntry ConversionCacheEntry; typedef struct _ConversionCacheEntry ConversionCacheEntry;
typedef struct _PipelineCacheKey PipelineCacheKey; typedef struct _PipelineCacheKey PipelineCacheKey;
typedef struct _RenderPassCacheKey RenderPassCacheKey; typedef struct _RenderPassCacheKey RenderPassCacheKey;
typedef struct _GskVulkanPipelineLayoutSetup GskVulkanPipelineLayoutSetup;
struct _GskVulkanPipelineLayoutSetup
{
gsize n_buffers;
gsize n_samplers;
gsize n_immutable_samplers;
VkSampler *immutable_samplers;
};
struct _GskVulkanPipelineLayout struct _GskVulkanPipelineLayout
{ {
gint ref_count; gint ref_count;
VkDescriptorSetLayout vk_buffer_set_layout;
VkDescriptorSetLayout vk_image_set_layout; VkDescriptorSetLayout vk_image_set_layout;
VkPipelineLayout vk_pipeline_layout; VkPipelineLayout vk_pipeline_layout;
GHashTable *pipeline_cache; GHashTable *pipeline_cache;
gsize n_samplers; GskVulkanPipelineLayoutSetup setup;
VkSampler samplers[]; VkSampler samplers[];
}; };
@ -139,18 +151,18 @@ render_pass_cache_key_equal (gconstpointer a,
} }
static GskVulkanPipelineLayout * static GskVulkanPipelineLayout *
gsk_vulkan_pipeline_layout_new (GskVulkanDevice *self, gsk_vulkan_pipeline_layout_new (GskVulkanDevice *self,
VkSampler *immutable_samplers, const GskVulkanPipelineLayoutSetup *setup)
gsize n_immutable_samplers)
{ {
GskVulkanPipelineLayout *layout; GskVulkanPipelineLayout *layout;
GdkDisplay *display; GdkDisplay *display;
layout = g_malloc (sizeof (GskVulkanPipelineLayout) + (n_immutable_samplers + 1) * sizeof (VkSampler)); layout = g_malloc (sizeof (GskVulkanPipelineLayout) + setup->n_immutable_samplers * sizeof (VkSampler));
layout->ref_count = 1; layout->ref_count = 1;
layout->n_samplers = n_immutable_samplers; layout->setup = *setup;
memcpy (layout->samplers, immutable_samplers, (n_immutable_samplers + 1) * sizeof (VkSampler)); memcpy (layout->samplers, setup->immutable_samplers, setup->n_immutable_samplers * sizeof (VkSampler));
layout->setup.immutable_samplers = layout->samplers;
layout->pipeline_cache = g_hash_table_new (pipeline_cache_key_hash, pipeline_cache_key_equal); layout->pipeline_cache = g_hash_table_new (pipeline_cache_key_hash, pipeline_cache_key_equal);
display = gsk_gpu_device_get_display (GSK_GPU_DEVICE (self)); display = gsk_gpu_device_get_display (GSK_GPU_DEVICE (self));
@ -164,14 +176,14 @@ gsk_vulkan_pipeline_layout_new (GskVulkanDevice *self,
{ {
.binding = 0, .binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = layout->n_samplers, .descriptorCount = layout->setup.n_immutable_samplers,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = layout->samplers .pImmutableSamplers = layout->setup.immutable_samplers
}, },
{ {
.binding = 1, .binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = DESCRIPTOR_POOL_MAXITEMS, .descriptorCount = layout->setup.n_samplers,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
} }
}, },
@ -190,13 +202,39 @@ gsk_vulkan_pipeline_layout_new (GskVulkanDevice *self,
NULL, NULL,
&layout->vk_image_set_layout); &layout->vk_image_set_layout);
GSK_VK_CHECK (vkCreateDescriptorSetLayout, display->vk_device,
&(VkDescriptorSetLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 1,
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
.pBindings = (VkDescriptorSetLayoutBinding[1]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = layout->setup.n_buffers,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
},
.pNext = &(VkDescriptorSetLayoutBindingFlagsCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
.bindingCount = 1,
.pBindingFlags = (VkDescriptorBindingFlags[1]) {
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT
| VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
| VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
},
}
},
NULL,
&layout->vk_buffer_set_layout);
GSK_VK_CHECK (vkCreatePipelineLayout, display->vk_device, GSK_VK_CHECK (vkCreatePipelineLayout, display->vk_device,
&(VkPipelineLayoutCreateInfo) { &(VkPipelineLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 2, .setLayoutCount = 2,
.pSetLayouts = (VkDescriptorSetLayout[2]) { .pSetLayouts = (VkDescriptorSetLayout[2]) {
layout->vk_image_set_layout, layout->vk_image_set_layout,
self->vk_buffer_set_layout, layout->vk_buffer_set_layout,
}, },
.pushConstantRangeCount = 1, .pushConstantRangeCount = 1,
.pPushConstantRanges = (VkPushConstantRange[1]) { .pPushConstantRanges = (VkPushConstantRange[1]) {
@ -210,7 +248,7 @@ gsk_vulkan_pipeline_layout_new (GskVulkanDevice *self,
NULL, NULL,
&layout->vk_pipeline_layout); &layout->vk_pipeline_layout);
g_hash_table_insert (self->pipeline_layouts, layout->samplers, layout); g_hash_table_insert (self->pipeline_layouts, &layout->setup, layout);
return layout; return layout;
} }
@ -227,7 +265,7 @@ gsk_vulkan_pipeline_layout_unref (GskVulkanDevice *self,
if (layout->ref_count) if (layout->ref_count)
return; return;
if (!g_hash_table_remove (self->pipeline_layouts, layout->samplers)) if (!g_hash_table_remove (self->pipeline_layouts, &layout->setup))
{ {
g_assert_not_reached (); g_assert_not_reached ();
} }
@ -237,6 +275,9 @@ gsk_vulkan_pipeline_layout_unref (GskVulkanDevice *self,
vkDestroyDescriptorSetLayout (display->vk_device, vkDestroyDescriptorSetLayout (display->vk_device,
layout->vk_image_set_layout, layout->vk_image_set_layout,
NULL); NULL);
vkDestroyDescriptorSetLayout (display->vk_device,
layout->vk_buffer_set_layout,
NULL);
vkDestroyPipelineLayout (display->vk_device, vkDestroyPipelineLayout (display->vk_device,
layout->vk_pipeline_layout, layout->vk_pipeline_layout,
@ -261,40 +302,46 @@ gsk_vulkan_pipeline_layout_ref (GskVulkanDevice *self,
} }
static guint static guint
gsk_vulkan_pipeline_layout_hash_samplers (gconstpointer data) gsk_vulkan_pipeline_layout_setup_hash (gconstpointer data)
{ {
const VkSampler *samplers = data; const GskVulkanPipelineLayoutSetup *setup = data;
guint result = 0; guint result;
gsize i;
while (*samplers) result = (setup->n_buffers << 23) |
(setup->n_samplers << 7) |
setup->n_immutable_samplers;
for (i = 0; i < setup->n_immutable_samplers; i++)
{ {
result = (result << 13) ^ result = (result << 13) ^
GPOINTER_TO_SIZE (*samplers) ^ GPOINTER_TO_SIZE (setup->immutable_samplers[i]) ^
(GPOINTER_TO_SIZE (*samplers) >> 32); (GPOINTER_TO_SIZE (setup->immutable_samplers[i]) >> 32);
samplers++;
} }
return result; return result;
} }
static gboolean static gboolean
pipeline_layout_equal_samplers (gconstpointer a, gsk_vulkan_pipeline_layout_setup_equal (gconstpointer a,
gconstpointer b) gconstpointer b)
{ {
const VkSampler *samplersa = a; const GskVulkanPipelineLayoutSetup *setupa = a;
const VkSampler *samplersb = b; const GskVulkanPipelineLayoutSetup *setupb = b;
gsize i;
while (TRUE) if (setupa->n_buffers != setupb->n_buffers ||
setupa->n_samplers != setupb->n_samplers ||
setupa->n_immutable_samplers != setupb->n_immutable_samplers)
return FALSE;
for (i = 0; i < setupa->n_immutable_samplers; i++)
{ {
if (*samplersa != *samplersb) if (setupa->immutable_samplers[i] != setupb->immutable_samplers[i])
return FALSE; return FALSE;
if (*samplersa == NULL)
return TRUE;
samplersa++;
samplersb++;
} }
return TRUE;
} }
static GskGpuImage * static GskGpuImage *
@ -390,10 +437,6 @@ gsk_vulkan_device_finalize (GObject *object)
self->vk_command_pool, self->vk_command_pool,
NULL); NULL);
vkDestroyDescriptorSetLayout (display->vk_device,
self->vk_buffer_set_layout,
NULL);
for (i = 0; i < VK_MAX_MEMORY_TYPES; i++) for (i = 0; i < VK_MAX_MEMORY_TYPES; i++)
g_clear_pointer (&self->allocators[i], gsk_vulkan_allocator_unref); g_clear_pointer (&self->allocators[i], gsk_vulkan_allocator_unref);
g_clear_pointer (&self->external_allocator, gsk_vulkan_allocator_unref); g_clear_pointer (&self->external_allocator, gsk_vulkan_allocator_unref);
@ -421,7 +464,7 @@ gsk_vulkan_device_init (GskVulkanDevice *self)
{ {
self->conversion_cache = g_hash_table_new (conversion_cache_entry_hash, conversion_cache_entry_equal); self->conversion_cache = g_hash_table_new (conversion_cache_entry_hash, conversion_cache_entry_equal);
self->render_pass_cache = g_hash_table_new (render_pass_cache_key_hash, render_pass_cache_key_equal); self->render_pass_cache = g_hash_table_new (render_pass_cache_key_hash, render_pass_cache_key_equal);
self->pipeline_layouts = g_hash_table_new (gsk_vulkan_pipeline_layout_hash_samplers, pipeline_layout_equal_samplers); self->pipeline_layouts = g_hash_table_new (gsk_vulkan_pipeline_layout_setup_hash, gsk_vulkan_pipeline_layout_setup_equal);
} }
static void static void
@ -431,32 +474,6 @@ gsk_vulkan_device_setup (GskVulkanDevice *self)
display = gsk_gpu_device_get_display (GSK_GPU_DEVICE (self)); display = gsk_gpu_device_get_display (GSK_GPU_DEVICE (self));
GSK_VK_CHECK (vkCreateDescriptorSetLayout, display->vk_device,
&(VkDescriptorSetLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 1,
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
.pBindings = (VkDescriptorSetLayoutBinding[1]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = DESCRIPTOR_POOL_MAXITEMS,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT
},
},
.pNext = &(VkDescriptorSetLayoutBindingFlagsCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
.bindingCount = 1,
.pBindingFlags = (VkDescriptorBindingFlags[1]) {
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT
| VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
| VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
},
}
},
NULL,
&self->vk_buffer_set_layout);
GSK_VK_CHECK (vkCreateCommandPool, display->vk_device, GSK_VK_CHECK (vkCreateCommandPool, display->vk_device,
&(const VkCommandPoolCreateInfo) { &(const VkCommandPoolCreateInfo) {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
@ -483,6 +500,8 @@ gsk_vulkan_device_get_for_display (GdkDisplay *display,
self = g_object_new (GSK_TYPE_VULKAN_DEVICE, NULL); self = g_object_new (GSK_TYPE_VULKAN_DEVICE, NULL);
self->features = display->vulkan_features; self->features = display->vulkan_features;
self->max_samplers = DESCRIPTOR_POOL_MAXITEMS;
self->max_buffers = DESCRIPTOR_POOL_MAXITEMS;
vkGetPhysicalDeviceProperties (display->vk_physical_device, &vk_props); vkGetPhysicalDeviceProperties (display->vk_physical_device, &vk_props);
gsk_gpu_device_setup (GSK_GPU_DEVICE (self), gsk_gpu_device_setup (GSK_GPU_DEVICE (self),
@ -540,9 +559,10 @@ gsk_vulkan_device_get_vk_image_set_layout (GskVulkanDevice *self,
} }
VkDescriptorSetLayout VkDescriptorSetLayout
gsk_vulkan_device_get_vk_buffer_set_layout (GskVulkanDevice *self) gsk_vulkan_device_get_vk_buffer_set_layout (GskVulkanDevice *self,
GskVulkanPipelineLayout *layout)
{ {
return self->vk_buffer_set_layout; return layout->vk_buffer_set_layout;
} }
VkPipelineLayout VkPipelineLayout
@ -836,7 +856,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.dataSize = sizeof (GskVulkanShaderSpecialization), .dataSize = sizeof (GskVulkanShaderSpecialization),
.pData = &(GskVulkanShaderSpecialization) { .pData = &(GskVulkanShaderSpecialization) {
.clip = clip, .clip = clip,
.n_immutable_samplers = layout->n_samplers, .n_immutable_samplers = layout->setup.n_immutable_samplers,
}, },
}, },
}, },
@ -862,7 +882,7 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
.dataSize = sizeof (GskVulkanShaderSpecialization), .dataSize = sizeof (GskVulkanShaderSpecialization),
.pData = &(GskVulkanShaderSpecialization) { .pData = &(GskVulkanShaderSpecialization) {
.clip = clip, .clip = clip,
.n_immutable_samplers = layout->n_samplers, .n_immutable_samplers = layout->setup.n_immutable_samplers,
}, },
}, },
}, },
@ -944,8 +964,11 @@ gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,
GskVulkanPipelineLayout * GskVulkanPipelineLayout *
gsk_vulkan_device_acquire_pipeline_layout (GskVulkanDevice *self, gsk_vulkan_device_acquire_pipeline_layout (GskVulkanDevice *self,
VkSampler *immutable_samplers, VkSampler *immutable_samplers,
gsize n_immutable_samplers) gsize n_immutable_samplers,
gsize n_samplers,
gsize n_buffers)
{ {
GskVulkanPipelineLayoutSetup setup;
GskVulkanPipelineLayout *layout; GskVulkanPipelineLayout *layout;
VkSampler fallback[2]; VkSampler fallback[2];
@ -957,18 +980,23 @@ gsk_vulkan_device_acquire_pipeline_layout (GskVulkanDevice *self,
immutable_samplers = fallback; immutable_samplers = fallback;
n_immutable_samplers = 1; n_immutable_samplers = 1;
} }
n_samplers = MIN (n_samplers, 8);
g_assert (n_samplers <= self->max_samplers);
n_buffers = MIN (n_buffers, 8);
g_assert (n_buffers <= self->max_buffers);
setup.n_samplers = MIN (2 << g_bit_nth_msf (n_samplers - 1, -1), self->max_samplers);
setup.n_buffers = MIN (2 << g_bit_nth_msf (n_buffers - 1, -1), self->max_buffers);
setup.n_immutable_samplers = n_immutable_samplers;
setup.immutable_samplers = immutable_samplers;
/* We require null-termination for the hash table lookup */ layout = g_hash_table_lookup (self->pipeline_layouts, &setup);
g_assert (immutable_samplers[n_immutable_samplers] == NULL);
layout = g_hash_table_lookup (self->pipeline_layouts, immutable_samplers);
if (layout) if (layout)
{ {
gsk_vulkan_pipeline_layout_ref (self, layout); gsk_vulkan_pipeline_layout_ref (self, layout);
return layout; return layout;
} }
return gsk_vulkan_pipeline_layout_new (self, immutable_samplers, n_immutable_samplers); return gsk_vulkan_pipeline_layout_new (self, &setup);
} }
void void

View File

@ -36,7 +36,6 @@ VkDevice gsk_vulkan_device_get_vk_device (GskVulk
VkPhysicalDevice gsk_vulkan_device_get_vk_physical_device (GskVulkanDevice *self) G_GNUC_PURE; VkPhysicalDevice gsk_vulkan_device_get_vk_physical_device (GskVulkanDevice *self) G_GNUC_PURE;
VkQueue gsk_vulkan_device_get_vk_queue (GskVulkanDevice *self) G_GNUC_PURE; 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; uint32_t gsk_vulkan_device_get_vk_queue_family_index (GskVulkanDevice *self) G_GNUC_PURE;
VkDescriptorSetLayout gsk_vulkan_device_get_vk_buffer_set_layout (GskVulkanDevice *self) G_GNUC_PURE;
VkCommandPool gsk_vulkan_device_get_vk_command_pool (GskVulkanDevice *self) G_GNUC_PURE; VkCommandPool gsk_vulkan_device_get_vk_command_pool (GskVulkanDevice *self) G_GNUC_PURE;
VkSampler gsk_vulkan_device_get_vk_sampler (GskVulkanDevice *self, VkSampler gsk_vulkan_device_get_vk_sampler (GskVulkanDevice *self,
GskGpuSampler sampler) G_GNUC_PURE; GskGpuSampler sampler) G_GNUC_PURE;
@ -44,11 +43,15 @@ VkSampler gsk_vulkan_device_get_vk_sampler (GskVulk
GskVulkanPipelineLayout * GskVulkanPipelineLayout *
gsk_vulkan_device_acquire_pipeline_layout (GskVulkanDevice *self, gsk_vulkan_device_acquire_pipeline_layout (GskVulkanDevice *self,
VkSampler *immutable_samplers, VkSampler *immutable_samplers,
gsize n_immutable_samplers); gsize n_immutable_samplers,
gsize n_samplers,
gsize n_buffers);
void gsk_vulkan_device_release_pipeline_layout (GskVulkanDevice *self, void gsk_vulkan_device_release_pipeline_layout (GskVulkanDevice *self,
GskVulkanPipelineLayout*layout); GskVulkanPipelineLayout*layout);
VkDescriptorSetLayout gsk_vulkan_device_get_vk_image_set_layout (GskVulkanDevice *self, VkDescriptorSetLayout gsk_vulkan_device_get_vk_image_set_layout (GskVulkanDevice *self,
GskVulkanPipelineLayout*layout) G_GNUC_PURE; GskVulkanPipelineLayout*layout) G_GNUC_PURE;
VkDescriptorSetLayout gsk_vulkan_device_get_vk_buffer_set_layout (GskVulkanDevice *self,
GskVulkanPipelineLayout*layout) G_GNUC_PURE;
VkPipelineLayout gsk_vulkan_device_get_vk_pipeline_layout (GskVulkanDevice *self, VkPipelineLayout gsk_vulkan_device_get_vk_pipeline_layout (GskVulkanDevice *self,
GskVulkanPipelineLayout*layout) G_GNUC_PURE; GskVulkanPipelineLayout*layout) G_GNUC_PURE;

View File

@ -30,8 +30,7 @@
#define GDK_ARRAY_NAME gsk_samplers #define GDK_ARRAY_NAME gsk_samplers
#define GDK_ARRAY_TYPE_NAME GskSamplers #define GDK_ARRAY_TYPE_NAME GskSamplers
#define GDK_ARRAY_ELEMENT_TYPE VkSampler #define GDK_ARRAY_ELEMENT_TYPE VkSampler
#define GDK_ARRAY_NULL_TERMINATED 1 #define GDK_ARRAY_PREALLOC 32
#define GDK_ARRAY_PREALLOC 31
#define GDK_ARRAY_NO_MEMSET 1 #define GDK_ARRAY_NO_MEMSET 1
#include "gdk/gdkarrayimpl.c" #include "gdk/gdkarrayimpl.c"
@ -251,7 +250,7 @@ gsk_vulkan_frame_prepare_descriptor_sets (GskVulkanFrame *self)
.descriptorSetCount = GSK_VULKAN_N_DESCRIPTOR_SETS, .descriptorSetCount = GSK_VULKAN_N_DESCRIPTOR_SETS,
.pSetLayouts = (VkDescriptorSetLayout[GSK_VULKAN_N_DESCRIPTOR_SETS]) { .pSetLayouts = (VkDescriptorSetLayout[GSK_VULKAN_N_DESCRIPTOR_SETS]) {
gsk_vulkan_device_get_vk_image_set_layout (device, self->pipeline_layout), gsk_vulkan_device_get_vk_image_set_layout (device, self->pipeline_layout),
gsk_vulkan_device_get_vk_buffer_set_layout (device), gsk_vulkan_device_get_vk_buffer_set_layout (device, self->pipeline_layout),
}, },
.pNext = &(VkDescriptorSetVariableDescriptorCountAllocateInfo) { .pNext = &(VkDescriptorSetVariableDescriptorCountAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO, .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
@ -355,7 +354,10 @@ gsk_vulkan_frame_submit (GskGpuFrame *frame,
self->pipeline_layout = gsk_vulkan_device_acquire_pipeline_layout (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)), self->pipeline_layout = gsk_vulkan_device_acquire_pipeline_layout (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
gsk_samplers_get_data (&self->immutable_samplers), gsk_samplers_get_data (&self->immutable_samplers),
gsk_samplers_get_size (&self->immutable_samplers)); gsk_samplers_get_size (&self->immutable_samplers),
gsk_descriptor_image_infos_get_size (&self->descriptor_images),
gsk_descriptor_buffer_infos_get_size (&self->descriptor_buffers));
GSK_VK_CHECK (vkBeginCommandBuffer, self->vk_command_buffer, GSK_VK_CHECK (vkBeginCommandBuffer, self->vk_command_buffer,
&(VkCommandBufferBeginInfo) { &(VkCommandBufferBeginInfo) {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,