win32: Import D3D12 resources into Vulkan renderer

This commit is contained in:
Benjamin Otte
2024-11-02 19:39:17 +01:00
parent 9ae76f6e69
commit 90d09a1180
7 changed files with 627 additions and 2 deletions

View File

@@ -359,6 +359,12 @@ gdk_d3d12_texture_new_from_builder (GdkD3D12TextureBuilder *builder,
#endif
}
ID3D12Resource *
gdk_d3d12_texture_get_resource (GdkD3D12Texture *self)
{
return self->resource;
}
G_LOCK_DEFINE_STATIC(handle_creation);
HANDLE

View File

@@ -11,6 +11,7 @@ GdkTexture * gdk_d3d12_texture_new_from_builder (GdkD3D1
gpointer data,
GError **error);
ID3D12Resource * gdk_d3d12_texture_get_resource (GdkD3D12Texture *self);
HANDLE gdk_d3d12_texture_get_resource_handle (GdkD3D12Texture *self);
guint gdk_d3d12_texture_import_gl (GdkD3D12Texture *self,

File diff suppressed because it is too large Load Diff

View File

@@ -5,6 +5,9 @@
#include <directx/d3d12.h>
#include <epoxy/gl.h>
#ifdef GDK_RENDERING_VULKAN
#include <vulkan/vulkan.h>
#endif
gboolean gdk_dxgi_format_is_supported (DXGI_FORMAT dxgi_format);
GdkMemoryFormat gdk_dxgi_format_get_memory_format (DXGI_FORMAT dxgi_format,
@@ -12,7 +15,10 @@ GdkMemoryFormat gdk_dxgi_format_get_memory_format (DXGI_FORMAT
gboolean gdk_dxgi_format_is_yuv (DXGI_FORMAT dxgi_format);
GLenum gdk_dxgi_format_get_gl_format (DXGI_FORMAT dxgi_format);
#ifdef GDK_RENDERING_VULKAN
VkFormat gdk_dxgi_format_get_vk_format (DXGI_FORMAT dxgi_format,
VkComponentMapping *out_swizzle);
#endif
void gdk_dxgi_format_convert (DXGI_FORMAT src_format,
gboolean src_premultiplied,
const guchar *src_data,

View File

@@ -11,6 +11,10 @@
#include "gdk/gdkglcontextprivate.h"
#include "gdk/gdkgltextureprivate.h"
#ifdef GDK_WINDOWING_WIN32
#include "gdk/win32/gdkd3d12textureprivate.h"
#endif
#define GDK_ARRAY_NAME gsk_semaphores
#define GDK_ARRAY_TYPE_NAME GskSemaphores
#define GDK_ARRAY_ELEMENT_TYPE VkSemaphore
@@ -226,6 +230,23 @@ gsk_vulkan_frame_upload_texture (GskGpuFrame *frame,
}
}
#endif
#ifdef GDK_WINDOWING_WIN32
if (GDK_IS_D3D12_TEXTURE (texture))
{
GdkD3D12Texture *d3d_texture = GDK_D3D12_TEXTURE (texture);
GskGpuImage *image;
image = gsk_vulkan_image_new_for_d3d12resource (GSK_VULKAN_DEVICE (gsk_gpu_frame_get_device (frame)),
gdk_d3d12_texture_get_resource (d3d_texture),
gdk_d3d12_texture_get_resource_handle (d3d_texture),
gdk_memory_format_alpha (gdk_texture_get_format (texture)) != GDK_MEMORY_ALPHA_STRAIGHT);
if (image)
{
gsk_gpu_image_toggle_ref_texture (image, texture);
return image;
}
}
#endif
return GSK_GPU_FRAME_CLASS (gsk_vulkan_frame_parent_class)->upload_texture (frame, with_mipmap, texture);
}

View File

@@ -18,6 +18,9 @@
#ifdef HAVE_DMABUF
#include <linux/dma-buf.h>
#endif
#ifdef GDK_WINDOWING_WIN32
#include <gdk/win32/gdkdxgiformatprivate.h>
#endif
struct _GskVulkanImage
{
@@ -1284,6 +1287,207 @@ gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self,
}
#endif
#ifdef GDK_WINDOWING_WIN32
static gboolean
gsk_vulkan_is_same_device (VkDevice vk_device,
ID3D12DeviceChild *child)
{
/* FIXME: implement */
return TRUE;
}
GskGpuImage *
gsk_vulkan_image_new_for_d3d12resource (GskVulkanDevice *device,
ID3D12Resource *resource,
HANDLE resource_handle,
gboolean premultiplied)
{
GskVulkanImage *self;
VkDevice vk_device;
VkFormat vk_format;
VkComponentMapping vk_components;
VkSamplerYcbcrConversion vk_conversion;
PFN_vkGetMemoryWin32HandlePropertiesKHR func_vkGetMemoryWin32HandlePropertiesKHR;
VkResult res;
GdkMemoryFormat format;
GskGpuImageFlags flags;
D3D12_RESOURCE_DESC desc;
gsize memory_index;
gboolean is_yuv;
VkMemoryRequirements2 requirements = {
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
};
VkMemoryWin32HandlePropertiesKHR handle_properties = {
.sType = VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR,
};
if (!gsk_vulkan_device_has_feature (device, GDK_VULKAN_FEATURE_WIN32))
{
GDK_DEBUG (D3D12, "Vulkan does not support D3D12Resource import");
return NULL;
}
vk_device = gsk_vulkan_device_get_vk_device (device);
func_vkGetMemoryWin32HandlePropertiesKHR = (PFN_vkGetMemoryWin32HandlePropertiesKHR) vkGetDeviceProcAddr (vk_device, "vkGetMemoryWin32HandlePropertiesKHR");
ID3D12Resource_GetDesc (resource, &desc);
if (!gsk_vulkan_is_same_device (vk_device, (ID3D12DeviceChild *) resource))
{
GDK_DEBUG (D3D12, "Resource is from a different device");
return NULL;
}
vk_format = gdk_dxgi_format_get_vk_format (desc.Format, &vk_components);
if (vk_format == VK_FORMAT_UNDEFINED)
{
GDK_DEBUG (D3D12, "GTK's Vulkan doesn't support DXGI format %u", desc.Format);
return NULL;
}
is_yuv = gdk_dxgi_format_is_yuv (desc.Format);
if (is_yuv && !gsk_vulkan_device_has_feature (device, GDK_VULKAN_FEATURE_YCBCR))
{
GDK_DEBUG (D3D12, "Vulkan driver cannot import DXGI format %u because it is YUV", desc.Format);
return NULL;
}
#if 0
if (!gsk_vulkan_device_supports_format (device,
vk_format,
dmabuf->modifier,
dmabuf->n_planes,
VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT,
VK_IMAGE_USAGE_SAMPLED_BIT,
width, height,
&flags))
{
GDK_DEBUG (DMABUF, "Vulkan driver does not support format %.4s::%016llx with %u planes",
(char *) &dmabuf->fourcc, (unsigned long long) dmabuf->modifier, dmabuf->n_planes);
return NULL;
}
#else
flags = 0;
#endif
self = g_object_new (GSK_TYPE_VULKAN_IMAGE, NULL);
self->device = g_object_ref (device);
self->vk_tiling = VK_IMAGE_TILING_OPTIMAL;
self->vk_format = 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;
res = vkCreateImage (vk_device,
&(VkImageCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.flags = 0,
.imageType = VK_IMAGE_TYPE_2D,
.format = vk_format,
.extent = { desc.Width, desc.Height, 1 },
.mipLevels = desc.MipLevels,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = self->vk_tiling,
.usage = VK_IMAGE_USAGE_SAMPLED_BIT |
(flags & GSK_GPU_IMAGE_NO_BLIT ? 0 : VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.initialLayout = self->vk_image_layout,
.pNext = &(VkExternalMemoryImageCreateInfo) {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT,
},
},
NULL,
&self->vk_image);
if (res != VK_SUCCESS)
{
GDK_DEBUG (D3D12, "vkCreateImage() failed: %s", gdk_vulkan_strerror (res));
return NULL;
}
gsk_gpu_image_setup (GSK_GPU_IMAGE (self),
flags |
(!premultiplied ? GSK_GPU_IMAGE_STRAIGHT_ALPHA : 0) |
(is_yuv ? (GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT) : 0) |
(desc.MipLevels > 1 ? GSK_GPU_IMAGE_CAN_MIPMAP | GSK_GPU_IMAGE_MIPMAP : 0),
gdk_dxgi_format_get_memory_format (desc.Format, premultiplied),
desc.Width, desc.Height);
vkGetImageMemoryRequirements2 (vk_device,
&(VkImageMemoryRequirementsInfo2) {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
.image = self->vk_image,
},
&requirements);
// Vulkan memory import
GSK_VK_CHECK (func_vkGetMemoryWin32HandlePropertiesKHR, vk_device,
VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT,
resource_handle,
&handle_properties);
memory_index = gsk_vulkan_device_find_allocator (device,
handle_properties.memoryTypeBits,
0,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
self->allocator = gsk_vulkan_device_get_external_allocator (device);
gsk_vulkan_allocator_ref (self->allocator);
gsk_vulkan_alloc (self->allocator,
requirements.memoryRequirements.size,
requirements.memoryRequirements.alignment,
&self->allocation);
GSK_VK_CHECK (vkAllocateMemory, vk_device,
&(VkMemoryAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = requirements.memoryRequirements.size,
.memoryTypeIndex = memory_index,
.pNext = &(VkImportMemoryWin32HandleInfoKHR) {
.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT,
.handle = resource_handle,
.pNext = &(VkMemoryDedicatedAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
.image = self->vk_image,
}
}
},
NULL,
&self->allocation.vk_memory);
GSK_VK_CHECK (vkBindImageMemory2, gsk_vulkan_device_get_vk_device (self->device),
1,
&(VkBindImageMemoryInfo) {
.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
.image = self->vk_image,
.memory = self->allocation.vk_memory,
.memoryOffset = self->allocation.offset,
});
if (is_yuv)
{
self->ycbcr = gsk_vulkan_device_get_ycbcr (device, vk_format);
gsk_vulkan_ycbcr_ref (self->ycbcr);
vk_conversion = gsk_vulkan_ycbcr_get_vk_conversion (self->ycbcr);
}
else
vk_conversion = VK_NULL_HANDLE;
gsk_vulkan_image_create_view (self,
vk_format,
&vk_components,
vk_conversion);
GDK_DEBUG (D3D12, "Vulkan uploaded %ux%u resource of %sformat %u",
(guint) desc.Width, (guint) desc.Height,
is_yuv ? "YUV " : "",
desc.Format);
return GSK_GPU_IMAGE (self);
}
#endif
static void
gsk_vulkan_image_get_projection_matrix (GskGpuImage *image,
graphene_matrix_t *out_projection)

View File

@@ -5,6 +5,10 @@
#include "gdk/gdkdmabufprivate.h"
#ifdef GDK_WINDOWING_WIN32
#include <gdk/win32/gdkwin32.h>
#endif
G_BEGIN_DECLS
#define GSK_TYPE_VULKAN_IMAGE (gsk_vulkan_image_get_type ())
@@ -47,6 +51,12 @@ GskGpuImage * gsk_vulkan_image_new_for_dmabuf (GskVulk
GdkTexture * gsk_vulkan_image_to_dmabuf_texture (GskVulkanImage *self,
GdkColorState *color_state);
#endif
#ifdef GDK_WINDOWING_WIN32
GskGpuImage * gsk_vulkan_image_new_for_d3d12resource (GskVulkanDevice *device,
ID3D12Resource *resource,
HANDLE resource_handle,
gboolean premultiplied);
#endif
guchar * gsk_vulkan_image_get_data (GskVulkanImage *self,
gsize *out_stride);