Compare commits

...

25 Commits

Author SHA1 Message Date
Benjamin Otte
88e8e01156 testsuite: Add a test for proper depth handling
Create a 16bit texture with a color values of
  color(srgb 0.999 0 0)
And then check that diffing it with a color node with that same color
returns black.
A color-matrix node has been added to multiply the difference so that it
can't escape due to being < 1/255.
2024-08-21 03:19:43 +02:00
Benjamin Otte
fc3bd7894e gpu: Make render_texture() render HDR nodes to BT2020_PQ
Also make sure that we pick at least FLOAT16 for the depth - or to be
more exact, that we pick at least the depth of the target colorstate.
2024-08-21 03:19:43 +02:00
Benjamin Otte
93f175986b gpu: Render high depth when node is HDR
When a rendernode is HDR content, we want to render to at least FLOAT16
format, so that the content can reliably be reproduced.

Note that GDK backends may still not support the format, so we might
still end up with a U8 buffer.
In that case, we will continue rendering to U8.
2024-08-21 03:19:43 +02:00
Benjamin Otte
d1281ac3e7 gpu: Don't consider CCS for offscreens
Instead, look at the depth we've been given.
If the colorspace depth is relevant, the caller will already have merged
it into it.
2024-08-21 03:19:43 +02:00
Benjamin Otte
fa6af928b8 ngl: Set a semi-correct format that matches depth
We will start caring about depth of the backbuffer soon, so make sure
the depth is at least somewhat correct.
2024-08-21 03:19:43 +02:00
Benjamin Otte
16c231cf87 gpu: Make gsk_gpu_get_node_as_image() take a depth
That way we can ensure that the depth of offscreens is at least the
depth of the target.

We want that to ensure we get SRGB when the source is SRGB and we also
want F16 when rendering F16 so we get no quantization issues with
gradients.
2024-08-21 03:19:42 +02:00
Benjamin Otte
c5cfc99143 gpu: Keep the target in the nodeprocessor
It's not used yet, but that's about to change.
2024-08-21 03:19:42 +02:00
Benjamin Otte
0226c216b2 gpu: Pull GskGpuFirstNodeInfo out
Move it from render() to process() so it can be shared everywhere else.
Which will be useful for further refactoring.

It also ensures that the convert() path only uses one renderpass.
2024-08-21 03:19:42 +02:00
Benjamin Otte
07861c2474 gpu: Split out culling passes into their own function 2024-08-21 03:19:42 +02:00
Benjamin Otte
c088578a9e nodeprocessor: Remove argument
It's not needed anymore, we can deduce it as needed inside the function.
2024-08-21 03:19:42 +02:00
Benjamin Otte
f12de0bebc rendernode: Colors should not influence depth decisions
Depth of a rendernode should be determined by the textures used and the
compositing colorstate requirements.
Colors influence the colorstate choice, so they indirectly influence the
depth, but they should not influence the depth directly.

Otherwise a single color in a border being rec2100-pq would make us
switch to 16bit float.

Also remove gdk_color_get_depth(), because it was only used here and
because again: Colors should not influence depth decisions.
2024-08-21 03:19:42 +02:00
Benjamin Otte
fdd3f7000b gpu: Add the ability to run renderpasses with and without SRGB
Now that we can properly detect support for SRGB, we can also use
glEnable/glDisable or multiple VkFormats to switch between rendering
linear or srgb.

We don't have enough infrastructure in the nodeprocessor to properly
do that yet, but that will follow.
2024-08-21 03:19:42 +02:00
Benjamin Otte
7149df64c4 gl: Add GDK_GL_FEATURE_SRGB
This features allows toggling SRGB rendering on and off. It is always
available on OpenGL, but not on GLES where it requires an extension.

If this feature is not available, draw contexts should never create SRGB
images and never return GDK_MEMORY_U8_SRGB.
2024-08-21 02:45:13 +02:00
Benjamin Otte
acfb5c4122 vulkan: Use mutable formats for all srgb images
Technically, we only need mutability for offscreens, but it's easier to
handle if we just enable it for all images
2024-08-21 02:45:13 +02:00
Benjamin Otte
78138167e7 vulkan: Require VK_KHR_mutable_swapchain for SRGB support
We want to be able to turn SRGB rendering on per-renderpass so that we
can deal with transparency properly, and that requires this extension
to use 2 different image views: One for SRGB and one for regular access.
2024-08-21 02:45:13 +02:00
Benjamin Otte
19b36d90fe vulkan: Add gdk_vulkan_context_has_feature()
A siimplification that will come in handy in the future.
2024-08-21 02:45:13 +02:00
Benjamin Otte
6d1db51c71 gdk: Report original colorstate for SRGB drawcontexts
We now convert from the SRGB colorstate to the non-SRGB variant inside
the rendering code.
2024-08-21 02:45:13 +02:00
Benjamin Otte
80341665db gpu: Pass color state to download op
Previously we were always implicitly using SRGB, which was correct more
or less by accident.
2024-08-21 02:45:13 +02:00
Benjamin Otte
a2c8405699 gpu: Use builder for memory texture 2024-08-21 02:45:13 +02:00
Benjamin Otte
6d37c6287c gpu: Only run a single renderpass
Instead of running one renderpass per clip region, run one renderpass for
the whole clip extents, and just set the scissor to the individual clip
rects.

This means that we need to use LOAD_OP_LOAD in cases where we don't
redraw the full extents, but nonetheless, the eprformance wins of
avoiding renderpasses are worth it, in particualr on tilers like the
Raspberry Pi or other mobile chips and the Apple M1/2.
2024-08-21 02:45:13 +02:00
Benjamin Otte
9287856f1d gpu: Add GskGpuLoadOp
We want to differentiate between CLEAR, DONT_CARE and LOAD in the
future, and the current boolean doesn't allow that.

Also implement support for the the different ops in the Vulkan
renderpass code.
2024-08-21 02:45:13 +02:00
Benjamin Otte
e6445f3e5e gpu: Add gsk_gpu_first_node_begin_rendering()
This starts the renderpass at the given scissor rect.

It just splits out the gsk_gpu_render_pass_begin_op() call into a
simpler function, so it's harder to mess up.
2024-08-21 02:45:13 +02:00
Benjamin Otte
bc235d4c3d gpu: Add GskGpuFirstNodeInfo
Just encapsulate all the data for the add_first_node() call into a
single struct.
2024-08-21 02:45:13 +02:00
Benjamin Otte
9ef0026f82 gpu: Refactoring: Pull out nodeprocessor
Add gsk_gpu_node_processor_set_scissor() that allows resetting the
nodeprocessor's scissor and clip rectangle.
That in turn allows using the same nodeprocessor instance for all the
rects we draw for the clip region.
2024-08-21 02:45:13 +02:00
Benjamin Otte
8b6d2d8a6b gpu: Split out a function
converting an image to any colorstate (not just ccs-capable default
colorstates) can go in its own function.
2024-08-21 02:45:13 +02:00
25 changed files with 687 additions and 453 deletions

View File

