diff --git a/gdk/win32/gdkd3d12texture.c b/gdk/win32/gdkd3d12texture.c
new file mode 100644
index 0000000000..1d1fd6476f
--- /dev/null
+++ b/gdk/win32/gdkd3d12texture.c
@@ -0,0 +1,347 @@
+/* gdkd3d12texture.c
+ *
+ * Copyright 2024 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ */
+
+#include "config.h"
+
+#include "gdkd3d12textureprivate.h"
+
+#include "gdkcolorstateprivate.h"
+#include "gdkd3d12texturebuilder.h"
+#include "gdkdxgiformatprivate.h"
+#include "gdkmemoryformatprivate.h"
+#include "gdkprivate-win32.h"
+#include "gdktextureprivate.h"
+
+/**
+ * GdkD3D12Texture:
+ *
+ * A `GdkTexture` representing a [ID3D12Resource](https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nn-d3d12-id3d12resource).
+ *
+ * To create a `GdkD3D12Texture`, use the auxiliary
+ * [class@Gdk.D3d12TextureBuilder] object.
+ *
+ * D3D12 textures can only be created on Windows.
+ *
+ * Since: 4.18
+ */
+
+struct _GdkD3D12Texture
+{
+ GdkTexture parent_instance;
+
+ ID3D12Resource *resource;
+
+ GDestroyNotify destroy;
+ gpointer data;
+};
+
+struct _GdkD3D12TextureClass
+{
+ GdkTextureClass parent_class;
+};
+
+/**
+ * gdk_d3d12_error_quark:
+ *
+ * Registers an error quark for [class@Gdk.D3d12Texture] errors.
+ *
+ * Returns: the error quark
+ **/
+G_DEFINE_QUARK (gdk-d3d12-error-quark, gdk_d3d12_error)
+
+G_DEFINE_TYPE (GdkD3D12Texture, gdk_d3d12_texture, GDK_TYPE_TEXTURE)
+
+static void
+gdk_d3d12_texture_dispose (GObject *object)
+{
+ GdkD3D12Texture *self = GDK_D3D12_TEXTURE (object);
+
+ gdk_win32_com_clear (&self->resource);
+
+ if (self->destroy)
+ {
+ self->destroy (self->data);
+ self->destroy = NULL;
+ }
+
+ G_OBJECT_CLASS (gdk_d3d12_texture_parent_class)->dispose (object);
+}
+
+static gboolean
+supports_nonzero (ID3D12Device *device)
+{
+ D3D12_FEATURE_DATA_D3D12_OPTIONS7 options;
+ HRESULT hr;
+
+ hr = ID3D12Device_CheckFeatureSupport (device,
+ D3D12_FEATURE_D3D12_OPTIONS7,
+ &options,
+ sizeof (options));
+ return SUCCEEDED (hr);
+}
+
+#define hr_return_if_fail(expr) G_STMT_START {\
+ HRESULT _hr = (expr); \
+ if (!SUCCEEDED (_hr)) \
+ { \
+ g_log (G_LOG_DOMAIN, \
+ G_LOG_LEVEL_CRITICAL, \
+ "file %s: line %d (%s): %s returned %ld (%s)", \
+ __FILE__, \
+ __LINE__, \
+ G_STRFUNC, \
+ #expr, \
+ _hr, \
+ g_win32_error_message (_hr)); \
+ return; \
+ } \
+}G_STMT_END
+
+static void
+gdk_d3d12_texture_download (GdkTexture *texture,
+ GdkMemoryFormat format,
+ GdkColorState *color_state,
+ guchar *data,
+ gsize stride)
+{
+ GdkD3D12Texture *self = GDK_D3D12_TEXTURE (texture);
+ UINT64 buffer_size;
+ ID3D12Device *device;
+ ID3D12CommandAllocator *allocator;
+ ID3D12GraphicsCommandList *commands;
+ ID3D12CommandQueue *queue;
+ ID3D12Fence *fence;
+ ID3D12Resource *buffer;
+ D3D12_RESOURCE_DESC resource_desc;
+ D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint;
+ void *buffer_data;
+
+ hr_return_if_fail (ID3D12Resource_GetDevice (self->resource,
+ &IID_ID3D12Device,
+ (void **) &device));
+ ID3D12Resource_GetDesc (self->resource, &resource_desc);
+ ID3D12Device_GetCopyableFootprints (device,
+ &resource_desc,
+ 0, 1, 0,
+ &footprint,
+ NULL,
+ NULL,
+ NULL);
+ buffer_size = footprint.Footprint.RowPitch * footprint.Footprint.Height;
+
+ hr_return_if_fail (ID3D12Device_CreateCommittedResource (device,
+ (&(D3D12_HEAP_PROPERTIES) {
+ .Type = D3D12_HEAP_TYPE_READBACK,
+ .CreationNodeMask = 1,
+ .VisibleNodeMask = 1,
+ }),
+ supports_nonzero (device) ? D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
+ : D3D12_HEAP_FLAG_NONE,
+ (&(D3D12_RESOURCE_DESC) {
+ .Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
+ .Width = buffer_size,
+ .Height = 1,
+ .DepthOrArraySize = 1,
+ .MipLevels = 1,
+ .SampleDesc = {
+ .Count = 1,
+ .Quality = 0,
+ },
+ .Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
+ }),
+ D3D12_RESOURCE_STATE_COMMON,
+ NULL,
+ &IID_ID3D12Resource,
+ (void **) &buffer));
+
+ hr_return_if_fail (ID3D12Device_CreateFence (device,
+ 0,
+ D3D12_FENCE_FLAG_NONE,
+ &IID_ID3D12Fence,
+ (void **) &fence));
+
+ hr_return_if_fail (ID3D12Device_CreateCommandQueue (device,
+ (&(D3D12_COMMAND_QUEUE_DESC) {
+ .Type = D3D12_COMMAND_LIST_TYPE_COPY,
+ .Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
+ .Flags = D3D12_COMMAND_QUEUE_FLAG_NONE,
+ }),
+ &IID_ID3D12CommandQueue,
+ (void **) &queue));
+ hr_return_if_fail (ID3D12Device_CreateCommandAllocator (device,
+ D3D12_COMMAND_LIST_TYPE_COPY,
+ &IID_ID3D12CommandAllocator,
+ (void **) &allocator));
+ hr_return_if_fail (ID3D12Device_CreateCommandList (device,
+ 0,
+ D3D12_COMMAND_LIST_TYPE_COPY,
+ allocator,
+ NULL,
+ &IID_ID3D12GraphicsCommandList,
+ (void **) &commands));
+
+ ID3D12GraphicsCommandList_CopyTextureRegion (commands,
+ (&(D3D12_TEXTURE_COPY_LOCATION) {
+ .pResource = buffer,
+ .Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
+ .PlacedFootprint = footprint,
+ }),
+ 0, 0, 0,
+ (&(D3D12_TEXTURE_COPY_LOCATION) {
+ .pResource = self->resource,
+ .Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
+ .SubresourceIndex = 0,
+ }),
+ NULL);
+ hr_return_if_fail (ID3D12GraphicsCommandList_Close (commands));
+ ID3D12CommandQueue_ExecuteCommandLists (queue, 1, (ID3D12CommandList **) &commands);
+
+#define FENCE_SIGNAL 1
+ hr_return_if_fail (ID3D12CommandQueue_Signal (queue, fence, FENCE_SIGNAL));
+ hr_return_if_fail (ID3D12Fence_SetEventOnCompletion (fence, FENCE_SIGNAL, NULL));
+
+ hr_return_if_fail (ID3D12Resource_Map (buffer,
+ 0,
+ (&(D3D12_RANGE) {
+ .Begin = 0,
+ .End = buffer_size,
+ }),
+ &buffer_data));
+
+ gdk_dxgi_format_convert (resource_desc.Format,
+ gdk_memory_format_alpha (texture->format) != GDK_MEMORY_ALPHA_STRAIGHT,
+ buffer_data,
+ footprint.Footprint.RowPitch,
+ texture->color_state,
+ format,
+ data,
+ stride,
+ color_state,
+ texture->width,
+ texture->height);
+
+ ID3D12Resource_Unmap (buffer, 0, (&(D3D12_RANGE) { 0, 0 }));
+
+ gdk_win32_com_clear (&buffer);
+ gdk_win32_com_clear (&commands);
+ gdk_win32_com_clear (&allocator);
+ gdk_win32_com_clear (&queue);
+ gdk_win32_com_clear (&fence);
+ gdk_win32_com_clear (&device);
+}
+
+static void
+gdk_d3d12_texture_class_init (GdkD3D12TextureClass *klass)
+{
+ GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ texture_class->download = gdk_d3d12_texture_download;
+
+ gobject_class->dispose = gdk_d3d12_texture_dispose;
+}
+
+static void
+gdk_d3d12_texture_init (GdkD3D12Texture *self)
+{
+}
+
+GdkTexture *
+gdk_d3d12_texture_new_from_builder (GdkD3D12TextureBuilder *builder,
+ GDestroyNotify destroy,
+ gpointer data,
+ GError **error)
+{
+ GdkD3D12Texture *self;
+ GdkTexture *update_texture;
+ GdkColorState *color_state;
+ GdkMemoryFormat format;
+ ID3D12Resource *resource;
+ D3D12_RESOURCE_DESC desc;
+ gboolean premultiplied;
+
+ resource = gdk_d3d12_texture_builder_get_resource (builder);
+ premultiplied = gdk_d3d12_texture_builder_get_premultiplied (builder);
+ ID3D12Resource_GetDesc (resource, &desc);
+
+ if (desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
+ {
+ g_set_error (error,
+ GDK_D3D12_ERROR, GDK_D3D12_ERROR_UNSUPPORTED_FORMAT,
+ "Resource must be 2D texture");
+ return NULL;
+ }
+
+ if (!gdk_dxgi_format_is_supported (desc.Format))
+ {
+ g_set_error (error,
+ GDK_D3D12_ERROR, GDK_D3D12_ERROR_UNSUPPORTED_FORMAT,
+ "Unsupported DXGI format %u", desc.Format);
+ return NULL;
+ }
+
+ format = gdk_dxgi_format_get_memory_format (desc.Format, premultiplied);
+
+ /* FIXME: Do we need to validate the desc.SampleDesc? */
+
+ color_state = gdk_d3d12_texture_builder_get_color_state (builder);
+ if (color_state == NULL)
+ color_state = gdk_color_state_get_srgb ();
+
+ self = (GdkD3D12Texture *) g_object_new (GDK_TYPE_D3D12_TEXTURE,
+ "width", (int) desc.Width,
+ "height", (int) desc.Height,
+ "color-state", color_state,
+ NULL);
+
+ GDK_TEXTURE (self)->format = format;
+ ID3D12Resource_AddRef (resource);
+ self->resource = resource;
+
+ GDK_DEBUG (D3D12,
+ "Creating %ux%u D3D12 texture, format %u",
+ (UINT) desc.Width, desc.Height,
+ desc.Format);
+
+ /* Set this only once we know that the texture will be created.
+ * Otherwise dispose() will run the callback */
+ self->destroy = destroy;
+ self->data = data;
+
+ update_texture = gdk_d3d12_texture_builder_get_update_texture (builder);
+ if (update_texture)
+ {
+ cairo_region_t *update_region = gdk_d3d12_texture_builder_get_update_region (builder);
+ if (update_region)
+ {
+ cairo_rectangle_int_t tex_rect = { 0, 0,
+ update_texture->width, update_texture->height };
+ update_region = cairo_region_copy (update_region);
+ cairo_region_intersect_rectangle (update_region, &tex_rect);
+ gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region);
+ }
+ }
+
+ return GDK_TEXTURE (self);
+
+#if 0
+ g_set_error_literal (error, GDK_D3D12_ERROR, GDK_D3D12_ERROR_NOT_AVAILABLE,
+ "d3d12 support disabled at compile-time.");
+ return NULL;
+#endif
+}
diff --git a/gdk/win32/gdkd3d12texture.h b/gdk/win32/gdkd3d12texture.h
new file mode 100644
index 0000000000..abe172ec25
--- /dev/null
+++ b/gdk/win32/gdkd3d12texture.h
@@ -0,0 +1,67 @@
+/* gdkd3d12texture.h
+ *
+ * Copyright 2024 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ */
+
+#pragma once
+
+#if !defined (__GDKWIN32_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_D3D12_TEXTURE (gdk_d3d12_texture_get_type ())
+
+#define GDK_D3D12_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_D3D12_TEXTURE, GdkD3D12Texture))
+#define GDK_IS_D3D12_TEXTURE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_D3D12_TEXTURE))
+
+#define GDK_D3D12_ERROR (gdk_d3d12_error_quark ())
+
+typedef struct _GdkD3D12Texture GdkD3D12Texture;
+typedef struct _GdkD3D12TextureClass GdkD3D12TextureClass;
+
+/**
+ * GdkD3D12Error:
+ * @GDK_D3D12_ERROR_NOT_AVAILABLE: D3D12 support is not available, because the OS
+ * is not Windows, the Windows version is not recent enough, or it was explicitly
+ * disabled at compile- or runtime
+ * @GDK_D3D12_ERROR_UNSUPPORTED_FORMAT: The requested format is not supported
+ * @GDK_D3D12_ERROR_CREATION_FAILED: GTK failed to create the resource for other
+ * reasons
+ *
+ * Error enumeration for `GdkD3D12Texture`.
+ *
+ * Since: 4.18
+ */
+typedef enum {
+ GDK_D3D12_ERROR_NOT_AVAILABLE,
+ GDK_D3D12_ERROR_UNSUPPORTED_FORMAT,
+ GDK_D3D12_ERROR_CREATION_FAILED,
+} GdkD3D12Error;
+
+GDK_AVAILABLE_IN_4_18
+GType gdk_d3d12_texture_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_4_18
+GQuark gdk_d3d12_error_quark (void) G_GNUC_CONST;
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkD3D12Texture, g_object_unref)
+
+G_END_DECLS
diff --git a/gdk/win32/gdkd3d12texturebuilder.c b/gdk/win32/gdkd3d12texturebuilder.c
new file mode 100644
index 0000000000..66df70d171
--- /dev/null
+++ b/gdk/win32/gdkd3d12texturebuilder.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright © 2024 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Benjamin Otte
+ */
+
+#include "config.h"
+
+#include "gdkd3d12texturebuilder.h"
+
+#include "gdkdebugprivate.h"
+#include "gdkcolorstate.h"
+#include "gdkd3d12textureprivate.h"
+#include "gdkprivate-win32.h"
+
+#include
+
+struct _GdkD3D12TextureBuilder
+{
+ GObject parent_instance;
+
+ ID3D12Resource *resource;
+
+ GdkColorState *color_state;
+ gboolean premultiplied;
+
+ GdkTexture *update_texture;
+ cairo_region_t *update_region;
+};
+
+struct _GdkD3D12TextureBuilderClass
+{
+ GObjectClass parent_class;
+};
+
+/**
+ * GdkD3D12TextureBuilder:
+ *
+ * `GdkD3D12TextureBuilder` is a builder used to construct [class@Gdk.Texture]
+ * objects from [ID3D12Resources](https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nn-d3d12-id3d12resource).
+ *
+ * The operation of `GdkD3D12TextureBuilder` is quite simple: Create a texture builder,
+ * set all the necessary properties, and then call [method@Gdk.D3d12TextureBuilder.build]
+ * to create the new texture.
+ *
+ * Not all `D3D12Resources` can be used. You have to use a texture resource for a `GdkTexture`.
+ * GDK will attempt to detect invalid resources and fail to create the texture in that case.
+
+ * `GdkD3D12TextureBuilder` can be used for quick one-shot construction of
+ * textures as well as kept around and reused to construct multiple textures.
+ *
+ * Since: 4.18
+ */
+
+enum
+{
+ PROP_0,
+ PROP_COLOR_STATE,
+ PROP_RESOURCE,
+ PROP_PREMULTIPLIED,
+ PROP_UPDATE_REGION,
+ PROP_UPDATE_TEXTURE,
+
+ N_PROPS
+};
+
+G_DEFINE_TYPE (GdkD3D12TextureBuilder, gdk_d3d12_texture_builder, G_TYPE_OBJECT)
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static void
+gdk_d3d12_texture_builder_dispose (GObject *object)
+{
+ GdkD3D12TextureBuilder *self = GDK_D3D12_TEXTURE_BUILDER (object);
+
+ g_clear_object (&self->update_texture);
+ g_clear_pointer (&self->update_region, cairo_region_destroy);
+ g_clear_pointer (&self->color_state, gdk_color_state_unref);
+
+ gdk_win32_com_clear (&self->resource);
+
+ G_OBJECT_CLASS (gdk_d3d12_texture_builder_parent_class)->dispose (object);
+}
+
+static void
+gdk_d3d12_texture_builder_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdkD3D12TextureBuilder *self = GDK_D3D12_TEXTURE_BUILDER (object);
+
+ switch (property_id)
+ {
+ case PROP_COLOR_STATE:
+ g_value_set_boxed (value, self->color_state);
+ break;
+
+ case PROP_PREMULTIPLIED:
+ g_value_set_boolean (value, self->premultiplied);
+ break;
+
+ case PROP_RESOURCE:
+ g_value_set_pointer (value, self->resource);
+ break;
+
+ case PROP_UPDATE_REGION:
+ g_value_set_boxed (value, self->update_region);
+ break;
+
+ case PROP_UPDATE_TEXTURE:
+ g_value_set_object (value, self->update_texture);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_d3d12_texture_builder_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdkD3D12TextureBuilder *self = GDK_D3D12_TEXTURE_BUILDER (object);
+
+ switch (property_id)
+ {
+ case PROP_COLOR_STATE:
+ gdk_d3d12_texture_builder_set_color_state (self, g_value_get_boxed (value));
+ break;
+
+ case PROP_PREMULTIPLIED:
+ gdk_d3d12_texture_builder_set_premultiplied (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_RESOURCE:
+ gdk_d3d12_texture_builder_set_resource (self, g_value_get_pointer (value));
+ break;
+
+ case PROP_UPDATE_REGION:
+ gdk_d3d12_texture_builder_set_update_region (self, g_value_get_boxed (value));
+ break;
+
+ case PROP_UPDATE_TEXTURE:
+ gdk_d3d12_texture_builder_set_update_texture (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdk_d3d12_texture_builder_class_init (GdkD3D12TextureBuilderClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = gdk_d3d12_texture_builder_dispose;
+ gobject_class->get_property = gdk_d3d12_texture_builder_get_property;
+ gobject_class->set_property = gdk_d3d12_texture_builder_set_property;
+
+ /**
+ * GdkD3D12TextureBuilder:color-state:
+ *
+ * The color state of the texture.
+ *
+ * Since: 4.18
+ */
+ properties[PROP_COLOR_STATE] =
+ g_param_spec_boxed ("color-state", NULL, NULL,
+ GDK_TYPE_COLOR_STATE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GdkD3D12TextureBuilder:premultiplied:
+ *
+ * Whether the alpha channel is premultiplied into the others.
+ *
+ * Only relevant if the format has alpha.
+ *
+ * Since: 4.18
+ */
+ properties[PROP_PREMULTIPLIED] =
+ g_param_spec_boolean ("premultiplied", NULL, NULL,
+ TRUE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GdkD3D12TextureBuilder:resource:
+ *
+ * The `ID3D12Resource`
+ *
+ * Since: 4.18
+ */
+ properties[PROP_RESOURCE] =
+ g_param_spec_pointer ("resource", NULL, NULL,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GdkD3D12TextureBuilder:update-region:
+ *
+ * The update region for [property@Gdk.D3d12TextureBuilder:update-texture].
+ *
+ * Since: 4.18
+ */
+ properties[PROP_UPDATE_REGION] =
+ g_param_spec_boxed ("update-region", NULL, NULL,
+ CAIRO_GOBJECT_TYPE_REGION,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * GdkD3D12TextureBuilder:update-texture:
+ *
+ * The texture [property@Gdk.D3d12TextureBuilder:update-region] is an update for.
+ *
+ * Since: 4.18
+ */
+ properties[PROP_UPDATE_TEXTURE] =
+ g_param_spec_object ("update-texture", NULL, NULL,
+ GDK_TYPE_TEXTURE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+static void
+gdk_d3d12_texture_builder_init (GdkD3D12TextureBuilder *self)
+{
+ self->premultiplied = TRUE;
+}
+
+/**
+ * gdk_d3d12_texture_builder_new: (constructor):
+ *
+ * Creates a new texture builder.
+ *
+ * Returns: the new `GdkTextureBuilder`
+ *
+ * Since: 4.18
+ **/
+GdkD3D12TextureBuilder *
+gdk_d3d12_texture_builder_new (void)
+{
+ return (GdkD3D12TextureBuilder *) g_object_new (GDK_TYPE_D3D12_TEXTURE_BUILDER, NULL);
+}
+
+/**
+ * gdk_d3d12_texture_builder_get_resource:
+ * @self: a `GdkD3D12TextureBuilder`
+ *
+ * Returns the resource that this texture builder is
+ * associated with.
+ *
+ * Returns: (nullable) (transfer none): the resource
+ *
+ * Since: 4.18
+ */
+ID3D12Resource *
+gdk_d3d12_texture_builder_get_resource (GdkD3D12TextureBuilder *self)
+{
+ g_return_val_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self), NULL);
+
+ return self->resource;
+}
+
+/**
+ * gdk_d3d12_texture_builder_set_resource:
+ * @self: a `GdkD3D12TextureBuilder`
+ * @resource: the resource
+ *
+ * Sets the resource that this texture builder is going to construct
+ * a texture for.
+ *
+ * Since: 4.18
+ */
+void
+gdk_d3d12_texture_builder_set_resource (GdkD3D12TextureBuilder *self,
+ ID3D12Resource *resource)
+{
+ g_return_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self));
+
+ if (self->resource == resource)
+ return;
+
+ if (resource)
+ ID3D12Resource_AddRef (resource);
+ if (self->resource)
+ ID3D12Resource_Release (self->resource);
+ self->resource = resource;
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RESOURCE]);
+}
+
+/**
+ * gdk_d3d12_texture_builder_get_premultiplied:
+ * @self: a `GdkD3D12TextureBuilder`
+ *
+ * Whether the data is premultiplied.
+ *
+ * Returns: whether the data is premultiplied
+ *
+ * Since: 4.18
+ */
+gboolean
+gdk_d3d12_texture_builder_get_premultiplied (GdkD3D12TextureBuilder *self)
+{
+ g_return_val_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self), TRUE);
+
+ return self->premultiplied;
+}
+
+/**
+ * gdk_d3d12_texture_builder_set_premultiplied:
+ * @self: a `GdkD3D12TextureBuilder`
+ * @premultiplied: whether the data is premultiplied
+ *
+ * Sets whether the data is premultiplied.
+ *
+ * Unless otherwise specified, all formats including alpha channels are assumed
+ * to be premultiplied.
+ *
+ * Since: 4.18
+ */
+void
+gdk_d3d12_texture_builder_set_premultiplied (GdkD3D12TextureBuilder *self,
+ gboolean premultiplied)
+{
+ g_return_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self));
+
+ if (self->premultiplied == premultiplied)
+ return;
+
+ self->premultiplied = premultiplied;
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PREMULTIPLIED]);
+}
+
+/**
+ * gdk_d3d12_texture_builder_get_color_state:
+ * @self: a `GdkD3D12TextureBuilder`
+ *
+ * Gets the color state previously set via gdk_d3d12_texture_builder_set_color_state().
+ *
+ * Returns: (nullable) (transfer none): the color state
+ *
+ * Since: 4.18
+ */
+GdkColorState *
+gdk_d3d12_texture_builder_get_color_state (GdkD3D12TextureBuilder *self)
+{
+ g_return_val_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self), NULL);
+
+ return self->color_state;
+}
+
+/**
+ * gdk_d3d12_texture_builder_set_color_state:
+ * @self: a `GdkD3D12TextureBuilder`
+ * @color_state: (nullable): a `GdkColorState` or `NULL` to unset the colorstate.
+ *
+ * Sets the color state for the texture.
+ *
+ * By default, the colorstate is `NULL`. In that case, GTK will choose the
+ * correct colorstate based on the format.
+ * If you don't know what colorstates are, this is probably the right thing.
+ *
+ * Since: 4.18
+ */
+void
+gdk_d3d12_texture_builder_set_color_state (GdkD3D12TextureBuilder *self,
+ GdkColorState *color_state)
+{
+ g_return_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self));
+
+ if (self->color_state == color_state ||
+ (self->color_state != NULL && color_state != NULL && gdk_color_state_equal (self->color_state, color_state)))
+ return;
+
+ g_clear_pointer (&self->color_state, gdk_color_state_unref);
+ self->color_state = color_state;
+ if (color_state)
+ gdk_color_state_ref (color_state);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]);
+}
+
+/**
+ * gdk_d3d12_texture_builder_get_update_texture:
+ * @self: a `GdkD3D12TextureBuilder`
+ *
+ * Gets the texture previously set via gdk_d3d12_texture_builder_set_update_texture() or
+ * %NULL if none was set.
+ *
+ * Returns: (transfer none) (nullable): The texture
+ *
+ * Since: 4.18
+ */
+GdkTexture *
+gdk_d3d12_texture_builder_get_update_texture (GdkD3D12TextureBuilder *self)
+{
+ g_return_val_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self), NULL);
+
+ return self->update_texture;
+}
+
+/**
+ * gdk_d3d12_texture_builder_set_update_texture:
+ * @self: a `GdkD3D12TextureBuilder`
+ * @texture: (nullable): the texture to update
+ *
+ * Sets the texture to be updated by this texture. See
+ * [method@Gdk.D3d12TextureBuilder.set_update_region] for an explanation.
+ *
+ * Since: 4.18
+ */
+void
+gdk_d3d12_texture_builder_set_update_texture (GdkD3D12TextureBuilder *self,
+ GdkTexture *texture)
+{
+ g_return_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self));
+ g_return_if_fail (texture == NULL || GDK_IS_TEXTURE (texture));
+
+ if (!g_set_object (&self->update_texture, texture))
+ return;
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_TEXTURE]);
+}
+
+/**
+ * gdk_d3d12_texture_builder_get_update_region:
+ * @self: a `GdkD3D12TextureBuilder`
+ *
+ * Gets the region previously set via gdk_d3d12_texture_builder_set_update_region() or
+ * %NULL if none was set.
+ *
+ * Returns: (transfer none) (nullable): The region
+ *
+ * Since: 4.18
+ */
+cairo_region_t *
+gdk_d3d12_texture_builder_get_update_region (GdkD3D12TextureBuilder *self)
+{
+ g_return_val_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self), NULL);
+
+ return self->update_region;
+}
+
+/**
+ * gdk_d3d12_texture_builder_set_update_region:
+ * @self: a `GdkD3D12TextureBuilder`
+ * @region: (nullable): the region to update
+ *
+ * Sets the region to be updated by this texture. Together with
+ * [property@Gdk.D3d12TextureBuilder:update-texture] this describes an
+ * update of a previous texture.
+ *
+ * When rendering animations of large textures, it is possible that
+ * consecutive textures are only updating contents in parts of the texture.
+ * It is then possible to describe this update via these two properties,
+ * so that GTK can avoid rerendering parts that did not change.
+ *
+ * An example would be a screen recording where only the mouse pointer moves.
+ *
+ * Since: 4.18
+ */
+void
+gdk_d3d12_texture_builder_set_update_region (GdkD3D12TextureBuilder *self,
+ cairo_region_t *region)
+{
+ g_return_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self));
+
+ if (self->update_region == region)
+ return;
+
+ g_clear_pointer (&self->update_region, cairo_region_destroy);
+
+ if (region)
+ self->update_region = cairo_region_reference (region);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_REGION]);
+}
+
+/**
+ * gdk_d3d12_texture_builder_build:
+ * @self: a `GdkD3D12TextureBuilder`
+ * @destroy: (nullable): destroy function to be called when the texture is
+ * released
+ * @data: user data to pass to the destroy function
+ * @error: Return location for an error
+ *
+ * Builds a new `GdkTexture` with the values set up in the builder.
+ *
+ * It is a programming error to call this function if any mandatory property has not been set.
+ *
+ * Not all formats defined in the `drm_fourcc.h` header are supported. You can use
+ * [method@Gdk.Display.get_d3d12_formats] to get a list of supported formats. If the
+ * format is not supported by GTK, %NULL will be returned and @error will be set.
+ *
+ * The `destroy` function gets called when the returned texture gets released.
+ *
+ * It is the responsibility of the caller to keep the file descriptors for the planes
+ * open until the created texture is no longer used, and close them afterwards (possibly
+ * using the @destroy notify).
+ *
+ * It is possible to call this function multiple times to create multiple textures,
+ * possibly with changing properties in between.
+ *
+ * Returns: (transfer full) (nullable): a newly built `GdkTexture` or `NULL`
+ * if the format is not supported
+ *
+ * Since: 4.18
+ */
+GdkTexture *
+gdk_d3d12_texture_builder_build (GdkD3D12TextureBuilder *self,
+ GDestroyNotify destroy,
+ gpointer data,
+ GError **error)
+{
+ g_return_val_if_fail (GDK_IS_D3D12_TEXTURE_BUILDER (self), NULL);
+ g_return_val_if_fail (destroy == NULL || data != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (self->resource, NULL);
+
+ return gdk_d3d12_texture_new_from_builder (self, destroy, data, error);
+}
diff --git a/gdk/win32/gdkd3d12texturebuilder.h b/gdk/win32/gdkd3d12texturebuilder.h
new file mode 100644
index 0000000000..f3a4eff7fc
--- /dev/null
+++ b/gdk/win32/gdkd3d12texturebuilder.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2024 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors: Benjamin Otte
+ */
+
+#pragma once
+
+#if !defined (__GDKWIN32_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#include
+
+#include
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_D3D12_TEXTURE_BUILDER (gdk_d3d12_texture_builder_get_type ())
+GDK_AVAILABLE_IN_4_18
+GDK_DECLARE_INTERNAL_TYPE (GdkD3D12TextureBuilder, gdk_d3d12_texture_builder, GDK, D3D12_TEXTURE_BUILDER, GObject)
+
+typedef struct _GdkD3D12TextureBuilder GdkD3D12TextureBuilder;
+
+GDK_AVAILABLE_IN_4_18
+GdkD3D12TextureBuilder * gdk_d3d12_texture_builder_new (void);
+
+GDK_AVAILABLE_IN_4_18
+ID3D12Resource * gdk_d3d12_texture_builder_get_resource (GdkD3D12TextureBuilder *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_18
+void gdk_d3d12_texture_builder_set_resource (GdkD3D12TextureBuilder *self,
+ ID3D12Resource *resource);
+
+GDK_AVAILABLE_IN_4_18
+gboolean gdk_d3d12_texture_builder_get_premultiplied (GdkD3D12TextureBuilder *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_18
+void gdk_d3d12_texture_builder_set_premultiplied (GdkD3D12TextureBuilder *self,
+ gboolean premultiplied);
+
+GDK_AVAILABLE_IN_4_18
+GdkColorState * gdk_d3d12_texture_builder_get_color_state (GdkD3D12TextureBuilder *self);
+GDK_AVAILABLE_IN_4_18
+void gdk_d3d12_texture_builder_set_color_state (GdkD3D12TextureBuilder *self,
+ GdkColorState *color_state);
+
+GDK_AVAILABLE_IN_4_18
+GdkTexture * gdk_d3d12_texture_builder_get_update_texture (GdkD3D12TextureBuilder *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_18
+void gdk_d3d12_texture_builder_set_update_texture (GdkD3D12TextureBuilder *self,
+ GdkTexture *texture);
+
+GDK_AVAILABLE_IN_4_18
+cairo_region_t * gdk_d3d12_texture_builder_get_update_region (GdkD3D12TextureBuilder *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_18
+void gdk_d3d12_texture_builder_set_update_region (GdkD3D12TextureBuilder *self,
+ cairo_region_t *region);
+
+GDK_AVAILABLE_IN_4_18
+GdkTexture * gdk_d3d12_texture_builder_build (GdkD3D12TextureBuilder *self,
+ GDestroyNotify destroy,
+ gpointer data,
+ GError **error);
+
+G_END_DECLS
+
diff --git a/gdk/win32/gdkd3d12textureprivate.h b/gdk/win32/gdkd3d12textureprivate.h
new file mode 100644
index 0000000000..4ee6e848f3
--- /dev/null
+++ b/gdk/win32/gdkd3d12textureprivate.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "gdkd3d12texture.h"
+
+#include "gdkd3d12texturebuilder.h"
+
+G_BEGIN_DECLS
+
+GdkTexture * gdk_d3d12_texture_new_from_builder (GdkD3D12TextureBuilder *builder,
+ GDestroyNotify destroy,
+ gpointer data,
+ GError **error);
+
+G_END_DECLS
+
diff --git a/gdk/win32/gdkwin32.h b/gdk/win32/gdkwin32.h
index ed4a7749cd..93d5c76c18 100644
--- a/gdk/win32/gdkwin32.h
+++ b/gdk/win32/gdkwin32.h
@@ -26,6 +26,8 @@
#define __GDKWIN32_H_INSIDE__
+#include
+#include
#include
#include
#include
diff --git a/gdk/win32/meson.build b/gdk/win32/meson.build
index 18600542cb..601b7b6b31 100644
--- a/gdk/win32/meson.build
+++ b/gdk/win32/meson.build
@@ -1,5 +1,7 @@
gdk_win32_public_sources = files([
'gdkcursor-win32.c',
+ 'gdkd3d12texture.c',
+ 'gdkd3d12texturebuilder.c',
'gdkdisplay-win32.c',
'gdkdisplaymanager-win32.c',
'gdkdrag-win32.c',
@@ -39,6 +41,8 @@ gdk_win32_sources = gdk_win32_public_sources + files([
])
gdk_win32_public_headers = files([
+ 'gdkd3d12texture.h',
+ 'gdkd3d12texturebuilder.h',
'gdkwin32cursor.h',
'gdkwin32display.h',
'gdkwin32displaymanager.h',