gpu: Completely revamp YCbCr handling

There is now a GskGpuYcbcr struct that maintains all the Vulkan
machinery related to YCbCrConversions.
It's a GskGpuCached, so it will make itself go away when it is no longer
used, ie a video stopped playing.
This commit is contained in:
Benjamin Otte 2024-07-22 01:24:52 +02:00
parent 762b981dfe
commit 67b9fb43d0
8 changed files with 313 additions and 107 deletions

View File

@ -96,7 +96,9 @@ gsk_gpu_shader_op_vk_command_n (GskGpuOp *op,
n_ops += next_shader->n_ops;
}
vk_pipeline_layout = gsk_vulkan_device_get_default_vk_pipeline_layout (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)));
vk_pipeline_layout = gsk_vulkan_device_get_vk_pipeline_layout (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
shader_op_class->n_textures > 0 ? gsk_vulkan_image_get_ycbcr (GSK_VULKAN_IMAGE (self->images[0])) : NULL,
shader_op_class->n_textures > 1 ? gsk_vulkan_image_get_ycbcr (GSK_VULKAN_IMAGE (self->images[1])) : NULL);
for (i = 0; i < shader_op_class->n_textures; i++)
{

View File

@ -6,6 +6,7 @@
#include "gskgpushaderopprivate.h"
#include "gskvulkanbufferprivate.h"
#include "gskvulkanimageprivate.h"
#include "gskvulkanycbcrprivate.h"
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdkvulkancontextprivate.h"
@ -19,7 +20,7 @@ struct _GskVulkanDevice
GskVulkanAllocator *external_allocator;
GdkVulkanFeatures features;
GHashTable *conversion_cache;
GHashTable *ycbcr_cache;
GHashTable *render_pass_cache;
GHashTable *pipeline_cache;
@ -70,24 +71,6 @@ struct _RenderPassCacheKey
VkRenderPass render_pass;
};
static guint
conversion_cache_entry_hash (gconstpointer data)
{
const ConversionCacheEntry *key = data;
return key->vk_format;
}
static gboolean
conversion_cache_entry_equal (gconstpointer a,
gconstpointer b)
{
const ConversionCacheEntry *keya = a;
const ConversionCacheEntry *keyb = b;
return keya->vk_format == keyb->vk_format;
}
static guint
pipeline_cache_key_hash (gconstpointer data)
{
@ -141,8 +124,7 @@ render_pass_cache_key_equal (gconstpointer a,
}
static VkDescriptorSetLayout
gsk_vulkan_device_create_vk_image_set_layout (GskVulkanDevice *self,
VkSampler immutable_sampler)
gsk_vulkan_device_create_vk_image_set_layout (GskVulkanDevice *self)
{
VkDevice vk_device;
VkDescriptorSetLayout result;
@ -160,9 +142,6 @@ gsk_vulkan_device_create_vk_image_set_layout (GskVulkanDevice *self,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = immutable_sampler == VK_NULL_HANDLE ? NULL : (VkSampler[1]) {
immutable_sampler,
},
}
},
},
@ -172,7 +151,7 @@ gsk_vulkan_device_create_vk_image_set_layout (GskVulkanDevice *self,
return result;
}
static VkPipelineLayout
VkPipelineLayout
gsk_vulkan_device_create_vk_pipeline_layout (GskVulkanDevice *self,
VkDescriptorSetLayout image1_layout,
VkDescriptorSetLayout image2_layout)
@ -302,6 +281,9 @@ gsk_vulkan_device_finalize (GObject *object)
g_object_steal_data (G_OBJECT (display), "-gsk-vulkan-device");
g_assert (g_hash_table_size (self->ycbcr_cache) == 0);
g_hash_table_unref (self->ycbcr_cache);
g_hash_table_iter_init (&iter, self->pipeline_cache);
while (g_hash_table_iter_next (&iter, &key, &value))
{
@ -312,16 +294,6 @@ gsk_vulkan_device_finalize (GObject *object)
}
g_hash_table_unref (self->pipeline_cache);
g_hash_table_iter_init (&iter, self->conversion_cache);
while (g_hash_table_iter_next (&iter, &key, &value))
{
ConversionCacheEntry *entry = key;
vkDestroySamplerYcbcrConversion (vk_device, entry->vk_conversion, NULL);
vkDestroySampler (vk_device, entry->vk_sampler, NULL);
g_free (key);
}
g_hash_table_unref (self->conversion_cache);
g_hash_table_iter_init (&iter, self->render_pass_cache);
while (g_hash_table_iter_next (&iter, &key, &value))
{
@ -380,7 +352,7 @@ gsk_vulkan_device_class_init (GskVulkanDeviceClass *klass)
static void
gsk_vulkan_device_init (GskVulkanDevice *self)
{
self->conversion_cache = g_hash_table_new (conversion_cache_entry_hash, conversion_cache_entry_equal);
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);
}
@ -416,7 +388,7 @@ gsk_vulkan_device_create_vk_objects (GskVulkanDevice *self)
NULL,
&self->vk_descriptor_pool);
self->vk_image_set_layout = gsk_vulkan_device_create_vk_image_set_layout (self, NULL);
self->vk_image_set_layout = gsk_vulkan_device_create_vk_image_set_layout (self);
self->default_vk_pipeline_layout = gsk_vulkan_device_create_vk_pipeline_layout (self,
self->vk_image_set_layout,
@ -507,6 +479,30 @@ gsk_vulkan_device_get_default_vk_pipeline_layout (GskVulkanDevice *self)
return self->default_vk_pipeline_layout;
}
VkPipelineLayout
gsk_vulkan_device_get_vk_pipeline_layout (GskVulkanDevice *self,
GskVulkanYcbcr *ycbcr0,
GskVulkanYcbcr *ycbcr1)
{
if (ycbcr0 == VK_NULL_HANDLE)
{
if (ycbcr1 == VK_NULL_HANDLE)
return self->default_vk_pipeline_layout;
else
return gsk_vulkan_ycbcr_get_vk_pipeline_layout (ycbcr1, 1);
}
else
{
if (ycbcr1 == VK_NULL_HANDLE)
return gsk_vulkan_ycbcr_get_vk_pipeline_layout (ycbcr0, 0);
else
{
/* FIXME: someone write a test plz */
g_assert_not_reached ();
}
}
}
VkCommandPool
gsk_vulkan_device_get_vk_command_pool (GskVulkanDevice *self)
{
@ -609,64 +605,26 @@ gsk_vulkan_device_get_vk_sampler (GskVulkanDevice *self,
return self->vk_samplers[sampler];
}
VkSamplerYcbcrConversion
gsk_vulkan_device_get_vk_conversion (GskVulkanDevice *self,
VkFormat vk_format,
VkSampler *out_sampler)
GskVulkanYcbcr *
gsk_vulkan_device_get_ycbcr (GskVulkanDevice *self,
VkFormat vk_format)
{
ConversionCacheEntry lookup;
ConversionCacheEntry *entry;
GdkDisplay *display;
GskVulkanYcbcr *ycbcr;
lookup = (ConversionCacheEntry) {
.vk_format = vk_format,
};
entry = g_hash_table_lookup (self->conversion_cache, &lookup);
if (entry)
{
if (out_sampler)
*out_sampler = entry->vk_sampler;
ycbcr = g_hash_table_lookup (self->ycbcr_cache, GSIZE_TO_POINTER(vk_format));
if (ycbcr)
return ycbcr;
return entry->vk_conversion;
}
ycbcr = gsk_vulkan_ycbcr_new (self, vk_format);
g_hash_table_insert (self->ycbcr_cache, GSIZE_TO_POINTER(vk_format), ycbcr);
return ycbcr;
}
display = gsk_gpu_device_get_display (GSK_GPU_DEVICE (self));
entry = g_memdup (&lookup, sizeof (ConversionCacheEntry));
GSK_VK_CHECK (vkCreateSamplerYcbcrConversion, display->vk_device,
&(VkSamplerYcbcrConversionCreateInfo) {
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
.format = vk_format,
.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601,
.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
.components = (VkComponentMapping) {
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY
},
.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN,
.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN,
.chromaFilter = VK_FILTER_LINEAR,
.forceExplicitReconstruction = VK_FALSE
},
NULL,
&entry->vk_conversion);
entry->vk_sampler = gsk_vulkan_device_create_sampler (self,
entry->vk_conversion,
VK_FILTER_LINEAR,
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
VK_SAMPLER_MIPMAP_MODE_NEAREST,
0.0f);
g_hash_table_insert (self->conversion_cache, entry, entry);
if (out_sampler)
*out_sampler = entry->vk_sampler;
return entry->vk_conversion;
void
gsk_vulkan_device_remove_ycbcr (GskVulkanDevice *self,
VkFormat vk_format)
{
g_hash_table_remove (self->ycbcr_cache, GSIZE_TO_POINTER(vk_format));
}
VkRenderPass

View File

@ -11,6 +11,9 @@
G_BEGIN_DECLS
/* forward declaration */
typedef struct _GskVulkanYcbcr GskVulkanYcbcr;
#define GSK_TYPE_VULKAN_DEVICE (gsk_vulkan_device_get_type ())
G_DECLARE_FINAL_TYPE(GskVulkanDevice, gsk_vulkan_device, GSK, VULKAN_DEVICE, GskGpuDevice)
@ -28,14 +31,21 @@ uint32_t gsk_vulkan_device_get_vk_queue_family_index (GskVulk
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;
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,
VkDescriptorSetLayout image2_layout);
VkPipelineLayout gsk_vulkan_device_get_default_vk_pipeline_layout (GskVulkanDevice *self) G_GNUC_PURE;
VkPipelineLayout gsk_vulkan_device_get_vk_pipeline_layout (GskVulkanDevice *self,
GskVulkanYcbcr *ycbcr0,
GskVulkanYcbcr *ycbcr1);
VkSampler gsk_vulkan_device_get_vk_sampler (GskVulkanDevice *self,
GskGpuSampler sampler) G_GNUC_PURE;
VkSamplerYcbcrConversion
gsk_vulkan_device_get_vk_conversion (GskVulkanDevice *self,
VkFormat vk_format,
VkSampler *out_sampler);
GskVulkanYcbcr * gsk_vulkan_device_get_ycbcr (GskVulkanDevice *self,
VkFormat vk_format);
void gsk_vulkan_device_remove_ycbcr (GskVulkanDevice *self,
VkFormat vk_format);
VkRenderPass gsk_vulkan_device_get_vk_render_pass (GskVulkanDevice *self,
VkFormat format,
VkImageLayout from_layout,

View File

@ -5,6 +5,7 @@
#include "gskvulkanbufferprivate.h"
#include "gskvulkanframeprivate.h"
#include "gskvulkanmemoryprivate.h"
#include "gskvulkanycbcrprivate.h"
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdkdmabuftextureprivate.h"
@ -31,7 +32,7 @@ struct _GskVulkanImage
VkImageView vk_image_view;
VkFramebuffer vk_framebuffer;
VkImageView vk_framebuffer_image_view;
VkSampler vk_sampler;
GskVulkanYcbcr *ycbcr;
VkSemaphore vk_semaphore;
VkDescriptorSet vk_descriptor_sets[GSK_GPU_SAMPLER_N_SAMPLERS];
@ -1115,7 +1116,11 @@ gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
#endif
if (is_yuv)
vk_conversion = gsk_vulkan_device_get_vk_conversion (device, vk_format, &self->vk_sampler);
{
self->ycbcr = gsk_vulkan_device_get_ycbcr (device, vk_format);
gsk_vulkan_ycbcr_ref (self->ycbcr);
vk_conversion = gsk_vulkan_ycbcr_get_vk_conversion (self->ycbcr);
}
else
vk_conversion = VK_NULL_HANDLE;
@ -1290,6 +1295,8 @@ gsk_vulkan_image_finalize (GObject *object)
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])
@ -1395,12 +1402,6 @@ gsk_vulkan_image_get_vk_framebuffer (GskVulkanImage *self,
return self->vk_framebuffer;
}
VkSampler
gsk_vulkan_image_get_vk_sampler (GskVulkanImage *self)
{
return self->vk_sampler;
}
VkDescriptorSet
gsk_vulkan_image_get_vk_descriptor_set (GskVulkanImage *self,
GskGpuSampler sampler)
@ -1415,7 +1416,8 @@ gsk_vulkan_image_get_vk_descriptor_set (GskVulkanImage *self,
.descriptorPool = gsk_vulkan_device_get_vk_descriptor_pool (self->device),
.descriptorSetCount = 1,
.pSetLayouts = (VkDescriptorSetLayout[1]) {
gsk_vulkan_device_get_vk_image_set_layout (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->vk_descriptor_sets[sampler]);
@ -1430,7 +1432,8 @@ gsk_vulkan_image_get_vk_descriptor_set (GskVulkanImage *self,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &(VkDescriptorImageInfo) {
.sampler = gsk_vulkan_device_get_vk_sampler (self->device, sampler),
.sampler = self->ycbcr ? gsk_vulkan_ycbcr_get_vk_sampler (self->ycbcr)
: gsk_vulkan_device_get_vk_sampler (self->device, sampler),
.imageView = self->vk_image_view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
},
@ -1442,6 +1445,12 @@ gsk_vulkan_image_get_vk_descriptor_set (GskVulkanImage *self,
return self->vk_descriptor_sets[sampler];
}
GskVulkanYcbcr *
gsk_vulkan_image_get_ycbcr (GskVulkanImage *self)
{
return self->ycbcr;
}
VkImage
gsk_vulkan_image_get_vk_image (GskVulkanImage *self)
{

View File

@ -50,7 +50,7 @@ GdkTexture * gsk_vulkan_image_to_dmabuf_texture (GskVulk
guchar * gsk_vulkan_image_get_data (GskVulkanImage *self,
gsize *out_stride);
VkSampler gsk_vulkan_image_get_vk_sampler (GskVulkanImage *self);
GskVulkanYcbcr * gsk_vulkan_image_get_ycbcr (GskVulkanImage *self);
VkDescriptorSet gsk_vulkan_image_get_vk_descriptor_set (GskVulkanImage *self,
GskGpuSampler sampler);
VkPipelineStageFlags gsk_vulkan_image_get_vk_pipeline_stage (GskVulkanImage *self);

203
gsk/gpu/gskvulkanycbcr.c Normal file
View File

@ -0,0 +1,203 @@
#include "config.h"
#include "gskvulkanycbcrprivate.h"
#include "gskgpucacheprivate.h"
struct _GskVulkanYcbcr
{
GskGpuCached parent;
int ref_count;
VkFormat vk_format;
VkSamplerYcbcrConversion vk_conversion;
VkSampler vk_sampler;
VkDescriptorSetLayout vk_descriptor_set_layout;
VkPipelineLayout vk_pipeline_layouts[2];
};
static void
gsk_vulkan_ycbcr_free (GskGpuCache *cache,
GskGpuCached *cached)
{
GskVulkanYcbcr *self = (GskVulkanYcbcr *) cached;
GskVulkanDevice *device;
VkDevice vk_device;
device = GSK_VULKAN_DEVICE (gsk_gpu_cache_get_device (cache));
vk_device = gsk_vulkan_device_get_vk_device (device);
g_assert (self->ref_count == 0);
gsk_vulkan_device_remove_ycbcr (device, self->vk_format);
vkDestroySampler (vk_device, self->vk_sampler, NULL);
vkDestroySamplerYcbcrConversion (vk_device, self->vk_conversion, NULL);
vkDestroyDescriptorSetLayout (vk_device, self->vk_descriptor_set_layout, NULL);
vkDestroyPipelineLayout (vk_device, self->vk_pipeline_layouts[0], NULL);
vkDestroyPipelineLayout (vk_device, self->vk_pipeline_layouts[1], NULL);
g_free (self);
}
static inline gboolean
gsk_gpu_cached_is_old (GskGpuCache *self,
GskGpuCached *cached,
gint64 cache_timeout,
gint64 timestamp)
{
if (cache_timeout < 0)
return -1;
else
return timestamp - cached->timestamp > cache_timeout;
}
static gboolean
gsk_vulkan_ycbcr_should_collect (GskGpuCache *cache,
GskGpuCached *cached,
gint64 cache_timeout,
gint64 timestamp)
{
GskVulkanYcbcr *self = (GskVulkanYcbcr *) cached;
if (self->ref_count > 0)
return FALSE;
return gsk_gpu_cached_is_old (cache, cached, cache_timeout, timestamp);
}
static const GskGpuCachedClass GSK_VULKAN_YCBCR_CLASS =
{
sizeof (GskVulkanYcbcr),
"Vulkan Ycbcr",
gsk_vulkan_ycbcr_free,
gsk_vulkan_ycbcr_should_collect
};
GskVulkanYcbcr *
gsk_vulkan_ycbcr_new (GskVulkanDevice *device,
VkFormat vk_format)
{
GskGpuCache *cache = gsk_gpu_device_get_cache (GSK_GPU_DEVICE (device));
VkDevice vk_device = gsk_vulkan_device_get_vk_device (device);
VkDescriptorSetLayout vk_image_set_layout;
GskVulkanYcbcr *self;
self = gsk_gpu_cached_new (cache, &GSK_VULKAN_YCBCR_CLASS);
self->vk_format = vk_format;
GSK_VK_CHECK (vkCreateSamplerYcbcrConversion, vk_device,
&(VkSamplerYcbcrConversionCreateInfo) {
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
.format = vk_format,
.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601,
.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW,
.components = (VkComponentMapping) {
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY
},
.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN,
.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN,
.chromaFilter = VK_FILTER_LINEAR,
.forceExplicitReconstruction = VK_FALSE
},
NULL,
&self->vk_conversion);
GSK_VK_CHECK (vkCreateSampler, vk_device,
&(VkSamplerCreateInfo) {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_LINEAR,
.minFilter = VK_FILTER_LINEAR,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
.unnormalizedCoordinates = VK_FALSE,
.maxAnisotropy = 1.0,
.minLod = 0.0,
.maxLod = 0.0f,
.pNext = &(VkSamplerYcbcrConversionInfo) {
.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
.conversion = self->vk_conversion
}
},
NULL,
&self->vk_sampler);
GSK_VK_CHECK (vkCreateDescriptorSetLayout, vk_device,
&(VkDescriptorSetLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 1,
.flags = 0,
.pBindings = (VkDescriptorSetLayoutBinding[1]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = (VkSampler[1]) {
self->vk_sampler,
},
}
},
},
NULL,
&self->vk_descriptor_set_layout);
vk_image_set_layout = gsk_vulkan_device_get_vk_image_set_layout (device);
self->vk_pipeline_layouts[0] = gsk_vulkan_device_create_vk_pipeline_layout (device,
self->vk_descriptor_set_layout,
vk_image_set_layout);
self->vk_pipeline_layouts[1] = gsk_vulkan_device_create_vk_pipeline_layout (device,
vk_image_set_layout,
self->vk_descriptor_set_layout);
return self;
}
GskVulkanYcbcr *
gsk_vulkan_ycbcr_ref (GskVulkanYcbcr *self)
{
self->ref_count++;
return self;
}
void
gsk_vulkan_ycbcr_unref (GskVulkanYcbcr *self)
{
self->ref_count--;
}
VkSamplerYcbcrConversion
gsk_vulkan_ycbcr_get_vk_conversion (GskVulkanYcbcr *self)
{
return self->vk_conversion;
}
VkSampler
gsk_vulkan_ycbcr_get_vk_sampler (GskVulkanYcbcr *self)
{
return self->vk_sampler;
}
VkDescriptorSetLayout
gsk_vulkan_ycbcr_get_vk_descriptor_set_layout (GskVulkanYcbcr *self)
{
return self->vk_descriptor_set_layout;
}
VkPipelineLayout
gsk_vulkan_ycbcr_get_vk_pipeline_layout (GskVulkanYcbcr *self,
gsize id)
{
g_assert (id < 2);
return self->vk_pipeline_layouts[id];
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "gskvulkandeviceprivate.h"
#include "gdk/gdkvulkancontextprivate.h"
G_BEGIN_DECLS
GskVulkanYcbcr * gsk_vulkan_ycbcr_new (GskVulkanDevice *self,
VkFormat vk_format);
GskVulkanYcbcr * gsk_vulkan_ycbcr_ref (GskVulkanYcbcr *self);
void gsk_vulkan_ycbcr_unref (GskVulkanYcbcr *self);
VkSamplerYcbcrConversion
gsk_vulkan_ycbcr_get_vk_conversion (GskVulkanYcbcr *self);
VkSampler gsk_vulkan_ycbcr_get_vk_sampler (GskVulkanYcbcr *self);
VkDescriptorSetLayout gsk_vulkan_ycbcr_get_vk_descriptor_set_layout (GskVulkanYcbcr *self);
VkPipelineLayout gsk_vulkan_ycbcr_get_vk_pipeline_layout (GskVulkanYcbcr *self,
gsize id);
G_END_DECLS

View File

@ -163,6 +163,7 @@ if have_vulkan
'gpu/gskvulkanframe.c',
'gpu/gskvulkanimage.c',
'gpu/gskvulkanmemory.c',
'gpu/gskvulkanycbcr.c',
])
endif # have_vulkan