@@ -229,20 +229,6 @@ gdk_color_from_rgba (GdkColor *self,
gdk_color_finish (&tmp);
}
/*< private >
* gdk_color_get_depth:
* @self: a `GdkColor`
*
* Returns the preferred depth for the color state of @self.
*
* Returns: the preferred depth
*/
GdkMemoryDepth
(gdk_color_get_depth) (const GdkColor *self)
{
return gdk_color_state_get_depth (self->color_state);
}
/*< private >
* gdk_color_print:
* @self: the `GdkColor` to print

View File

@@ -129,10 +129,3 @@ _gdk_color_to_float (const GdkColor *self,
values);
}
#define gdk_color_get_depth(self) _gdk_color_get_depth ((self))
static inline GdkMemoryDepth
_gdk_color_get_depth (const GdkColor *self)
{
return gdk_color_state_get_depth (self->color_state);
}

View File

@@ -83,7 +83,6 @@ gboolean gdk_color_equal (const GdkColor *color1,
const GdkColor *color2);
gboolean gdk_color_is_clear (const GdkColor *self);
gboolean gdk_color_is_opaque (const GdkColor *self);
GdkMemoryDepth gdk_color_get_depth (const GdkColor *self);
void gdk_color_convert (GdkColor *self,
GdkColorState *color_state,

View File

@@ -45,9 +45,10 @@ typedef struct _GdkDisplayClass GdkDisplayClass;
typedef enum {
GDK_VULKAN_FEATURE_DMABUF = 1 << 0,
GDK_VULKAN_FEATURE_YCBCR = 1 << 1,
GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT = 1 << 2,
GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT = 1 << 3,
GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT = 1 << 4,
GDK_VULKAN_FEATURE_SRGB = 1 << 2,
GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT = 1 << 3,
GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT = 1 << 4,
GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT = 1 << 5,
} GdkVulkanFeatures;
/* Tracks information about the device grab on this display */

View File

@@ -638,10 +638,7 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
else
*out_depth = GDK_MEMORY_U8;
if (*out_depth == GDK_MEMORY_U8_SRGB)
*out_color_state = gdk_color_state_get_no_srgb_tf (color_state);
else
*out_color_state = color_state;
*out_color_state = color_state;
#else
*out_color_state = gdk_color_state_get_srgb ();
*out_depth = GDK_MEMORY_U8;
@@ -1711,10 +1708,13 @@ gdk_gl_context_check_features (GdkGLContext *context)
if (gdk_gl_version_greater_equal (&priv->gl_version, &GDK_GL_VERSION_INIT (3, 0)) ||
epoxy_has_gl_extension ("GL_EXT_unpack_subimage"))
features |= GDK_GL_FEATURE_UNPACK_SUBIMAGE;
if (epoxy_has_gl_extension ("GL_EXT_sRGB_write_control"))
features |= GDK_GL_FEATURE_SRGB;
}
else
{
features |= GDK_GL_FEATURE_UNPACK_SUBIMAGE;
features |= GDK_GL_FEATURE_UNPACK_SUBIMAGE |
GDK_GL_FEATURE_SRGB;
}
if (epoxy_has_gl_extension ("GL_KHR_debug"))

View File

