Merge branch 'wip/otte/for-vulkan' into 'main'

vulkan: Add support for different image formats

See merge request GNOME/gtk!6117
This commit is contained in:
Benjamin Otte 2023-06-19 14:30:50 +00:00
commit c40588886b
13 changed files with 878 additions and 381 deletions

View File

@ -36,6 +36,7 @@
#include "gdkglcontextprivate.h"
#include "gdkmonitorprivate.h"
#include "gdkrectangle.h"
#include "gdkvulkancontext.h"
#ifdef HAVE_EGL
#include <epoxy/egl.h>
@ -1216,6 +1217,49 @@ gdk_display_get_keymap (GdkDisplay *display)
return GDK_DISPLAY_GET_CLASS (display)->get_keymap (display);
}
/*<private>
* gdk_display_create_vulkan_context:
* @self: a `GdkDisplay`
* @error: return location for an error
*
* Creates a new `GdkVulkanContext` for use with @display.
*
* The context can not be used to draw to surfaces, it can only be
* used for custom rendering or compute.
*
* If the creation of the `GdkVulkanContext` failed, @error will be set.
*
* Returns: (transfer full): the newly created `GdkVulkanContext`, or
* %NULL on error
*/
GdkVulkanContext *
gdk_display_create_vulkan_context (GdkDisplay *self,
GError **error)
{
g_return_val_if_fail (GDK_IS_DISPLAY (self), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
if (gdk_display_get_debug_flags (self) & GDK_DEBUG_VULKAN_DISABLE)
{
g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE,
_("Vulkan support disabled via GDK_DEBUG"));
return NULL;
}
if (GDK_DISPLAY_GET_CLASS (self)->vk_extension_name == NULL)
{
g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
"The %s backend has no Vulkan support.", G_OBJECT_TYPE_NAME (self));
return FALSE;
}
return g_initable_new (GDK_DISPLAY_GET_CLASS (self)->vk_context_type,
NULL,
error,
"display", self,
NULL);
}
static void
gdk_display_init_gl (GdkDisplay *self)
{

View File

@ -202,6 +202,9 @@ gulong _gdk_display_get_next_serial (GdkDisplay *display
void _gdk_display_pause_events (GdkDisplay *display);
void _gdk_display_unpause_events (GdkDisplay *display);
GdkVulkanContext * gdk_display_create_vulkan_context (GdkDisplay *self,
GError **error);
GdkGLContext * gdk_display_get_gl_context (GdkDisplay *display);
gboolean gdk_display_init_egl (GdkDisplay *display,

View File

@ -47,7 +47,11 @@ typedef struct _GdkVulkanContextPrivate GdkVulkanContextPrivate;
struct _GdkVulkanContextPrivate {
#ifdef GDK_RENDERING_VULKAN
VkSurfaceKHR surface;
VkSurfaceFormatKHR image_format;
struct {
VkSurfaceFormatKHR vk_format;
GdkMemoryFormat gdk_format;
} formats[4];
GdkMemoryDepth current_format;
VkSwapchainKHR swapchain;
VkSemaphore draw_semaphore;
@ -429,8 +433,8 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
.minImageCount = CLAMP (4,
capabilities.minImageCount,
capabilities.maxImageCount ? capabilities.maxImageCount : G_MAXUINT32),
.imageFormat = priv->image_format.format,
.imageColorSpace = priv->image_format.colorSpace,
.imageFormat = priv->formats[priv->current_format].vk_format.format,
.imageColorSpace = priv->formats[priv->current_format].vk_format.colorSpace,
.imageExtent = capabilities.currentExtent,
.imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
@ -499,19 +503,20 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
}
static gboolean
device_supports_incremental_present (VkPhysicalDevice device)
physical_device_supports_extension (VkPhysicalDevice device,
const char *extension_name)
{
VkExtensionProperties *extensions;
uint32_t n_device_extensions;
vkEnumerateDeviceExtensionProperties (device, NULL, &n_device_extensions, NULL);
GDK_VK_CHECK (vkEnumerateDeviceExtensionProperties, device, NULL, &n_device_extensions, NULL);
extensions = g_newa (VkExtensionProperties, n_device_extensions);
vkEnumerateDeviceExtensionProperties (device, NULL, &n_device_extensions, extensions);
GDK_VK_CHECK (vkEnumerateDeviceExtensionProperties, device, NULL, &n_device_extensions, extensions);
for (uint32_t i = 0; i < n_device_extensions; i++)
{
if (g_str_equal (extensions[i].extensionName, VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME))
if (g_str_equal (extensions[i].extensionName, extension_name))
return TRUE;
}
@ -527,6 +532,20 @@ gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
guint i;
if (depth != priv->current_format)
{
if (priv->formats[depth].gdk_format != priv->formats[priv->current_format].gdk_format)
{
GError *error = NULL;
if (!gdk_vulkan_context_check_swapchain (context, &error))
{
g_warning ("%s", error->message);
g_error_free (error);
return;
}
}
priv->current_format = depth;
}
for (i = 0; i < priv->n_images; i++)
{
cairo_region_union (priv->regions[i], region);
@ -665,6 +684,7 @@ gdk_vulkan_context_real_init (GInitable *initable,
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (initable);
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
VkResult res;
VkBool32 supported;
uint32_t i;
@ -673,6 +693,17 @@ gdk_vulkan_context_real_init (GInitable *initable,
if (!priv->vulkan_ref)
return FALSE;
if (surface == NULL)
{
for (i = 0; i < G_N_ELEMENTS (priv->formats); i++)
{
priv->formats[i].vk_format.format = VK_FORMAT_B8G8R8A8_UNORM;
priv->formats[i].vk_format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
priv->formats[i].gdk_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED;
}
return TRUE;
}
res = GDK_VULKAN_CONTEXT_GET_CLASS (context)->create_surface (context, &priv->surface);
if (res != VK_SUCCESS)
{
@ -707,17 +738,73 @@ gdk_vulkan_context_real_init (GInitable *initable,
&n_formats, formats);
for (i = 0; i < n_formats; i++)
{
if (formats[i].format == VK_FORMAT_B8G8R8A8_UNORM)
break;
if (formats[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
continue;
switch ((int) formats[i].format)
{
case VK_FORMAT_B8G8R8A8_UNORM:
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED)
{
priv->formats[GDK_MEMORY_U8].vk_format = formats[i];
priv->formats[GDK_MEMORY_U8].gdk_format = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED;
};
break;
case VK_FORMAT_R8G8B8A8_UNORM:
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED)
{
priv->formats[GDK_MEMORY_U8].vk_format = formats[i];
priv->formats[GDK_MEMORY_U8].gdk_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
}
break;
case VK_FORMAT_R16G16B16A16_UNORM:
priv->formats[GDK_MEMORY_U16].vk_format = formats[i];
priv->formats[GDK_MEMORY_U16].gdk_format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
break;
case VK_FORMAT_R16G16B16A16_SFLOAT:
priv->formats[GDK_MEMORY_FLOAT16].vk_format = formats[i];
priv->formats[GDK_MEMORY_FLOAT16].gdk_format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
break;
case VK_FORMAT_R32G32B32A32_SFLOAT:
priv->formats[GDK_MEMORY_FLOAT32].vk_format = formats[i];
priv->formats[GDK_MEMORY_FLOAT32].gdk_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
break;
default:
break;
}
}
if (i == n_formats)
if (priv->formats[GDK_MEMORY_U8].vk_format.format == VK_FORMAT_UNDEFINED)
{
g_set_error_literal (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_NOT_AVAILABLE,
"No supported image format found.");
goto out_surface;
}
priv->image_format = formats[i];
priv->has_present_region = device_supports_incremental_present (display->vk_physical_device);
/* Ensure all the formats exist:
* - If a format was found, keep that one.
* - FLOAT32 chooses the best format we have.
* - FLOAT16 and U16 pick the format FLOAT32 uses
*/
if (priv->formats[GDK_MEMORY_FLOAT32].vk_format.format == VK_FORMAT_UNDEFINED)
{
if (priv->formats[GDK_MEMORY_FLOAT16].vk_format.format != VK_FORMAT_UNDEFINED)
priv->formats[GDK_MEMORY_FLOAT32] = priv->formats[GDK_MEMORY_FLOAT16];
else if (priv->formats[GDK_MEMORY_U16].vk_format.format != VK_FORMAT_UNDEFINED)
priv->formats[GDK_MEMORY_FLOAT32] = priv->formats[GDK_MEMORY_U16];
else
priv->formats[GDK_MEMORY_FLOAT32] = priv->formats[GDK_MEMORY_U8];
}
if (priv->formats[GDK_MEMORY_FLOAT16].vk_format.format == VK_FORMAT_UNDEFINED)
priv->formats[GDK_MEMORY_FLOAT16] = priv->formats[GDK_MEMORY_FLOAT32];
if (priv->formats[GDK_MEMORY_U16].vk_format.format == VK_FORMAT_UNDEFINED)
priv->formats[GDK_MEMORY_U16] = priv->formats[GDK_MEMORY_FLOAT32];
priv->has_present_region = physical_device_supports_extension (display->vk_physical_device,
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
if (!gdk_vulkan_context_check_swapchain (context, error))
goto out_surface;
@ -843,7 +930,7 @@ gdk_vulkan_context_get_image_format (GdkVulkanContext *context)
g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), VK_FORMAT_UNDEFINED);
return priv->image_format.format;
return priv->formats[priv->current_format].vk_format.format;
}
/**
@ -1039,6 +1126,10 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
for (i = first; i < last; i++)
{
uint32_t n_queue_props;
if (!physical_device_supports_extension (devices[i], VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
continue;
vkGetPhysicalDeviceQueueFamilyProperties (devices[i], &n_queue_props, NULL);
VkQueueFamilyProperties *queue_props = g_newa (VkQueueFamilyProperties, n_queue_props);
vkGetPhysicalDeviceQueueFamilyProperties (devices[i], &n_queue_props, queue_props);
@ -1049,7 +1140,8 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
GPtrArray *device_extensions;
gboolean has_incremental_present;
has_incremental_present = device_supports_incremental_present (devices[i]);
has_incremental_present = physical_device_supports_extension (devices[i],
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
device_extensions = g_ptr_array_new ();
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_SWAPCHAIN_EXTENSION_NAME);

View File

@ -72,18 +72,16 @@ gsk_vulkan_buffer_new_storage (GdkVulkanContext *context,
}
GskVulkanBuffer *
gsk_vulkan_buffer_new_staging (GdkVulkanContext *context,
gsize size)
gsk_vulkan_buffer_new_map (GdkVulkanContext *context,
gsize size,
GskVulkanMapMode mode)
{
return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
return gsk_vulkan_buffer_new_internal (context,
size,
(mode & GSK_VULKAN_READ ? VK_BUFFER_USAGE_TRANSFER_SRC_BIT : 0) |
(mode & GSK_VULKAN_WRITE ? VK_BUFFER_USAGE_TRANSFER_DST_BIT : 0));
}
GskVulkanBuffer *
gsk_vulkan_buffer_new_download (GdkVulkanContext *context,
gsize size)
{
return gsk_vulkan_buffer_new_internal (context, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
}
void
gsk_vulkan_buffer_free (GskVulkanBuffer *self)
{

View File

@ -6,14 +6,20 @@ G_BEGIN_DECLS
typedef struct _GskVulkanBuffer GskVulkanBuffer;
typedef enum
{
GSK_VULKAN_READ = (1 << 0),
GSK_VULKAN_WRITE = (1 << 1),
GSK_VULKAN_READWRITE = GSK_VULKAN_READ | GSK_VULKAN_WRITE
} GskVulkanMapMode;
GskVulkanBuffer * gsk_vulkan_buffer_new (GdkVulkanContext *context,
gsize size);
GskVulkanBuffer * gsk_vulkan_buffer_new_storage (GdkVulkanContext *context,
gsize size);
GskVulkanBuffer * gsk_vulkan_buffer_new_staging (GdkVulkanContext *context,
gsize size);
GskVulkanBuffer * gsk_vulkan_buffer_new_download (GdkVulkanContext *context,
gsize size);
GskVulkanBuffer * gsk_vulkan_buffer_new_map (GdkVulkanContext *context,
gsize size,
GskVulkanMapMode mode);
void gsk_vulkan_buffer_free (GskVulkanBuffer *buffer);
VkBuffer gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self);

View File

@ -6,6 +6,10 @@
#include "gskvulkanmemoryprivate.h"
#include "gskvulkanpipelineprivate.h"
#include "gdk/gdkmemoryformatprivate.h"
#include "gskrendernodeprivate.h"
#include <string.h>
struct _GskVulkanUploader
@ -30,6 +34,8 @@ struct _GskVulkanImage
GdkVulkanContext *vulkan;
GdkMemoryFormat format;
VkFormat vk_format;
gsize width;
gsize height;
VkImageUsageFlags vk_usage;
@ -196,8 +202,353 @@ gsk_vulkan_uploader_reset (GskVulkanUploader *self)
self->staging_buffer_free_list = NULL;
}
typedef struct _GskMemoryFormatInfo GskMemoryFormatInfo;
struct _GskMemoryFormatInfo
{
VkFormat format;
VkComponentMapping components;
};
static const GskMemoryFormatInfo *
gsk_memory_format_get_vk_format_infos (GdkMemoryFormat format)
{
#define SWIZZLE(a, b, c, d) { VK_COMPONENT_SWIZZLE_ ## a, VK_COMPONENT_SWIZZLE_ ## b, VK_COMPONENT_SWIZZLE_ ## c, VK_COMPONENT_SWIZZLE_ ## d }
#define DEFAULT_SWIZZLE SWIZZLE (R, G, B, A)
switch (format)
{
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_B8G8R8A8_UNORM, DEFAULT_SWIZZLE },
{ VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(B, G, R, A) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R8G8B8A8_UNORM, SWIZZLE(G, B, A, R) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R8G8B8A8_UNORM, DEFAULT_SWIZZLE },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
#if 0
GDK_MEMORY_B8G8R8A8,
GDK_MEMORY_A8R8G8B8,
GDK_MEMORY_R8G8B8A8,
GDK_MEMORY_A8B8G8R8,
#endif
case GDK_MEMORY_R8G8B8:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R8G8B8_UNORM, DEFAULT_SWIZZLE },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_B8G8R8:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_B8G8R8_UNORM, DEFAULT_SWIZZLE },
{ VK_FORMAT_R8G8B8_UNORM, SWIZZLE(B, G, R, A) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_R16G16B16:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R16G16B16_UNORM, DEFAULT_SWIZZLE },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R16G16B16A16_UNORM, DEFAULT_SWIZZLE },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
#if 0
GDK_MEMORY_R16G16B16A16,
#endif
case GDK_MEMORY_R16G16B16_FLOAT:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R16G16B16_SFLOAT, DEFAULT_SWIZZLE },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R16G16B16A16_SFLOAT, DEFAULT_SWIZZLE },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
#if 0
GDK_MEMORY_R16G16B16A16_FLOAT,
#endif
case GDK_MEMORY_R32G32B32_FLOAT:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R32G32B32_SFLOAT, DEFAULT_SWIZZLE },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R32G32B32A32_SFLOAT, DEFAULT_SWIZZLE },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
#if 0
GDK_MEMORY_R32G32B32A32_FLOAT,
#endif
case GDK_MEMORY_G8A8_PREMULTIPLIED:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R8G8_UNORM, SWIZZLE (R, R, R, G) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
#if 0
GDK_MEMORY_G8A8,
#endif
case GDK_MEMORY_G8:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R8_UNORM, SWIZZLE (R, R, R, ONE) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_G16A16_PREMULTIPLIED:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R16G16_UNORM, SWIZZLE (R, R, R, G) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
#if 0
GDK_MEMORY_G16A16
#endif
case GDK_MEMORY_G16:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R16_UNORM, SWIZZLE (R, R, R, ONE) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_A8:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R8_UNORM, SWIZZLE (R, R, R, R) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_A16:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_R16_UNORM, SWIZZLE (R, R, R, R) },
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
case GDK_MEMORY_R16G16B16A16:
case GDK_MEMORY_R16G16B16A16_FLOAT:
case GDK_MEMORY_R32G32B32A32_FLOAT:
case GDK_MEMORY_G8A8:
case GDK_MEMORY_G16A16:
{
static const GskMemoryFormatInfo info[] = {
{ VK_FORMAT_UNDEFINED }
};
return info;
}
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
return NULL;
}
#undef DEFAULT_SWIZZLE
#undef SWIZZLE
}
static GdkMemoryFormat
gsk_memory_format_get_fallback (GdkMemoryFormat format)
{
switch (format)
{
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_B8G8R8A8:
return GDK_MEMORY_B8G8R8A8_PREMULTIPLIED;
case GDK_MEMORY_A8R8G8B8:
return GDK_MEMORY_A8R8G8B8_PREMULTIPLIED;
case GDK_MEMORY_R8G8B8A8:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_A8B8G8R8:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_R8G8B8:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_B8G8R8:
return GDK_MEMORY_R8G8B8;
case GDK_MEMORY_R16G16B16:
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
case GDK_MEMORY_R16G16B16A16:
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
case GDK_MEMORY_R16G16B16_FLOAT:
return GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
case GDK_MEMORY_R16G16B16A16_FLOAT:
return GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
case GDK_MEMORY_R32G32B32_FLOAT:
return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_R32G32B32A32_FLOAT:
return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
case GDK_MEMORY_G8A8_PREMULTIPLIED:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_G8A8:
return GDK_MEMORY_G8A8_PREMULTIPLIED;
case GDK_MEMORY_G8:
return GDK_MEMORY_R8G8B8;
case GDK_MEMORY_G16A16_PREMULTIPLIED:
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
case GDK_MEMORY_G16A16:
return GDK_MEMORY_G16A16_PREMULTIPLIED;
case GDK_MEMORY_G16:
return GDK_MEMORY_R16G16B16;
case GDK_MEMORY_A8:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_A16:
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
case GDK_MEMORY_N_FORMATS:
default:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
}
}
GdkMemoryFormat
gsk_render_node_get_preferred_vulkan_format (GskRenderNode *node)
{
switch (gsk_render_node_get_preferred_depth (node))
{
case GDK_MEMORY_U8:
return GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
case GDK_MEMORY_U16:
return GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
case GDK_MEMORY_FLOAT16:
return GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
case GDK_MEMORY_FLOAT32:
return GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
default:
g_return_val_if_reached (GDK_MEMORY_R8G8B8A8_PREMULTIPLIED);
}
}
static gboolean
gsk_vulkan_context_supports_format (GdkVulkanContext *context,
VkFormat format)
{
VkFormatProperties properties;
vkGetPhysicalDeviceFormatProperties (gdk_vulkan_context_get_physical_device (context),
format,
&properties);
if ((properties.linearTilingFeatures & (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)) &&
(properties.optimalTilingFeatures & (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)))
return TRUE;
return FALSE;
}
static void
gsk_vulkan_image_create_view (GskVulkanImage *self,
const GskMemoryFormatInfo *format)
{
GSK_VK_CHECK (vkCreateImageView, gdk_vulkan_context_get_device (self->vulkan),
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = self->vk_image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format->format,
.components = format->components,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
NULL,
&self->vk_image_view);
}
static GskVulkanImage *
gsk_vulkan_image_new (GdkVulkanContext *context,
GdkMemoryFormat format,
gsize width,
gsize height,
VkImageTiling tiling,
@ -208,12 +559,30 @@ gsk_vulkan_image_new (GdkVulkanContext *context,
{
VkMemoryRequirements requirements;
GskVulkanImage *self;
const GskMemoryFormatInfo *vk_format;
g_assert (width > 0 && height > 0);
while (TRUE)
{
for (vk_format = gsk_memory_format_get_vk_format_infos (format);
vk_format->format != VK_FORMAT_UNDEFINED;
vk_format++)
{
if (gsk_vulkan_context_supports_format (context, vk_format->format))
break;
}
if (vk_format->format != VK_FORMAT_UNDEFINED)
break;
format = gsk_memory_format_get_fallback (format);
}
self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
self->vulkan = g_object_ref (context);
self->format = format;
self->vk_format = vk_format->format;
self->width = width;
self->height = height;
self->vk_usage = usage;
@ -225,7 +594,7 @@ gsk_vulkan_image_new (GdkVulkanContext *context,
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.flags = 0,
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_B8G8R8A8_UNORM,
.format = vk_format->format,
.extent = { width, height, 1 },
.mipLevels = 1,
.arrayLayers = 1,
@ -251,36 +620,10 @@ gsk_vulkan_image_new (GdkVulkanContext *context,
self->vk_image,
gsk_vulkan_memory_get_device_memory (self->memory),
0);
return self;
}
static void
gsk_vulkan_image_ensure_view (GskVulkanImage *self,
VkFormat format)
{
if (self->vk_image_view == VK_NULL_HANDLE)
GSK_VK_CHECK (vkCreateImageView, gdk_vulkan_context_get_device (self->vulkan),
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = self->vk_image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format,
.components = {
.r = VK_COMPONENT_SWIZZLE_R,
.g = VK_COMPONENT_SWIZZLE_G,
.b = VK_COMPONENT_SWIZZLE_B,
.a = VK_COMPONENT_SWIZZLE_A,
},
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
NULL,
&self->vk_image_view);
gsk_vulkan_image_create_view (self, vk_format);
return self;
}
GskVulkanImage *
@ -293,9 +636,11 @@ gsk_vulkan_image_new_from_texture (GskVulkanUploader *uploader,
downloader = gdk_texture_downloader_new (texture);
result = gsk_vulkan_image_new_for_upload (uploader,
gdk_texture_get_format (texture),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
gsk_vulkan_image_map_memory (result, uploader, &map);
gdk_texture_downloader_set_format (downloader, result->format);
gsk_vulkan_image_map_memory (result, uploader, GSK_VULKAN_WRITE, &map);
gdk_texture_downloader_download_into (downloader, map.data, map.stride);
gsk_vulkan_image_unmap_memory (result, uploader, &map);
gdk_texture_downloader_free (downloader);
@ -304,12 +649,14 @@ gsk_vulkan_image_new_from_texture (GskVulkanUploader *uploader,
GskVulkanImage *
gsk_vulkan_image_new_for_upload (GskVulkanUploader *uploader,
GdkMemoryFormat format,
gsize width,
gsize height)
{
GskVulkanImage *self;
self = gsk_vulkan_image_new (uploader->vulkan,
format,
width,
height,
VK_IMAGE_TILING_LINEAR,
@ -319,19 +666,34 @@ gsk_vulkan_image_new_for_upload (GskVulkanUploader *uploader,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
static void
gsk_vulkan_image_map_memory_direct (GskVulkanImage *self,
GskVulkanUploader *uploader,
GskVulkanMapMode mode,
GskVulkanImageMap *map)
{
VkImageSubresource image_res;
VkSubresourceLayout image_layout;
if (self->vk_image_layout != VK_IMAGE_LAYOUT_PREINITIALIZED)
{
gsk_vulkan_uploader_add_image_barrier (uploader,
FALSE,
self,
VK_IMAGE_LAYOUT_GENERAL,
(mode & GSK_VULKAN_READ ? VK_ACCESS_MEMORY_READ_BIT : 0) |
(mode & GSK_VULKAN_WRITE ? VK_ACCESS_MEMORY_WRITE_BIT : 0));
if (mode & GSK_VULKAN_READ)
{
gsk_vulkan_uploader_upload (uploader);
GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
}
}
image_res.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
image_res.mipLevel = 0;
image_res.arrayLayer = 0;
@ -339,6 +701,7 @@ gsk_vulkan_image_map_memory_direct (GskVulkanImage *self,
vkGetImageSubresourceLayout (gdk_vulkan_context_get_device (self->vulkan),
self->vk_image, &image_res, &image_layout);
map->mode = mode;
map->staging_buffer = NULL;
map->data = gsk_vulkan_memory_map (self->memory) + image_layout.offset;
map->stride = image_layout.rowPitch;
@ -361,13 +724,52 @@ gsk_vulkan_image_unmap_memory_direct (GskVulkanImage *self,
static void
gsk_vulkan_image_map_memory_indirect (GskVulkanImage *self,
GskVulkanUploader *uploader,
GskVulkanMapMode mode,
GskVulkanImageMap *map)
{
gsize buffer_size = self->width * self->height * 4;
map->mode = mode;
map->stride = self->width * gdk_memory_format_bytes_per_pixel (self->format);
map->staging_buffer = gsk_vulkan_buffer_new_map (uploader->vulkan, self->height * map->stride, mode);
if (self->vk_image_layout != VK_IMAGE_LAYOUT_PREINITIALIZED)
{
if (mode & GSK_VULKAN_READ)
{
gsk_vulkan_uploader_add_image_barrier (uploader,
FALSE,
self,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT);
vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
self->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
gsk_vulkan_buffer_get_buffer (map->staging_buffer),
1,
(VkBufferImageCopy[1]) {
{
.bufferOffset = 0,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.imageOffset = { 0, 0, 0 },
.imageExtent = {
.width = self->width,
.height = self->height,
.depth = 1
}
}
});
gsk_vulkan_uploader_upload (uploader);
GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
}
}
map->staging_buffer = gsk_vulkan_buffer_new_staging (uploader->vulkan, buffer_size);
map->data = gsk_vulkan_buffer_map (map->staging_buffer);
map->stride = self->width * 4;
}
static void
@ -377,70 +779,75 @@ gsk_vulkan_image_unmap_memory_indirect (GskVulkanImage *self,
{
gsk_vulkan_buffer_unmap (map->staging_buffer);
gsk_vulkan_uploader_add_buffer_barrier (uploader,
FALSE,
&(VkBufferMemoryBarrier) {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = gsk_vulkan_buffer_get_buffer (map->staging_buffer),
.offset = 0,
.size = VK_WHOLE_SIZE,
});
if (map->mode & GSK_VULKAN_WRITE)
{
gsk_vulkan_uploader_add_buffer_barrier (uploader,
FALSE,
&(VkBufferMemoryBarrier) {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = gsk_vulkan_buffer_get_buffer (map->staging_buffer),
.offset = 0,
.size = VK_WHOLE_SIZE,
});
gsk_vulkan_uploader_add_image_barrier (uploader,
FALSE,
self,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT);
gsk_vulkan_uploader_add_image_barrier (uploader,
FALSE,
self,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_ACCESS_TRANSFER_WRITE_BIT);
vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
gsk_vulkan_buffer_get_buffer (map->staging_buffer),
self->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
(VkBufferImageCopy[1]) {
{
.bufferOffset = 0,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.imageOffset = { 0, 0, 0 },
.imageExtent = {
.width = self->width,
.height = self->height,
.depth = 1
vkCmdCopyBufferToImage (gsk_vulkan_uploader_get_copy_buffer (uploader),
gsk_vulkan_buffer_get_buffer (map->staging_buffer),
self->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
(VkBufferImageCopy[1]) {
{
.bufferOffset = 0,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.imageOffset = { 0, 0, 0 },
.imageExtent = {
.width = self->width,
.height = self->height,
.depth = 1
}
}
}
});
});
uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list,
map->staging_buffer);
}
else
{
gsk_vulkan_buffer_free (map->staging_buffer);
}
gsk_vulkan_uploader_add_image_barrier (uploader,
TRUE,
self,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_ACCESS_SHADER_READ_BIT);
uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list,
map->staging_buffer);
}
void
gsk_vulkan_image_map_memory (GskVulkanImage *self,
GskVulkanUploader *uploader,
GskVulkanMapMode mode,
GskVulkanImageMap *map)
{
g_assert (self->vk_image_layout == VK_IMAGE_LAYOUT_UNDEFINED ||
self->vk_image_layout == VK_IMAGE_LAYOUT_PREINITIALIZED);
if (!GSK_DEBUG_CHECK (STAGING) && gsk_vulkan_memory_can_map (self->memory, TRUE))
gsk_vulkan_image_map_memory_direct (self, uploader, map);
gsk_vulkan_image_map_memory_direct (self, uploader, mode, map);
else
gsk_vulkan_image_map_memory_indirect (self, uploader, map);
gsk_vulkan_image_map_memory_indirect (self, uploader, mode, map);
}
void
@ -469,29 +876,17 @@ gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
self->width = width;
self->height = height;
self->vk_image = image;
self->vk_format = format;
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
GskVulkanImage *
gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
gsize width,
gsize height)
{
GskVulkanImage *self;
self = gsk_vulkan_image_new (context,
width,
height,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
gsk_vulkan_image_create_view (self,
&(GskMemoryFormatInfo) {
format,
{ VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_G,
VK_COMPONENT_SWIZZLE_B,
VK_COMPONENT_SWIZZLE_A
}
});
return self;
}
@ -504,6 +899,7 @@ gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
GskVulkanImage *self;
self = gsk_vulkan_image_new (context,
GDK_MEMORY_DEFAULT,
width,
height,
VK_IMAGE_TILING_OPTIMAL,
@ -512,22 +908,22 @@ gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
0,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
GskVulkanImage *
gsk_vulkan_image_new_for_offscreen (GdkVulkanContext *context,
GdkMemoryFormat preferred_format,
gsize width,
gsize height)
{
GskVulkanImage *self;
self = gsk_vulkan_image_new (context,
preferred_format,
width,
height,
VK_IMAGE_TILING_OPTIMAL,
VK_IMAGE_TILING_LINEAR,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
@ -535,8 +931,6 @@ gsk_vulkan_image_new_for_offscreen (GdkVulkanContext *context,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
return self;
}
@ -544,54 +938,18 @@ GdkTexture *
gsk_vulkan_image_download (GskVulkanImage *self,
GskVulkanUploader *uploader)
{
GskVulkanBuffer *buffer;
GskVulkanImageMap map;
GdkTexture *texture;
GBytes *bytes;
guchar *mem;
gsk_vulkan_uploader_add_image_barrier (uploader,
FALSE,
self,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_ACCESS_TRANSFER_READ_BIT);
buffer = gsk_vulkan_buffer_new_download (self->vulkan, self->width * self->height * 4);
vkCmdCopyImageToBuffer (gsk_vulkan_uploader_get_copy_buffer (uploader),
self->vk_image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
gsk_vulkan_buffer_get_buffer (buffer),
1,
(VkBufferImageCopy[1]) {
{
.bufferOffset = 0,
.imageSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.imageOffset = { 0, 0, 0 },
.imageExtent = {
.width = self->width,
.height = self->height,
.depth = 1
}
}
});
gsk_vulkan_uploader_upload (uploader);
GSK_VK_CHECK (vkQueueWaitIdle, gdk_vulkan_context_get_queue (self->vulkan));
mem = gsk_vulkan_buffer_map (buffer);
bytes = g_bytes_new (mem, self->width * self->height * 4);
gsk_vulkan_image_map_memory (self, uploader, GSK_VULKAN_READ, &map);
bytes = g_bytes_new (map.data, map.stride * self->height);
texture = gdk_memory_texture_new (self->width, self->height,
GDK_MEMORY_DEFAULT,
self->format,
bytes,
self->width * 4);
gsk_vulkan_buffer_unmap (buffer);
gsk_vulkan_buffer_free (buffer);
map.stride);
g_bytes_unref (bytes);
gsk_vulkan_image_unmap_memory (self, uploader, &map);
return texture;
}
@ -613,7 +971,7 @@ gsk_vulkan_image_upload_regions (GskVulkanImage *self,
for (int i = 0; i < num_regions; i++)
size += regions[i].width * regions[i].height * 4;
staging = gsk_vulkan_buffer_new_staging (uploader->vulkan, size);
staging = gsk_vulkan_buffer_new_map (uploader->vulkan, size, GSK_VULKAN_WRITE);
mem = gsk_vulkan_buffer_map (staging);
bufferImageCopy = alloca (sizeof (VkBufferImageCopy) * num_regions);
@ -672,8 +1030,6 @@ gsk_vulkan_image_upload_regions (GskVulkanImage *self,
VK_ACCESS_SHADER_READ_BIT);
uploader->staging_buffer_free_list = g_slist_prepend (uploader->staging_buffer_free_list, staging);
gsk_vulkan_image_ensure_view (self, VK_FORMAT_B8G8R8A8_UNORM);
}
static void
@ -738,3 +1094,9 @@ gsk_vulkan_image_get_image_view (GskVulkanImage *self)
{
return self->vk_image_view;
}
VkFormat
gsk_vulkan_image_get_vk_format (GskVulkanImage *self)
{
return self->vk_format;
}

View File

@ -1,9 +1,12 @@
#pragma once
#include <gdk/gdk.h>
#include <gsk/gskrendernode.h>
#include "gskvulkanbufferprivate.h"
#include "gskvulkancommandpoolprivate.h"
G_BEGIN_DECLS
typedef struct _GskVulkanUploader GskVulkanUploader;
@ -19,6 +22,8 @@ void gsk_vulkan_uploader_free (GskVulk
void gsk_vulkan_uploader_reset (GskVulkanUploader *self);
void gsk_vulkan_uploader_upload (GskVulkanUploader *self);
GdkMemoryFormat gsk_render_node_get_preferred_vulkan_format (GskRenderNode *node);
GskVulkanImage * gsk_vulkan_image_new_for_swapchain (GdkVulkanContext *context,
VkImage image,
VkFormat format,
@ -40,13 +45,11 @@ void gsk_vulkan_image_upload_regions (GskVulk
GskVulkanUploader *uploader,
guint num_regions,
GskImageRegion *regions);
GskVulkanImage * gsk_vulkan_image_new_for_framebuffer (GdkVulkanContext *context,
gsize width,
gsize height);
GskVulkanImage * gsk_vulkan_image_new_for_atlas (GdkVulkanContext *context,
gsize width,
gsize height);
GskVulkanImage * gsk_vulkan_image_new_for_offscreen (GdkVulkanContext *context,
GdkMemoryFormat preferred_format,
gsize width,
gsize height);
@ -58,17 +61,20 @@ typedef struct _GskVulkanImageMap GskVulkanImageMap;
struct _GskVulkanImageMap
{
guchar *data;
gsize stride;
gsize stride;
GskVulkanMapMode mode;
/* private */
gpointer staging_buffer;
GskVulkanBuffer *staging_buffer;
};
GskVulkanImage * gsk_vulkan_image_new_for_upload (GskVulkanUploader *uploader,
GdkMemoryFormat format,
gsize width,
gsize height);
void gsk_vulkan_image_map_memory (GskVulkanImage *self,
GskVulkanUploader *uploader,
GskVulkanMapMode mode,
GskVulkanImageMap *map);
void gsk_vulkan_image_unmap_memory (GskVulkanImage *self,
GskVulkanUploader *uploader,
@ -78,6 +84,7 @@ gsize gsk_vulkan_image_get_width (GskVulk
gsize gsk_vulkan_image_get_height (GskVulkanImage *self);
VkImage gsk_vulkan_image_get_image (GskVulkanImage *self);
VkImageView gsk_vulkan_image_get_image_view (GskVulkanImage *self);
VkFormat gsk_vulkan_image_get_vk_format (GskVulkanImage *self);
G_END_DECLS

View File

@ -50,10 +50,8 @@ struct _GskVulkanRender
graphene_rect_t viewport;
cairo_region_t *clip;
GHashTable *framebuffers;
GskVulkanCommandPool *command_pool;
VkFence fence;
VkRenderPass render_pass;
VkDescriptorSetLayout descriptor_set_layout;
VkPipelineLayout pipeline_layout;
GskVulkanUploader *uploader;
@ -131,7 +129,6 @@ gsk_vulkan_render_new (GskRenderer *renderer,
self->vulkan = context;
self->renderer = renderer;
self->framebuffers = g_hash_table_new (g_direct_hash, g_direct_equal);
gsk_descriptor_image_infos_init (&self->descriptor_images);
gsk_descriptor_image_infos_init (&self->descriptor_samplers);
gsk_descriptor_buffer_infos_init (&self->descriptor_buffers);
@ -171,46 +168,6 @@ gsk_vulkan_render_new (GskRenderer *renderer,
NULL,
&self->descriptor_pool);
GSK_VK_CHECK (vkCreateRenderPass, gdk_vulkan_context_get_device (self->vulkan),
&(VkRenderPassCreateInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = (VkAttachmentDescription[]) {
{
.format = gdk_vulkan_context_get_image_format (self->vulkan),
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
}
},
.subpassCount = 1,
.pSubpasses = (VkSubpassDescription []) {
{
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.inputAttachmentCount = 0,
.colorAttachmentCount = 1,
.pColorAttachments = (VkAttachmentReference []) {
{
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
}
},
.pResolveAttachments = (VkAttachmentReference []) {
{
.attachment = VK_ATTACHMENT_UNUSED,
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
}
},
.pDepthStencilAttachment = NULL,
}
},
.dependencyCount = 0
},
NULL,
&self->render_pass);
GSK_VK_CHECK (vkCreateDescriptorSetLayout, device,
&(VkDescriptorSetLayoutCreateInfo) {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
@ -324,58 +281,6 @@ gsk_vulkan_render_new (GskRenderer *renderer,
return self;
}
typedef struct {
VkFramebuffer framebuffer;
} HashFramebufferEntry;
static void
gsk_vulkan_render_remove_framebuffer_from_image (gpointer data,
GObject *image)
{
GskVulkanRender *self = data;
HashFramebufferEntry *fb;
fb = g_hash_table_lookup (self->framebuffers, image);
g_hash_table_remove (self->framebuffers, image);
vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
fb->framebuffer,
NULL);
g_free (fb);
}
VkFramebuffer
gsk_vulkan_render_get_framebuffer (GskVulkanRender *self,
GskVulkanImage *image)
{
HashFramebufferEntry *fb;
fb = g_hash_table_lookup (self->framebuffers, image);
if (fb)
return fb->framebuffer;
fb = g_new0 (HashFramebufferEntry, 1);
GSK_VK_CHECK (vkCreateFramebuffer, gdk_vulkan_context_get_device (self->vulkan),
&(VkFramebufferCreateInfo) {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = self->render_pass,
.attachmentCount = 1,
.pAttachments = (VkImageView[1]) {
gsk_vulkan_image_get_image_view (image)
},
.width = gsk_vulkan_image_get_width (image),
.height = gsk_vulkan_image_get_height (image),
.layers = 1
},
NULL,
&fb->framebuffer);
g_hash_table_insert (self->framebuffers, image, fb);
g_object_weak_ref (G_OBJECT (image), gsk_vulkan_render_remove_framebuffer_from_image, self);
return fb->framebuffer;
}
VkFence
gsk_vulkan_render_get_fence (GskVulkanRender *self)
{
@ -441,7 +346,8 @@ gsk_vulkan_render_upload (GskVulkanRender *self)
GskVulkanPipeline *
gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
GskVulkanPipelineType type)
GskVulkanPipelineType type,
VkRenderPass render_pass)
{
static const struct {
const char *name;
@ -492,7 +398,7 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
self->pipelines[type] = pipeline_info[type].create_func (self->vulkan,
self->pipeline_layout,
pipeline_info[type].name,
self->render_pass);
render_pass);
return self->pipelines[type];
}
@ -640,6 +546,7 @@ gsk_vulkan_render_prepare_descriptor_sets (GskVulkanRender *self)
{
gsk_vulkan_buffer_unmap (self->storage_buffer);
self->storage_buffer_memory = NULL;
self->storage_buffer_used = 0;
}
GSK_VK_CHECK (vkAllocateDescriptorSets, device,
@ -810,8 +717,6 @@ gsk_vulkan_render_cleanup (GskVulkanRender *self)
void
gsk_vulkan_render_free (GskVulkanRender *self)
{
GHashTableIter iter;
gpointer key, value;
VkDevice device;
guint i;
@ -819,20 +724,6 @@ gsk_vulkan_render_free (GskVulkanRender *self)
device = gdk_vulkan_context_get_device (self->vulkan);
g_hash_table_iter_init (&iter, self->framebuffers);
while (g_hash_table_iter_next (&iter, &key, &value))
{
HashFramebufferEntry *fb = value;
vkDestroyFramebuffer (gdk_vulkan_context_get_device (self->vulkan),
fb->framebuffer,
NULL);
g_free (fb);
g_object_weak_unref (G_OBJECT (key), gsk_vulkan_render_remove_framebuffer_from_image, self);
g_hash_table_iter_remove (&iter);
}
g_hash_table_unref (self->framebuffers);
for (i = 0; i < GSK_VULKAN_N_PIPELINES; i++)
g_clear_object (&self->pipelines[i]);
@ -843,10 +734,6 @@ gsk_vulkan_render_free (GskVulkanRender *self)
self->pipeline_layout,
NULL);
vkDestroyRenderPass (device,
self->render_pass,
NULL);
vkDestroyDescriptorPool (device,
self->descriptor_pool,
NULL);

View File

@ -12,6 +12,8 @@
#include "gskvulkanrenderprivate.h"
#include "gskvulkanglyphcacheprivate.h"
#include "gdk/gdkdisplayprivate.h"
#include "gdk/gdkdrawcontextprivate.h"
#include "gdk/gdktextureprivate.h"
#include "gdk/gdkprofilerprivate.h"
@ -139,20 +141,23 @@ static void
gsk_vulkan_renderer_update_images_cb (GdkVulkanContext *context,
GskVulkanRenderer *self)
{
GdkSurface *window;
GdkSurface *surface;
double scale;
gsize width, height;
guint i;
surface = gsk_renderer_get_surface (GSK_RENDERER (self));
if (surface == NULL)
return;
gsk_vulkan_renderer_free_targets (self);
self->n_targets = gdk_vulkan_context_get_n_images (context);
self->targets = g_new (GskVulkanImage *, self->n_targets);
window = gsk_renderer_get_surface (GSK_RENDERER (self));
scale = gdk_surface_get_scale (window);
width = (int) ceil (gdk_surface_get_width (window) * scale);
height = (int) ceil (gdk_surface_get_height (window) * scale);
scale = gdk_surface_get_scale (surface);
width = (int) ceil (gdk_surface_get_width (surface) * scale);
height = (int) ceil (gdk_surface_get_height (surface) * scale);
for (i = 0; i < self->n_targets; i++)
{
@ -203,13 +208,10 @@ gsk_vulkan_renderer_realize (GskRenderer *renderer,
GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer);
if (surface == NULL)
{
g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED,
"The Vulkan renderer does not support surfaceless rendering yet.");
return FALSE;
}
self->vulkan = gdk_display_create_vulkan_context (gdk_display_get_default (), error);
else
self->vulkan = gdk_surface_create_vulkan_context (surface, error);
self->vulkan = gdk_surface_create_vulkan_context (surface, error);
if (self->vulkan == NULL)
return FALSE;
@ -283,9 +285,10 @@ gsk_vulkan_renderer_render_texture (GskRenderer *renderer,
viewport->origin.y,
ceil (viewport->size.width),
ceil (viewport->size.height));
image = gsk_vulkan_image_new_for_framebuffer (self->vulkan,
rounded_viewport.size.width,
rounded_viewport.size.height);
image = gsk_vulkan_image_new_for_offscreen (self->vulkan,
gsk_render_node_get_preferred_vulkan_format (root),
rounded_viewport.size.width,
rounded_viewport.size.height);
gsk_vulkan_render_reset (render, image, &rounded_viewport, NULL);
gsk_vulkan_render_add_node (render, root);
@ -339,7 +342,9 @@ gsk_vulkan_renderer_render (GskRenderer *renderer,
gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time);
#endif
gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->vulkan), region);
gdk_draw_context_begin_frame_full (GDK_DRAW_CONTEXT (self->vulkan),
gsk_render_node_get_preferred_depth (root),
region);
render = gsk_vulkan_renderer_get_render (self);
render_region = get_render_region (self);

View File

@ -50,5 +50,5 @@ GskRenderer * gsk_vulkan_renderer_new (void);
G_END_DECLS
#endif /* GDK_WINDOWING_VULKAN */
#endif /* GDK_RENDERING_VULKAN */

View File

@ -136,6 +136,7 @@ struct _GskVulkanRenderPass
graphene_vec2_t scale;
VkRenderPass render_pass;
VkFramebuffer framebuffer;
VkSemaphore signal_semaphore;
GArray *wait_semaphores;
GskVulkanBuffer *vertex_data;
@ -186,7 +187,7 @@ gsk_vulkan_render_pass_new (GdkVulkanContext *context,
.attachmentCount = 1,
.pAttachments = (VkAttachmentDescription[]) {
{
.format = gdk_vulkan_context_get_image_format (self->vulkan),
.format = gsk_vulkan_image_get_vk_format (target),
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
@ -220,6 +221,21 @@ gsk_vulkan_render_pass_new (GdkVulkanContext *context,
NULL,
&self->render_pass);
GSK_VK_CHECK (vkCreateFramebuffer, gdk_vulkan_context_get_device (self->vulkan),
&(VkFramebufferCreateInfo) {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = self->render_pass,
.attachmentCount = 1,
.pAttachments = (VkImageView[1]) {
gsk_vulkan_image_get_image_view (target)
},
.width = gsk_vulkan_image_get_width (target),
.height = gsk_vulkan_image_get_height (target),
.layers = 1
},
NULL,
&self->framebuffer);
self->signal_semaphore = signal_semaphore;
self->wait_semaphores = g_array_new (FALSE, FALSE, sizeof (VkSemaphore));
self->vertex_data = NULL;
@ -238,19 +254,19 @@ gsk_vulkan_render_pass_new (GdkVulkanContext *context,
void
gsk_vulkan_render_pass_free (GskVulkanRenderPass *self)
{
VkDevice device = gdk_vulkan_context_get_device (self->vulkan);
g_array_unref (self->render_ops);
g_object_unref (self->vulkan);
g_object_unref (self->target);
cairo_region_destroy (self->clip);
vkDestroyRenderPass (gdk_vulkan_context_get_device (self->vulkan),
self->render_pass,
NULL);
vkDestroyFramebuffer (device, self->framebuffer, NULL);
vkDestroyRenderPass (device, self->render_pass, NULL);
if (self->vertex_data)
gsk_vulkan_buffer_free (self->vertex_data);
if (self->signal_semaphore != VK_NULL_HANDLE)
vkDestroySemaphore (gdk_vulkan_context_get_device (self->vulkan),
self->signal_semaphore,
NULL);
vkDestroySemaphore (device, self->signal_semaphore, NULL);
g_array_unref (self->wait_semaphores);
g_free (self);
@ -297,6 +313,16 @@ gsk_vulkan_render_pass_append_push_constants (GskVulkanRenderPass *self,
return FALSE; \
}G_STMT_END
static GskVulkanPipeline *
gsk_vulkan_render_pass_get_pipeline (GskVulkanRenderPass *self,
GskVulkanRender *render,
GskVulkanPipelineType pipeline_type)
{
return gsk_vulkan_render_get_pipeline (render,
pipeline_type,
self->render_pass);
}
static void
gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
GskVulkanRender *render,
@ -333,7 +359,7 @@ gsk_vulkan_render_pass_add_fallback_node (GskVulkanRenderPass *self,
return FALSE;
}
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_TEXTURE);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, GSK_VULKAN_PIPELINE_TEXTURE);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -397,7 +423,7 @@ gsk_vulkan_render_pass_add_color_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -423,7 +449,7 @@ gsk_vulkan_render_pass_add_linear_gradient_node (GskVulkanRenderPass *self
else
pipeline_type = GSK_VULKAN_PIPELINE_LINEAR_GRADIENT_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -449,7 +475,7 @@ gsk_vulkan_render_pass_add_border_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_BORDER_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -475,7 +501,7 @@ gsk_vulkan_render_pass_add_texture_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -501,7 +527,7 @@ gsk_vulkan_render_pass_add_texture_scale_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -529,7 +555,7 @@ gsk_vulkan_render_pass_add_inset_shadow_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_INSET_SHADOW_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -557,7 +583,7 @@ gsk_vulkan_render_pass_add_outset_shadow_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_OUTSET_SHADOW_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -737,7 +763,7 @@ gsk_vulkan_render_pass_add_opacity_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -763,7 +789,7 @@ gsk_vulkan_render_pass_add_color_matrix_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_COLOR_MATRIX_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -933,7 +959,7 @@ gsk_vulkan_render_pass_add_repeat_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -959,7 +985,7 @@ gsk_vulkan_render_pass_add_blend_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -985,7 +1011,7 @@ gsk_vulkan_render_pass_add_cross_fade_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -1036,7 +1062,7 @@ gsk_vulkan_render_pass_add_text_node (GskVulkanRenderPass *self,
pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
op.type = GSK_VULKAN_OP_TEXT;
}
op.text.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.text.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
op.text.start_glyph = 0;
op.text.texture_index = G_MAXUINT;
@ -1100,7 +1126,7 @@ gsk_vulkan_render_pass_add_blur_node (GskVulkanRenderPass *self,
else
pipeline_type = GSK_VULKAN_PIPELINE_BLUR_CLIP_ROUNDED;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
op.render.pipeline = gsk_vulkan_render_pass_get_pipeline (self, render, pipeline_type);
g_array_append_val (self->render_ops, op);
return TRUE;
@ -1249,6 +1275,7 @@ gsk_vulkan_render_pass_render_offscreen (GdkVulkanContext *vulkan,
ceil (scale_y * viewport->size.height));
result = gsk_vulkan_image_new_for_offscreen (vulkan,
gsk_render_node_get_preferred_vulkan_format (node),
view.size.width, view.size.height);
#ifdef G_ENABLE_DEBUG
@ -1368,8 +1395,8 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
width = ceil (node->bounds.size.width * graphene_vec2_get_x (scale));
height = ceil (node->bounds.size.height * graphene_vec2_get_y (scale));
result = gsk_vulkan_image_new_for_upload (uploader, width, height);
gsk_vulkan_image_map_memory (result, uploader, &map);
result = gsk_vulkan_image_new_for_upload (uploader, GDK_MEMORY_DEFAULT, width, height);
gsk_vulkan_image_map_memory (result, uploader, GSK_VULKAN_WRITE, &map);
surface = cairo_image_surface_create_for_data (map.data,
CAIRO_FORMAT_ARGB32,
width, height,
@ -1429,8 +1456,8 @@ gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self,
width = ceil (node->bounds.size.width * graphene_vec2_get_x (&self->scale));
height = ceil (node->bounds.size.height * graphene_vec2_get_y (&self->scale));
op->source = gsk_vulkan_image_new_for_upload (uploader, width, height);
gsk_vulkan_image_map_memory (op->source, uploader, &map);
op->source = gsk_vulkan_image_new_for_upload (uploader, GDK_MEMORY_DEFAULT, width, height);
gsk_vulkan_image_map_memory (op->source, uploader, GSK_VULKAN_WRITE, &map);
surface = cairo_image_surface_create_for_data (map.data,
CAIRO_FORMAT_ARGB32,
width, height,
@ -2430,7 +2457,7 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
&(VkRenderPassBeginInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = self->render_pass,
.framebuffer = gsk_vulkan_render_get_framebuffer (render, self->target),
.framebuffer = self->framebuffer,
.renderArea = {
{ rect.x, rect.y },
{ rect.width, rect.height }

View File

@ -81,7 +81,8 @@ void gsk_vulkan_render_add_render_pass (GskVulk
void gsk_vulkan_render_upload (GskVulkanRender *self);
GskVulkanPipeline * gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
GskVulkanPipelineType pipeline_type);
GskVulkanPipelineType pipeline_type,
VkRenderPass render_pass);
gsize gsk_vulkan_render_get_sampler_descriptor (GskVulkanRender *self,
GskVulkanRenderSampler render_sampler);
gsize gsk_vulkan_render_get_image_descriptor (GskVulkanRender *self,

View File

@ -1,6 +1,9 @@
#include <gtk/gtk.h>
#include "gsk/gl/gskglrenderer.h"
#ifdef GDK_RENDERING_VULKAN
#include "gsk/vulkan/gskvulkanrenderer.h"
#endif
#include <epoxy/gl.h>
@ -8,6 +11,7 @@
static GdkGLContext *gl_context = NULL;
static GskRenderer *gl_renderer = NULL;
static GskRenderer *vulkan_renderer = NULL;
typedef struct _TextureBuilder TextureBuilder;
@ -16,6 +20,7 @@ typedef enum {
TEXTURE_METHOD_GL,
TEXTURE_METHOD_GL_RELEASED,
TEXTURE_METHOD_GL_NATIVE,
TEXTURE_METHOD_VULKAN,
TEXTURE_METHOD_PNG,
TEXTURE_METHOD_PNG_PIXBUF,
TEXTURE_METHOD_TIFF,
@ -431,7 +436,7 @@ encode (GdkMemoryFormat format,
return GSIZE_TO_POINTER (method * GDK_MEMORY_N_FORMATS + format);
}
static gboolean
static void
decode (gconstpointer data,
GdkMemoryFormat *format,
TextureMethod *method)
@ -442,14 +447,6 @@ decode (gconstpointer data,
value /= GDK_MEMORY_N_FORMATS;
*method = value;
if (*method == TEXTURE_METHOD_TIFF_PIXBUF)
{
g_test_skip ("the pixbuf tiff loader is broken (gdk-pixbuf#100)");
return FALSE;
}
return TRUE;
}
static gpointer
@ -805,13 +802,17 @@ compare_textures (GdkTexture *texture1,
}
static GdkTexture *
upload_to_gl (GdkTexture *texture)
upload_to_renderer (GdkTexture *texture,
GskRenderer *renderer)
{
GskRenderNode *node;
GdkTexture *result;
if (gl_renderer == NULL)
return texture;
if (renderer == NULL)
{
g_test_skip ("renderer not supported");
return texture;
}
node = gsk_texture_node_new (texture,
&GRAPHENE_RECT_INIT(
@ -819,7 +820,7 @@ upload_to_gl (GdkTexture *texture)
gdk_texture_get_width (texture),
gdk_texture_get_height (texture)
));
result = gsk_renderer_render_texture (gl_renderer, node, NULL);
result = gsk_renderer_render_texture (renderer, node, NULL);
gsk_render_node_unref (node);
g_object_unref (texture);
@ -910,7 +911,7 @@ upload_to_gl_native (GdkTexture *texture)
return result;
}
return upload_to_gl (texture);
return upload_to_renderer (texture, gl_renderer);
}
static GdkTexture *
@ -934,11 +935,11 @@ create_texture (GdkMemoryFormat format,
break;
case TEXTURE_METHOD_GL:
texture = upload_to_gl (texture);
texture = upload_to_renderer (texture, gl_renderer);
break;
case TEXTURE_METHOD_GL_RELEASED:
texture = upload_to_gl (texture);
texture = upload_to_renderer (texture, gl_renderer);
if (GDK_IS_GL_TEXTURE (texture))
gdk_gl_texture_release (GDK_GL_TEXTURE (texture));
break;
@ -947,6 +948,10 @@ create_texture (GdkMemoryFormat format,
texture = upload_to_gl_native (texture);
break;
case TEXTURE_METHOD_VULKAN:
texture = upload_to_renderer (texture, vulkan_renderer);
break;
case TEXTURE_METHOD_PNG:
{
GBytes *bytes = gdk_texture_save_to_png_bytes (texture);
@ -1030,6 +1035,7 @@ texture_method_is_accurate (TextureMethod method)
case TEXTURE_METHOD_GL:
case TEXTURE_METHOD_GL_RELEASED:
case TEXTURE_METHOD_GL_NATIVE:
case TEXTURE_METHOD_VULKAN:
case TEXTURE_METHOD_PNG:
case TEXTURE_METHOD_PNG_PIXBUF:
case TEXTURE_METHOD_TIFF_PIXBUF:
@ -1123,22 +1129,66 @@ static gboolean
should_skip_download_test (GdkMemoryFormat format,
TextureMethod method)
{
int major, minor;
switch (method)
{
case TEXTURE_METHOD_LOCAL:
case TEXTURE_METHOD_PNG:
case TEXTURE_METHOD_PNG_PIXBUF:
case TEXTURE_METHOD_TIFF:
return FALSE;
gdk_gl_context_get_version (gl_context, &major, &minor);
case TEXTURE_METHOD_GL:
case TEXTURE_METHOD_GL_RELEASED:
if (gl_renderer == NULL)
{
g_test_skip ("OpenGL renderer is not supported");
return TRUE;
}
G_GNUC_FALLTHROUGH;
if ((method == TEXTURE_METHOD_GL ||
method == TEXTURE_METHOD_GL_RELEASED ||
method == TEXTURE_METHOD_GL_NATIVE) &&
gdk_gl_context_get_use_es (gl_context) &&
(major < 3 || (major == 3 && minor < 1)) &&
gdk_memory_format_is_deep (format))
{
g_test_skip ("GLES < 3.1 can't handle 16bit non-RGBA formats");
case TEXTURE_METHOD_GL_NATIVE:
{
int major, minor;
if (gl_context == NULL)
{
g_test_skip ("OpenGL is not supported");
return TRUE;
}
gdk_gl_context_get_version (gl_context, &major, &minor);
if ((method == TEXTURE_METHOD_GL ||
method == TEXTURE_METHOD_GL_RELEASED ||
method == TEXTURE_METHOD_GL_NATIVE) &&
gdk_gl_context_get_use_es (gl_context) &&
(major < 3 || (major == 3 && minor < 1)) &&
gdk_memory_format_is_deep (format))
{
g_test_skip ("GLES < 3.1 can't handle 16bit non-RGBA formats");
return TRUE;
}
return FALSE;
}
case TEXTURE_METHOD_VULKAN:
if (vulkan_renderer == NULL)
{
g_test_skip ("Vulkan is not supported");
return TRUE;
}
return FALSE;
case TEXTURE_METHOD_TIFF_PIXBUF:
g_test_skip ("the pixbuf tiff loader is broken (gdk-pixbuf#100)");
return TRUE;
}
return FALSE;
case N_TEXTURE_METHODS:
default:
g_assert_not_reached ();
return TRUE;
}
}
static void
@ -1152,8 +1202,7 @@ test_download (gconstpointer data,
GdkTexture *expected, *test;
gsize i;
if (!decode (data, &format, &method))
return;
decode (data, &format, &method);
if (should_skip_download_test (format, method))
return;
@ -1168,7 +1217,8 @@ test_download (gconstpointer data,
if (color.alpha == 0.f &&
!gdk_memory_format_is_premultiplied (format) &&
gdk_memory_format_has_alpha (format) &&
(method == TEXTURE_METHOD_GL || method == TEXTURE_METHOD_GL_RELEASED || method == TEXTURE_METHOD_GL_NATIVE))
(method == TEXTURE_METHOD_GL || method == TEXTURE_METHOD_GL_RELEASED ||
method == TEXTURE_METHOD_GL_NATIVE || method == TEXTURE_METHOD_VULKAN))
color = (GdkRGBA) { 0, 0, 0, 0 };
expected = create_texture (format, TEXTURE_METHOD_LOCAL, width, height, &color);
@ -1297,7 +1347,7 @@ add_test (const char *name,
{
for (method = 0; method < N_TEXTURE_METHODS; method++)
{
const char *method_names[N_TEXTURE_METHODS] = { "local", "gl", "gl-released", "gl-native", "png", "png-pixbuf", "tiff", "tiff-pixbuf" };
const char *method_names[N_TEXTURE_METHODS] = { "local", "gl", "gl-released", "gl-native", "vulkan", "png", "png-pixbuf", "tiff", "tiff-pixbuf" };
char *test_name = g_strdup_printf ("%s/%s/%s",
name,
g_enum_get_value (enum_class, format)->value_nick,
@ -1344,7 +1394,7 @@ main (int argc, char *argv[])
add_conversion_test ("/memorytexture/conversion_random", test_conversion_random);
gl_context = gdk_display_create_gl_context (gdk_display_get_default (), NULL);
if (!gdk_gl_context_realize (gl_context, NULL))
if (gl_context == NULL || !gdk_gl_context_realize (gl_context, NULL))
{
g_clear_object (&gl_context);
}
@ -1355,8 +1405,23 @@ main (int argc, char *argv[])
g_clear_object (&gl_renderer);
}
#ifdef GDK_RENDERING_VULKAN
vulkan_renderer = gsk_vulkan_renderer_new ();
if (!gsk_renderer_realize (vulkan_renderer, NULL, NULL))
{
g_clear_object (&vulkan_renderer);
}
#endif
result = g_test_run ();
#ifdef GDK_RENDERING_VULKAN
if (vulkan_renderer)
{
gsk_renderer_unrealize (vulkan_renderer);
g_clear_object (&vulkan_renderer);
}
#endif
if (gl_renderer)
{
gsk_renderer_unrealize (gl_renderer);