@@ -34,6 +34,7 @@ typedef enum {
GDK_GL_FEATURE_SYNC = 1 << 3,
GDK_GL_FEATURE_BASE_INSTANCE = 1 << 4,
GDK_GL_FEATURE_BUFFER_STORAGE = 1 << 5,
GDK_GL_FEATURE_SRGB = 1 << 6,
} GdkGLFeatures;
typedef enum {

View File

@@ -38,6 +38,7 @@
static const GdkDebugKey gsk_vulkan_feature_keys[] = {
{ "dmabuf", GDK_VULKAN_FEATURE_DMABUF, "Never import Dmabufs" },
{ "ycbcr", GDK_VULKAN_FEATURE_YCBCR, "Do not support Ycbcr textures (also disables dmabufs)" },
{ "srgb", GDK_VULKAN_FEATURE_SRGB, "Do not support SRGB images" },
{ "semaphore-export", GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT, "Disable sync of exported dmabufs" },
{ "semaphore-import", GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT, "Disable sync of imported dmabufs" },
{ "incremental-present", GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT, "Do not send damage regions" },
@@ -303,6 +304,15 @@ surface_present_mode_to_string (VkPresentModeKHR present_mode)
return "(unknown)";
}
static gboolean
gdk_vulkan_context_has_feature (GdkVulkanContext *self,
GdkVulkanFeatures feature)
{
GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (self));
return (display->vulkan_features & feature) ? TRUE : FALSE;
}
static const VkPresentModeKHR preferred_present_modes[] = {
VK_PRESENT_MODE_MAILBOX_KHR,
VK_PRESENT_MODE_IMMEDIATE_KHR,
@@ -457,8 +467,7 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
res = GDK_VK_CHECK (vkCreateSwapchainKHR, device,
&(VkSwapchainCreateInfoKHR) {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = NULL,
.flags = 0,
.flags = priv->current_depth == GDK_MEMORY_U8_SRGB ? VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR : 0,
.surface = priv->surface,
.minImageCount = CLAMP (4,
capabilities.minImageCount,
@@ -477,7 +486,15 @@ gdk_vulkan_context_check_swapchain (GdkVulkanContext *context,
.compositeAlpha = composite_alpha,
.presentMode = present_mode,
.clipped = VK_FALSE,
.oldSwapchain = priv->swapchain
.oldSwapchain = priv->swapchain,
.pNext = priv->current_depth == GDK_MEMORY_U8_SRGB ? &(VkImageFormatListCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
.viewFormatCount = 2,
.pViewFormats = (VkFormat[]) {
priv->formats[priv->current_depth].vk_format.format,
priv->formats[GDK_MEMORY_U8].vk_format.format,
}
} : NULL,
},
NULL,
&new_swapchain);
@@ -591,6 +608,9 @@ physical_device_check_features (VkPhysicalDevice device)
physical_device_supports_extension (device, VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME))
features |= GDK_VULKAN_FEATURE_DMABUF;
if (physical_device_supports_extension (device, VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME))
features |= GDK_VULKAN_FEATURE_SRGB;
if (physical_device_supports_extension (device, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME))
{
if (semaphore_props.externalSemaphoreFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT)
@@ -625,6 +645,9 @@ gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
color_state = gdk_surface_get_color_state (surface);
depth = gdk_memory_depth_merge (depth, gdk_color_state_get_depth (color_state));
if (depth == GDK_MEMORY_U8_SRGB && !gdk_vulkan_context_has_feature (context, GDK_VULKAN_FEATURE_SRGB))
depth = GDK_MEMORY_U8;
g_assert (depth != GDK_MEMORY_U8_SRGB || gdk_color_state_get_no_srgb_tf (color_state) != NULL);
if (depth != priv->current_depth && depth != GDK_MEMORY_NONE)
@@ -678,10 +701,7 @@ gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
cairo_region_union (region, priv->regions[priv->draw_index]);
if (priv->current_depth == GDK_MEMORY_U8_SRGB)
*out_color_state = gdk_color_state_get_no_srgb_tf (color_state);
else
*out_color_state = color_state;
*out_color_state = color_state;
*out_depth = priv->current_depth;
}
@@ -692,11 +712,10 @@ gdk_vulkan_context_end_frame (GdkDrawContext *draw_context,
GdkVulkanContext *context = GDK_VULKAN_CONTEXT (draw_context);
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
GdkSurface *surface = gdk_draw_context_get_surface (draw_context);
GdkDisplay *display = gdk_draw_context_get_display (draw_context);
VkRectLayerKHR *rectangles;
int n_regions;
if (display->vulkan_features & GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT)
if (gdk_vulkan_context_has_feature (context, GDK_VULKAN_FEATURE_INCREMENTAL_PRESENT))
{
double scale;
@@ -1529,6 +1548,10 @@ gdk_display_create_vulkan_device (GdkDisplay *display,
g_ptr_array_add (device_extensions, (gpointer) VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME);
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
}
if (features & GDK_VULKAN_FEATURE_SRGB)
{
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);
}
if (features & (GDK_VULKAN_FEATURE_SEMAPHORE_IMPORT | GDK_VULKAN_FEATURE_SEMAPHORE_EXPORT))
{
g_ptr_array_add (device_extensions, (gpointer) VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME);

View File

@@ -33,6 +33,7 @@ struct _GskGpuDownloadOp
GskGpuOp op;
GskGpuImage *image;
GdkColorState *color_state;
gboolean allow_dmabuf;
GdkGpuDownloadOpCreateFunc create_func;
GskGpuDownloadFunc func;
@@ -118,6 +119,7 @@ gsk_gpu_download_op_vk_create (GskGpuDownloadOp *self)
guchar *data;
gsize width, height, stride;
GdkMemoryFormat format;
GdkMemoryTextureBuilder *builder;
data = gsk_gpu_buffer_map (self->buffer);
width = gsk_gpu_image_get_width (self->image);
@@ -125,11 +127,17 @@ gsk_gpu_download_op_vk_create (GskGpuDownloadOp *self)
format = gsk_gpu_image_get_format (self->image);
stride = width * gdk_memory_format_bytes_per_pixel (format);
bytes = g_bytes_new (data, stride * height);
self->texture = gdk_memory_texture_new (width,
height,
format,
bytes,
stride);
builder = gdk_memory_texture_builder_new ();
gdk_memory_texture_builder_set_width (builder, width);
gdk_memory_texture_builder_set_height (builder, height);
gdk_memory_texture_builder_set_format (builder, format);
gdk_memory_texture_builder_set_bytes (builder, bytes);
gdk_memory_texture_builder_set_stride (builder, stride);
gdk_memory_texture_builder_set_color_state (builder, self->color_state);
self->texture = gdk_memory_texture_builder_build (builder);
g_object_unref (builder);
g_bytes_unref (bytes);
gsk_gpu_buffer_unmap (self->buffer, 0);
}
@@ -144,7 +152,8 @@ gsk_gpu_download_op_vk_command (GskGpuOp *op,
#ifdef HAVE_DMABUF
if (self->allow_dmabuf)
self->texture = gsk_vulkan_image_to_dmabuf_texture (GSK_VULKAN_IMAGE (self->image));
self->texture = gsk_vulkan_image_to_dmabuf_texture (GSK_VULKAN_IMAGE (self->image),
self->color_state);
if (self->texture)
{
GskGpuDevice *device = gsk_gpu_frame_get_device (frame);
@@ -316,6 +325,7 @@ gsk_gpu_download_op_gl_command (GskGpuOp *op,
gdk_dmabuf_texture_builder_set_premultiplied (db, gdk_memory_format_get_premultiplied (gsk_gpu_image_get_format (self->image)));
gdk_dmabuf_texture_builder_set_width (db, gsk_gpu_image_get_width (self->image));
gdk_dmabuf_texture_builder_set_height (db, gsk_gpu_image_get_height (self->image));
gdk_dmabuf_texture_builder_set_color_state (db, self->color_state);
self->texture = gdk_dmabuf_texture_builder_build (db, release_dmabuf_texture, texture, NULL);
@@ -340,6 +350,7 @@ gsk_gpu_download_op_gl_command (GskGpuOp *op,
gdk_gl_texture_builder_set_context (builder, context);
gdk_gl_texture_builder_set_id (builder, data->texture_id);
gdk_gl_texture_builder_set_format (builder, gsk_gpu_image_get_format (self->image));
gdk_gl_texture_builder_set_color_state (builder, self->color_state);
gdk_gl_texture_builder_set_width (builder, gsk_gpu_image_get_width (self->image));
gdk_gl_texture_builder_set_height (builder, gsk_gpu_image_get_height (self->image));
gdk_gl_texture_builder_set_sync (builder, data->sync);
@@ -367,6 +378,7 @@ static const GskGpuOpClass GSK_GPU_DOWNLOAD_OP_CLASS = {
void
gsk_gpu_download_op (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *color_state,
gboolean allow_dmabuf,
GskGpuDownloadFunc func,
gpointer user_data)
@@ -376,6 +388,7 @@ gsk_gpu_download_op (GskGpuFrame *frame,
self = (GskGpuDownloadOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_DOWNLOAD_OP_CLASS);
self->image = g_object_ref (image);
self->color_state = gdk_color_state_ref (color_state);
self->allow_dmabuf = allow_dmabuf;
self->func = func,
self->user_data = user_data;

View File

@@ -9,6 +9,7 @@ typedef void (* GskGpuDownloadFunc) (gpointe
void gsk_gpu_download_op (GskGpuFrame *frame,
GskGpuImage *image,
GdkColorState *color_state,
gboolean allow_dmabuf,
GskGpuDownloadFunc func,
gpointer user_data);

View File

@@ -648,7 +648,7 @@ gsk_gpu_frame_record (GskGpuFrame *self,
gsk_gpu_node_processor_process (self, target, target_color_state, clip, node, viewport, pass_type);
if (texture)
gsk_gpu_download_op (self, target, TRUE, copy_texture, texture);
gsk_gpu_download_op (self, target, target_color_state, TRUE, copy_texture, texture);
}
static void
@@ -755,6 +755,7 @@ gsk_gpu_frame_download_texture (GskGpuFrame *self,
gsk_gpu_download_op (self,
image,
gdk_texture_get_color_state (texture),
FALSE,
do_download,
g_memdup (&(Download) {

File diff suppressed because it is too large Load Diff

View File

@@ -268,11 +268,17 @@ gsk_gpu_renderer_fallback_render_texture (GskGpuRenderer *self,
GskGpuFrame *frame;
max_size = gsk_gpu_device_get_max_image_size (priv->device);
depth = gsk_render_node_get_preferred_depth (root);
if (gsk_render_node_is_hdr (root))
color_state = GDK_COLOR_STATE_REC2100_PQ;
else
color_state = GDK_COLOR_STATE_SRGB;
depth = gdk_memory_depth_merge (gdk_color_state_get_depth (color_state),
gsk_render_node_get_preferred_depth (root));
do
{
image = gsk_gpu_device_create_download_image (priv->device,
gsk_render_node_get_preferred_depth (root),
depth,
MIN (max_size, rounded_viewport->size.width),
MIN (max_size, rounded_viewport->size.height));
max_size /= 2;
@@ -300,11 +306,6 @@ gsk_gpu_renderer_fallback_render_texture (GskGpuRenderer *self,
MIN (image_width, width - x),
MIN (image_height, height - y));
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_SRGB)
color_state = GDK_COLOR_STATE_SRGB_LINEAR;
else
color_state = GDK_COLOR_STATE_SRGB;
clip_region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
0, 0,
gsk_gpu_image_get_width (image),
@@ -357,11 +358,19 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
GskGpuImage *image;
GdkTexture *texture;
graphene_rect_t rounded_viewport;
GdkMemoryDepth depth;
GdkColorState *color_state;
cairo_region_t *clip_region;
gsk_gpu_device_maybe_gc (priv->device);
if (gsk_render_node_is_hdr (root))
color_state = GDK_COLOR_STATE_REC2100_PQ;
else
color_state = GDK_COLOR_STATE_SRGB;
depth = gdk_memory_depth_merge (gdk_color_state_get_depth (color_state),
gsk_render_node_get_preferred_depth (root));
gsk_gpu_renderer_make_current (self);
rounded_viewport = GRAPHENE_RECT_INIT (viewport->origin.x,
@@ -369,18 +378,13 @@ gsk_gpu_renderer_render_texture (GskRenderer *renderer,
ceil (viewport->size.width),
ceil (viewport->size.height));
image = gsk_gpu_device_create_download_image (priv->device,
gsk_render_node_get_preferred_depth (root),
depth,
rounded_viewport.size.width,
rounded_viewport.size.height);
if (image == NULL)
return gsk_gpu_renderer_fallback_render_texture (self, root, &rounded_viewport);
if (gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_SRGB)
color_state = GDK_COLOR_STATE_SRGB_LINEAR;
else
color_state = GDK_COLOR_STATE_SRGB;
frame = gsk_gpu_renderer_create_frame (self);
clip_region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
@@ -436,6 +440,8 @@ gsk_gpu_renderer_render (GskRenderer *renderer,
gsk_gpu_renderer_make_current (self);
depth = gsk_render_node_get_preferred_depth (root);
if (gsk_render_node_is_hdr (root))
depth = gdk_memory_depth_merge (depth, GDK_MEMORY_FLOAT16);
frame = gsk_gpu_renderer_get_frame (self);
scale = gsk_gpu_renderer_get_scale (self);

View File

@@ -20,8 +20,9 @@ struct _GskGpuRenderPassOp
GskGpuOp op;
GskGpuImage *target;
gboolean no_srgb;
cairo_rectangle_int_t area;
gboolean clear;
GskGpuLoadOp load_op;
float clear_color[4];
GskRenderPassType pass_type;
};
@@ -45,8 +46,21 @@ gsk_gpu_render_pass_op_print (GskGpuOp *op,
gsk_gpu_print_op (string, indent, "begin-render-pass");
gsk_gpu_print_image (string, self->target);
gsk_gpu_print_int_rect (string, &self->area);
if (self->clear)
gsk_gpu_print_rgba (string, self->clear_color);
switch (self->load_op)
{
case GSK_GPU_LOAD_OP_LOAD:
gsk_gpu_print_string (string, "load");
break;
case GSK_GPU_LOAD_OP_CLEAR:
gsk_gpu_print_rgba (string, self->clear_color);
break;
case GSK_GPU_LOAD_OP_DONT_CARE:
gsk_gpu_print_string (string, "dont-care");
break;
default:
g_assert_not_reached ();
break;
}
gsk_gpu_print_newline (string);
}
@@ -100,6 +114,21 @@ gsk_gpu_render_pass_op_do_barriers (GskGpuRenderPassOp *self,
}
}
static VkAttachmentLoadOp
gsk_gpu_load_op_to_vk_load_op (GskGpuLoadOp op)
{
switch (op)
{
case GSK_GPU_LOAD_OP_LOAD:
return VK_ATTACHMENT_LOAD_OP_LOAD;
case GSK_GPU_LOAD_OP_CLEAR:
return VK_ATTACHMENT_LOAD_OP_CLEAR;
case GSK_GPU_LOAD_OP_DONT_CARE:
return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
default:
g_return_val_if_reached (VK_ATTACHMENT_LOAD_OP_DONT_CARE);
}
}
static GskGpuOp *
gsk_gpu_render_pass_op_vk_command (GskGpuOp *op,
GskGpuFrame *frame,
@@ -112,9 +141,10 @@ gsk_gpu_render_pass_op_vk_command (GskGpuOp *op,
gsk_gpu_render_pass_op_do_barriers (self, state);
state->vk_format = gsk_vulkan_image_get_vk_format (GSK_VULKAN_IMAGE (self->target));
state->vk_format = gsk_vulkan_image_get_vk_format (GSK_VULKAN_IMAGE (self->target), self->no_srgb);
state->vk_render_pass = gsk_vulkan_device_get_vk_render_pass (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
state->vk_format,
gsk_gpu_load_op_to_vk_load_op (self->load_op),
gsk_vulkan_image_get_vk_image_layout (GSK_VULKAN_IMAGE (self->target)),
gsk_gpu_render_pass_type_to_vk_image_layout (self->pass_type));
@@ -136,24 +166,25 @@ gsk_gpu_render_pass_op_vk_command (GskGpuOp *op,
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = state->vk_render_pass,
.framebuffer = gsk_vulkan_image_get_vk_framebuffer (GSK_VULKAN_IMAGE(self->target),
self->no_srgb,
state->vk_render_pass),
.renderArea = {
{ self->area.x, self->area.y },
{ self->area.width, self->area.height }
},
.clearValueCount = 1,
.pClearValues = (VkClearValue [1]) {
.clearValueCount = self->load_op == GSK_GPU_LOAD_OP_CLEAR ? 1 : 0,
.pClearValues = self->load_op == GSK_GPU_LOAD_OP_CLEAR ? (VkClearValue [1]) {
{
.color = {
.float32 = {
self->clear ? self->clear_color[0] : 0,
self->clear ? self->clear_color[1] : 0,
self->clear ? self->clear_color[2] : 0,
self->clear ? self->clear_color[3] : 0
self->clear_color[0],
self->clear_color[1],
self->clear_color[2],
self->clear_color[3]
}
}
}
}
}
} : NULL,
},
VK_SUBPASS_CONTENTS_INLINE);
@@ -186,6 +217,14 @@ gsk_gpu_render_pass_op_gl_command (GskGpuOp *op,
else
state->flip_y = 0;
if (gsk_gpu_image_get_flags (self->target) & GSK_GPU_IMAGE_SRGB)
{
if (self->no_srgb)
glDisable (GL_FRAMEBUFFER_SRGB);
else
glEnable (GL_FRAMEBUFFER_SRGB);
}
glViewport (0, 0,
gsk_gpu_image_get_width (self->target),
gsk_gpu_image_get_height (self->target));
@@ -194,7 +233,7 @@ gsk_gpu_render_pass_op_gl_command (GskGpuOp *op,
glScissor (self->area.x, state->flip_y - self->area.y - self->area.height, self->area.width, self->area.height);
else
glScissor (self->area.x, self->area.y, self->area.width, self->area.height);
if (self->clear)
if (self->load_op == GSK_GPU_LOAD_OP_CLEAR)
{
glClearColor (self->clear_color[0], self->clear_color[1], self->clear_color[2], self->clear_color[3]);
glClear (GL_COLOR_BUFFER_BIT);
@@ -328,19 +367,25 @@ static const GskGpuOpClass GSK_GPU_RENDER_PASS_END_OP_CLASS = {
void
gsk_gpu_render_pass_begin_op (GskGpuFrame *frame,
GskGpuImage *image,
gboolean no_srgb,
const cairo_rectangle_int_t *area,
float clear_color_or_null[4],
GskGpuLoadOp load_op,
float clear_color[4],
GskRenderPassType pass_type)
{
GskGpuRenderPassOp *self;
g_assert (load_op != GSK_GPU_LOAD_OP_CLEAR || clear_color != NULL);
g_assert (!no_srgb || gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_SRGB);
self = (GskGpuRenderPassOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_RENDER_PASS_OP_CLASS);
self->target = g_object_ref (image);
self->no_srgb = no_srgb;
self->area = *area;
self->clear = clear_color_or_null != NULL;
if (clear_color_or_null)
gsk_gpu_vec4_to_float (clear_color_or_null, self->clear_color);
self->load_op = load_op;
if (self->load_op == GSK_GPU_LOAD_OP_CLEAR)
gsk_gpu_vec4_to_float (clear_color, self->clear_color);
self->pass_type = pass_type;
}

View File

@@ -10,8 +10,10 @@ G_BEGIN_DECLS
void gsk_gpu_render_pass_begin_op (GskGpuFrame *frame,
GskGpuImage *image,
gboolean no_srgb,
const cairo_rectangle_int_t *area,
float clear_color_or_null[4],
GskGpuLoadOp load_op,
float clear_color[4],
GskRenderPassType pass_type);
void gsk_gpu_render_pass_end_op (GskGpuFrame *frame,
GskGpuImage *image,

View File

@@ -64,6 +64,13 @@ typedef enum
GSK_RENDER_PASS_EXPORT
} GskRenderPassType;
typedef enum
{
GSK_GPU_LOAD_OP_LOAD,
GSK_GPU_LOAD_OP_CLEAR,
GSK_GPU_LOAD_OP_DONT_CARE
} GskGpuLoadOp;
typedef enum {
GSK_GPU_PATTERN_DONE,
GSK_GPU_PATTERN_COLOR,

View File

@@ -91,23 +91,28 @@ static GskGpuImage *
gsk_ngl_renderer_get_backbuffer (GskGpuRenderer *renderer)
{
GskNglRenderer *self = GSK_NGL_RENDERER (renderer);
GdkMemoryFormat format;
GdkMemoryDepth depth;
GdkDrawContext *context;
GdkSurface *surface;
double scale;
context = gsk_gpu_renderer_get_context (renderer);
surface = gdk_draw_context_get_surface (context);
depth = gdk_draw_context_get_depth (context);
format = gdk_memory_depth_get_format (depth);
scale = gsk_gpu_renderer_get_scale (renderer);
if (self->backbuffer == NULL ||
!!(gsk_gpu_image_get_flags (self->backbuffer) & GSK_GPU_IMAGE_SRGB) != gdk_surface_get_gl_is_srgb (surface) ||
gsk_gpu_image_get_format (self->backbuffer) != format ||
gsk_gpu_image_get_width (self->backbuffer) != ceil (gdk_surface_get_width (surface) * scale) ||
gsk_gpu_image_get_height (self->backbuffer) != ceil (gdk_surface_get_height (surface) * scale))
{
gsk_ngl_renderer_free_backbuffer (self);
self->backbuffer = gsk_gl_image_new_backbuffer (GSK_GL_DEVICE (gsk_gpu_renderer_get_device (renderer)),
GDK_GL_CONTEXT (context),
GDK_MEMORY_DEFAULT /* FIXME */,
format,
gdk_surface_get_gl_is_srgb (surface),
ceil (gdk_surface_get_width (surface) * scale),
ceil (gdk_surface_get_height (surface) * scale));

View File

@@ -74,6 +74,7 @@ struct _PipelineCacheKey
struct _RenderPassCacheKey
{
VkFormat format;
VkAttachmentLoadOp vk_load_op;
VkImageLayout from_layout;
VkImageLayout to_layout;
VkRenderPass render_pass;
@@ -114,8 +115,9 @@ render_pass_cache_key_hash (gconstpointer data)
{
const RenderPassCacheKey *key = data;
return (key->from_layout << 20) ^
(key->to_layout << 16) ^
return (key->from_layout << 26) ^
(key->to_layout << 18) ^
(key->vk_load_op << 16) ^
(key->format);
}
@@ -128,6 +130,7 @@ render_pass_cache_key_equal (gconstpointer a,
return keya->from_layout == keyb->from_layout &&
keya->to_layout == keyb->to_layout &&
keya->vk_load_op == keyb->vk_load_op &&
keya->format == keyb->format;
}
@@ -706,10 +709,11 @@ gsk_vulkan_device_remove_ycbcr (GskVulkanDevice *self,
}
VkRenderPass
gsk_vulkan_device_get_vk_render_pass (GskVulkanDevice *self,
VkFormat format,
VkImageLayout from_layout,
VkImageLayout to_layout)
gsk_vulkan_device_get_vk_render_pass (GskVulkanDevice *self,
VkFormat format,
VkAttachmentLoadOp vk_load_op,
VkImageLayout from_layout,
VkImageLayout to_layout)
{
RenderPassCacheKey cache_key;
RenderPassCacheKey *cached_result;
@@ -718,6 +722,7 @@ gsk_vulkan_device_get_vk_render_pass (GskVulkanDevice *self,
cache_key = (RenderPassCacheKey) {
.format = format,
.vk_load_op = vk_load_op,
.from_layout = from_layout,
.to_layout = to_layout,
};
@@ -735,7 +740,7 @@ gsk_vulkan_device_get_vk_render_pass (GskVulkanDevice *self,
{
.format = format,
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.loadOp = vk_load_op,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.initialLayout = from_layout,
.finalLayout = to_layout

View File

@@ -53,6 +53,7 @@ void gsk_vulkan_device_remove_ycbcr (GskVulk
VkRenderPass gsk_vulkan_device_get_vk_render_pass (GskVulkanDevice *self,
VkFormat format,
VkAttachmentLoadOp vk_load_op,
VkImageLayout from_layout,
VkImageLayout to_layout);
VkPipeline gsk_vulkan_device_get_vk_pipeline (GskVulkanDevice *self,

View File

@@ -19,19 +19,24 @@
#include <linux/dma-buf.h>
#endif
enum {
DEFAULT = 0,
NO_SRGB = 1
};
struct _GskVulkanImage
{
GskGpuImage parent_instance;
GskVulkanDevice *device;
VkFormat vk_format;
VkFormat vk_format[2];
VkImageTiling vk_tiling;
VkImageUsageFlags vk_usage;
VkImage vk_image;
VkImageView vk_image_view;
VkFramebuffer vk_framebuffer;
VkImageView vk_framebuffer_image_view;
VkFramebuffer vk_framebuffer[2];
VkImageView vk_framebuffer_image_view[2];
GskVulkanYcbcr *ycbcr;
VkSemaphore vk_semaphore;
struct {
@@ -278,11 +283,15 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
tiling, usage, width, height,
&tiling, &flags))
{
vk_format = vk_srgb_format;
/* all fine */
}
else if (!gsk_vulkan_device_check_format (device, vk_format, &vk_components, required_flags,
tiling, usage, width, height,
&tiling, &flags))
else if (gsk_vulkan_device_check_format (device, vk_format, &vk_components, required_flags,
tiling, usage, width, height,
&tiling, &flags))
{
vk_srgb_format = VK_FORMAT_UNDEFINED;
}
else
{
GdkMemoryFormat rgba_format;
@@ -296,11 +305,15 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
tiling, usage, width, height,
&tiling, &flags))
{
vk_format = vk_srgb_format;
/* all fine */
}
else if (!gsk_vulkan_device_check_format (device, vk_format, &vk_components, required_flags,
tiling, usage, width, height,
&tiling, &flags))
else if (gsk_vulkan_device_check_format (device, vk_format, &vk_components, required_flags,
tiling, usage, width, height,
&tiling, &flags))
{
vk_srgb_format = VK_FORMAT_UNDEFINED;
}
else
{
const GdkMemoryFormat *fallbacks;
gsize i;
@@ -316,7 +329,6 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
tiling, usage, width, height,
&tiling, &flags))
{
vk_format = vk_srgb_format;
format = fallbacks[i];
break;
}
@@ -324,6 +336,7 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
tiling, usage, width, height,
&tiling, &flags))
{
vk_srgb_format = VK_FORMAT_UNDEFINED;
format = fallbacks[i];
break;
}
@@ -335,7 +348,7 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
}
}
if (vk_format == vk_srgb_format)
if (vk_srgb_format != VK_FORMAT_UNDEFINED)
flags |= GSK_GPU_IMAGE_SRGB;
if (gdk_memory_format_alpha (format) == GDK_MEMORY_ALPHA_STRAIGHT)
@@ -354,7 +367,11 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
self->device = g_object_ref (device);
self->vk_format = vk_format;
self->vk_format[NO_SRGB] = vk_format;
if (flags & GSK_GPU_IMAGE_SRGB)
self->vk_format[DEFAULT] = vk_srgb_format;
else
self->vk_format[DEFAULT] = vk_format;
self->vk_tiling = tiling;
self->vk_usage = usage;
self->vk_pipeline_stage = stage;
@@ -366,7 +383,7 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
GSK_VK_CHECK (vkCreateImage, vk_device,
&(VkImageCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.flags = 0,
.flags = (flags & GSK_GPU_IMAGE_SRGB) ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0,
.imageType = VK_IMAGE_TYPE_2D,
.format = vk_format,
.extent = { width, height, 1 },
@@ -378,6 +395,15 @@ gsk_vulkan_image_new (GskVulkanDevice *device,
(flags & GSK_GPU_IMAGE_NO_BLIT ? 0 : VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.initialLayout = self->vk_image_layout,
.pNext = (flags & GSK_GPU_IMAGE_SRGB) ? &(VkImageFormatListCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
.pNext = NULL,
.viewFormatCount = 2,
.pViewFormats = (VkFormat[]) {
vk_format,
vk_srgb_format
}
} : NULL,
},
NULL,
&self->vk_image);
@@ -477,8 +503,8 @@ gsk_vulkan_image_get_data (GskVulkanImage *self,
GskGpuImage *
gsk_vulkan_image_new_for_swapchain (GskVulkanDevice *device,
VkImage image,
VkFormat format,
GdkMemoryFormat memory_format,
VkFormat vk_format,
GdkMemoryFormat format,
gsize width,
gsize height)
{
@@ -490,19 +516,25 @@ gsk_vulkan_image_new_for_swapchain (GskVulkanDevice *device,
self->device = g_object_ref (device);
self->vk_tiling = VK_IMAGE_TILING_OPTIMAL;
self->vk_image = image;
self->vk_format = format;
self->vk_format[0] = vk_format;
if (vk_format == gdk_memory_format_vk_srgb_format (format))
{
self->vk_format[1] = gdk_memory_format_vk_format (format, NULL);
flags |= GSK_GPU_IMAGE_SRGB;
}
else
{
self->vk_format[1] = vk_format;
}
self->vk_pipeline_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
self->vk_image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
self->vk_access = 0;
if (format == gdk_memory_format_vk_srgb_format (memory_format))
flags |= GSK_GPU_IMAGE_SRGB;
/* FIXME: The flags here are very suboptimal */
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), flags, memory_format, width, height);
gsk_gpu_image_setup (GSK_GPU_IMAGE (self), flags, format, width, height);
gsk_vulkan_image_create_view (self,
format,
vk_format,
&(VkComponentMapping) {
VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_G,
@@ -759,7 +791,8 @@ gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device,
self->device = g_object_ref (device);
self->vk_tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
self->vk_format = vk_format;
self->vk_format[0] = vk_format;
self->vk_format[1] = vk_format;
self->vk_pipeline_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
self->vk_image_layout = VK_IMAGE_LAYOUT_UNDEFINED;
self->vk_access = 0;
@@ -775,7 +808,7 @@ gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device,
res = vkCreateImage (vk_device,
&(VkImageCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.flags = 0,
.flags = (vk_format == vk_srgb_format) ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0,
.imageType = VK_IMAGE_TYPE_2D,
.format = vk_format,
.extent = { width, height, 1 },
@@ -793,7 +826,16 @@ gsk_vulkan_image_new_dmabuf (GskVulkanDevice *device,
.pNext = &(VkImageDrmFormatModifierListCreateInfoEXT) {
.sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT,
.drmFormatModifierCount = n_modifiers,
.pDrmFormatModifiers = modifiers
.pDrmFormatModifiers = modifiers,
.pNext = (vk_format == vk_srgb_format) ? &(VkImageFormatListCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
.pNext = NULL,
.viewFormatCount = 2,
.pViewFormats = (VkFormat[]) {
vk_format,
gdk_memory_format_vk_format (format, NULL),
}
} : NULL,
}
},
},
@@ -911,7 +953,8 @@ gsk_vulkan_image_new_for_dmabuf (GskVulkanDevice *device,
self->device = g_object_ref (device);
self->vk_tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
self->vk_format = vk_format;
self->vk_format[0] = vk_format;
self->vk_format[1] = vk_format;
self->vk_pipeline_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
self->vk_image_layout = VK_IMAGE_LAYOUT_GENERAL;
self->vk_access = 0;
@@ -1163,7 +1206,7 @@ gsk_vulkan_image_get_n_planes (GskVulkanImage *self,
gsize i;
vkGetPhysicalDeviceFormatProperties2 (gsk_vulkan_device_get_vk_physical_device (self->device),
self->vk_format,
self->vk_format[0],
&properties);
for (i = 0; i < drm_properties.drmFormatModifierCount; i++)
@@ -1176,7 +1219,8 @@ gsk_vulkan_image_get_n_planes (GskVulkanImage *self,
}
GdkTexture *
gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self)
gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self,
GdkColorState *color_state)
{
GskGpuImage *image = GSK_GPU_IMAGE (self);
GdkDmabufTextureBuilder *builder;
@@ -1230,6 +1274,7 @@ gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self)
gdk_dmabuf_texture_builder_set_modifier (builder, properties.drmFormatModifier);
gdk_dmabuf_texture_builder_set_premultiplied (builder, !(gsk_gpu_image_get_flags (image) & GSK_GPU_IMAGE_STRAIGHT_ALPHA));
gdk_dmabuf_texture_builder_set_n_planes (builder, n_planes);
gdk_dmabuf_texture_builder_set_color_state (builder, color_state);
for (plane = 0; plane < n_planes; plane++)
{
@@ -1306,12 +1351,14 @@ gsk_vulkan_image_finalize (GObject *object)
self->descriptor_sets[i].vk_descriptor_set);
}
if (self->vk_framebuffer != VK_NULL_HANDLE)
vkDestroyFramebuffer (vk_device, self->vk_framebuffer, NULL);
if (self->vk_framebuffer_image_view != VK_NULL_HANDLE &&
self->vk_framebuffer_image_view != self->vk_image_view)
vkDestroyImageView (vk_device, self->vk_framebuffer_image_view, NULL);
for (i = 0; i < 2; i++)
{
if (self->vk_framebuffer[i] != VK_NULL_HANDLE)
vkDestroyFramebuffer (vk_device, self->vk_framebuffer[0], NULL);
if (self->vk_framebuffer_image_view[i] != VK_NULL_HANDLE &&
self->vk_framebuffer_image_view[i] != self->vk_image_view)
vkDestroyImageView (vk_device, self->vk_framebuffer_image_view[i], NULL);
}
if (self->vk_image_view != VK_NULL_HANDLE)
vkDestroyImageView (vk_device, self->vk_image_view, NULL);
@@ -1351,23 +1398,32 @@ gsk_vulkan_image_init (GskVulkanImage *self)
VkFramebuffer
gsk_vulkan_image_get_vk_framebuffer (GskVulkanImage *self,
gboolean no_srgb,
VkRenderPass render_pass)
{
VkDevice vk_device;
GskGpuImageFlags flags;
guint id;
if (self->vk_framebuffer)
return self->vk_framebuffer;
flags = gsk_gpu_image_get_flags (GSK_GPU_IMAGE (self));
if (flags & GSK_GPU_IMAGE_SRGB)
id = no_srgb ? NO_SRGB : DEFAULT;
else
id = DEFAULT;
if (self->vk_framebuffer[id])
return self->vk_framebuffer[id];
vk_device = gsk_vulkan_device_get_vk_device (self->device);
if (gsk_gpu_image_get_flags (GSK_GPU_IMAGE (self)) & GSK_GPU_IMAGE_CAN_MIPMAP)
if (flags & (GSK_GPU_IMAGE_CAN_MIPMAP | GSK_GPU_IMAGE_SRGB))
{
GSK_VK_CHECK (vkCreateImageView, vk_device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = self->vk_image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = self->vk_format,
.format = self->vk_format[id],
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
@@ -1377,11 +1433,11 @@ gsk_vulkan_image_get_vk_framebuffer (GskVulkanImage *self,
}
},
NULL,
&self->vk_framebuffer_image_view);
&self->vk_framebuffer_image_view[id]);
}
else
{
self->vk_framebuffer_image_view = self->vk_image_view;
self->vk_framebuffer_image_view[id] = self->vk_image_view;
}
GSK_VK_CHECK (vkCreateFramebuffer, vk_device,
@@ -1390,16 +1446,16 @@ gsk_vulkan_image_get_vk_framebuffer (GskVulkanImage *self,
.renderPass = render_pass,
.attachmentCount = 1,
.pAttachments = (VkImageView[1]) {
self->vk_framebuffer_image_view,
self->vk_framebuffer_image_view[id],
},
.width = gsk_gpu_image_get_width (GSK_GPU_IMAGE (self)),
.height = gsk_gpu_image_get_height (GSK_GPU_IMAGE (self)),
.layers = 1
},
NULL,
&self->vk_framebuffer);
&self->vk_framebuffer[id]);
return self->vk_framebuffer;
return self->vk_framebuffer[id];
}
VkDescriptorSet
@@ -1531,8 +1587,9 @@ gsk_vulkan_image_transition (GskVulkanImage *self,
}
VkFormat
gsk_vulkan_image_get_vk_format (GskVulkanImage *self)
gsk_vulkan_image_get_vk_format (GskVulkanImage *self,
gboolean no_srgb)
{
return self->vk_format;
return self->vk_format[no_srgb ? NO_SRGB : DEFAULT];
}

View File

@@ -44,7 +44,8 @@ GskGpuImage * gsk_vulkan_image_new_for_dmabuf (GskVulk
gsize height,
const GdkDmabuf *dmabuf,
gboolean premultiplied);
GdkTexture * gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self);
GdkTexture * gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self,
GdkColorState *color_state);
#endif
guchar * gsk_vulkan_image_get_data (GskVulkanImage *self,
@@ -72,8 +73,10 @@ void gsk_vulkan_image_transition (GskVulk
VkImage gsk_vulkan_image_get_vk_image (GskVulkanImage *self);
VkImageView gsk_vulkan_image_get_vk_image_view (GskVulkanImage *self);
VkFormat gsk_vulkan_image_get_vk_format (GskVulkanImage *self);
VkFormat gsk_vulkan_image_get_vk_format (GskVulkanImage *self,
gboolean no_srgb);
VkFramebuffer gsk_vulkan_image_get_vk_framebuffer (GskVulkanImage *self,
gboolean no_srgb,
VkRenderPass pass);
static inline guint

View File

@@ -161,6 +161,7 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer);
graphene_rect_t opaque_tmp;
const graphene_rect_t *opaque;
GdkColorState *ccs;
cairo_t *cr;
if (gsk_render_node_get_opaque_rect (root, &opaque_tmp))
@@ -189,9 +190,15 @@ gsk_cairo_renderer_render (GskRenderer *renderer,
cairo_restore (cr);
}
ccs = gdk_draw_context_get_color_state (GDK_DRAW_CONTEXT (self->cairo_context));
if (gdk_draw_context_get_depth (GDK_DRAW_CONTEXT (self->cairo_context)) == GDK_MEMORY_U8_SRGB)
{
ccs = gdk_color_state_get_no_srgb_tf (ccs);
g_assert (ccs);
}
gsk_cairo_renderer_do_render (renderer,
cr,
gdk_draw_context_get_color_state (GDK_DRAW_CONTEXT (self->cairo_context)),
ccs,
root);
cairo_destroy (cr);

View File

@@ -81,14 +81,6 @@ gsk_color_stops_are_opaque (const GskColorStop *stops,
return TRUE;
}
/* FIXME: Replace this once GdkColor lands */
static inline GdkMemoryDepth
my_color_stops_get_depth (const GskColorStop *stops,
gsize n_stops)
{
return gdk_color_state_get_depth (GDK_COLOR_STATE_SRGB);
}
static inline gboolean
color_state_is_hdr (GdkColorState *color_state)
{
@@ -324,7 +316,7 @@ gsk_color_node_new2 (const GdkColor *color,
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->fully_opaque = gdk_color_is_opaque (color);
node->preferred_depth = gdk_color_get_depth (color);
node->preferred_depth = GDK_MEMORY_NONE;
node->is_hdr = color_state_is_hdr (color->color_state);
gdk_color_init_copy (&self->color, color);
@@ -505,7 +497,7 @@ gsk_linear_gradient_node_new (const graphene_rect_t *bounds,
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
node->preferred_depth = my_color_stops_get_depth (color_stops, n_color_stops);
node->preferred_depth = GDK_MEMORY_NONE;
gsk_rect_init_from_rect (&node->bounds, bounds);
gsk_rect_normalize (&node->bounds);
@@ -561,7 +553,7 @@ gsk_repeating_linear_gradient_node_new (const graphene_rect_t *bounds,
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
node->preferred_depth = my_color_stops_get_depth (color_stops, n_color_stops);
node->preferred_depth = GDK_MEMORY_NONE;
gsk_rect_init_from_rect (&node->bounds, bounds);
gsk_rect_normalize (&node->bounds);
@@ -845,7 +837,7 @@ gsk_radial_gradient_node_new (const graphene_rect_t *bounds,
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
node->preferred_depth = my_color_stops_get_depth (color_stops, n_color_stops);
node->preferred_depth = GDK_MEMORY_NONE;
gsk_rect_init_from_rect (&node->bounds, bounds);
gsk_rect_normalize (&node->bounds);
@@ -917,7 +909,7 @@ gsk_repeating_radial_gradient_node_new (const graphene_rect_t *bounds,
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
node->preferred_depth = my_color_stops_get_depth (color_stops, n_color_stops);
node->preferred_depth = GDK_MEMORY_NONE;
gsk_rect_init_from_rect (&node->bounds, bounds);
gsk_rect_normalize (&node->bounds);
@@ -1319,7 +1311,7 @@ gsk_conic_gradient_node_new (const graphene_rect_t *bounds,
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->fully_opaque = gsk_color_stops_are_opaque (color_stops, n_color_stops);
node->preferred_depth = my_color_stops_get_depth (color_stops, n_color_stops);
node->preferred_depth = GDK_MEMORY_NONE;
gsk_rect_init_from_rect (&node->bounds, bounds);
gsk_rect_normalize (&node->bounds);
@@ -1789,11 +1781,7 @@ gsk_border_node_new2 (const GskRoundedRect *outline,
self = gsk_render_node_alloc (GSK_BORDER_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->preferred_depth = gdk_memory_depth_merge (
gdk_memory_depth_merge (gdk_color_get_depth (&border_color[0]),
gdk_color_get_depth (&border_color[1])),
gdk_memory_depth_merge (gdk_color_get_depth (&border_color[2]),
gdk_color_get_depth (&border_color[3])));
node->preferred_depth = GDK_MEMORY_NONE;
gsk_rounded_rect_init_copy (&self->outline, outline);
memcpy (self->border_width, border_width, sizeof (self->border_width));
@@ -2811,7 +2799,7 @@ gsk_inset_shadow_node_new2 (const GskRoundedRect *outline,
self = gsk_render_node_alloc (GSK_INSET_SHADOW_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->preferred_depth = gdk_color_get_depth (color);
node->preferred_depth = GDK_MEMORY_NONE;
gsk_rounded_rect_init_copy (&self->outline, outline);
gdk_color_init_copy (&self->color, color);
@@ -3207,7 +3195,7 @@ gsk_outset_shadow_node_new2 (const GskRoundedRect *outline,
self = gsk_render_node_alloc (GSK_OUTSET_SHADOW_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->preferred_depth = gdk_color_get_depth (color);
node->preferred_depth = GDK_MEMORY_NONE;
gsk_rounded_rect_init_copy (&self->outline, outline);
gdk_color_init_copy (&self->color, color);
@@ -5799,7 +5787,6 @@ gsk_shadow_node_new2 (GskRenderNode *child,
GskShadowNode *self;
GskRenderNode *node;
gsize i;
GdkMemoryDepth depth;
gboolean is_hdr;
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
@@ -5814,7 +5801,6 @@ gsk_shadow_node_new2 (GskRenderNode *child,
self->n_shadows = n_shadows;
self->shadows = g_new (GskShadow2, n_shadows);
depth = gsk_render_node_get_preferred_depth (child);
is_hdr = gsk_render_node_is_hdr (child);
for (i = 0; i < n_shadows; i++)
@@ -5822,11 +5808,10 @@ gsk_shadow_node_new2 (GskRenderNode *child,
gdk_color_init_copy (&self->shadows[i].color, &shadows[i].color);
graphene_point_init_from_point (&self->shadows[i].offset, &shadows[i].offset);
self->shadows[i].radius = shadows[i].radius;
depth = gdk_memory_depth_merge (depth, gdk_color_get_depth (&shadows[i].color));
is_hdr = is_hdr || color_state_is_hdr (shadows[i].color.color_state);
}
node->preferred_depth = depth;
node->preferred_depth = gsk_render_node_get_preferred_depth (child);
node->is_hdr = is_hdr;
gsk_shadow_node_get_bounds (self, &node->bounds);
@@ -6518,7 +6503,7 @@ gsk_text_node_new2 (PangoFont *font,
self = gsk_render_node_alloc (GSK_TEXT_NODE);
node = (GskRenderNode *) self;
node->offscreen_for_opacity = FALSE;
node->preferred_depth = gdk_color_get_depth (color);
node->preferred_depth = GDK_MEMORY_NONE;
node->is_hdr = color_state_is_hdr (color->color_state);
self->fontmap = g_object_ref (pango_font_get_font_map (font));

View File

@@ -0,0 +1,18 @@
color-matrix {
matrix: matrix3d(65535, 0, 0, 0, 0, 65535, 0, 0, 0, 0, 65535, 0, 0, 0, 0, 1);
child: blend {
mode: difference;
bottom: texture {
bounds: 0 0 10 10;
texture: url("data:image/png;base64,\
iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKEAYAAADdohP+AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\
AZxpOzIAAAAfSURBVCiRY/w/n4GBgeH/fwYqASZqGTRq4KiBg8lAAH3dA7DFgV4pAAAAAElFTkSu\
QmCC\
");
}
top: color {
bounds: 0 0 10 10;
color: color(srgb 0.999 0 0);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

View File

@@ -31,6 +31,7 @@ compare_render_tests = [
'border-zero-width-color',
'borders-rotated',
'borders-scaled',
'bug-rgba8-offscreen-in-high-depth',
'clip-contained',
'clip-coordinates-2d',
'clip-coordinates-nocairo',