From 595294b8f407ad5171a3856e8a0bc967a11b5c67 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 31 Oct 2024 14:51:13 +0100 Subject: [PATCH] gpu: Add D3D12 texture support to GL renderer Add a gdk_d3d12_texture_import_gl() function to match the EGL import behavior. And then use it in the import code. What makes this a bit awkward is that we need to not just shuffle a tex_id but also a mem_id around, but oh well... --- gdk/win32/gdkd3d12texture.c | 90 ++++++++++++++++++++++++++++++ gdk/win32/gdkd3d12textureprivate.h | 4 ++ gsk/gpu/gskglframe.c | 22 ++++++++ 3 files changed, 116 insertions(+) diff --git a/gdk/win32/gdkd3d12texture.c b/gdk/win32/gdkd3d12texture.c index d505790541..77aa14a1ad 100644 --- a/gdk/win32/gdkd3d12texture.c +++ b/gdk/win32/gdkd3d12texture.c @@ -23,10 +23,13 @@ #include "gdkcolorstateprivate.h" #include "gdkd3d12texturebuilder.h" #include "gdkdxgiformatprivate.h" +#include "gdkglcontextprivate.h" #include "gdkmemoryformatprivate.h" #include "gdkprivate-win32.h" #include "gdktextureprivate.h" +#include + /** * GdkD3D12Texture: * @@ -409,3 +412,90 @@ out: G_UNLOCK (handle_creation); return result; } + +/* + * gdk_d3d12_texture_import_gl: + * @self: texture to import into GL + * @context: GL context to use for the import. The context + * must be the current context. + * @out_mem_id: (out): out result for the memory object + * created during the import. See GL_EXT_memory_object_win32 + * for details. + * + * Imports the given D3D12 texture into the given OpenGL + * context. + * + * This function binds `GL_TEXTURE_2D` during the import. + * + * Returns: The newly created texture or 0 on failure. + */ +guint +gdk_d3d12_texture_import_gl (GdkD3D12Texture *self, + GdkGLContext *context, + guint *out_mem_id) +{ + GdkTexture *texture = GDK_TEXTURE (self); + GLuint tex_id, mem_id; + D3D12_RESOURCE_DESC desc; + HANDLE handle; + GLenum gl_internal_format; + GLenum gl_error; + + /* We assume that the context is current, the caller needs to juggle that */ + g_assert (gdk_gl_context_get_current () == context); + + if (!gdk_gl_context_has_feature (context, GDK_GL_FEATURE_EXTERNAL_OBJECTS_WIN32)) + { + GDK_DEBUG (D3D12, "Not importing %ux%u texture, EXT_external_objects_win32 is not supported", + texture->width, texture->height); + return 0; + } + + ID3D12Resource_GetDesc (self->resource, &desc); + + gl_internal_format = gdk_dxgi_format_get_gl_format (desc.Format); + if (gl_internal_format == 0) + { + GDK_DEBUG (D3D12, "Not importing %ux%u texture, no matching GL format for DGI format %u", + texture->width, texture->height, + desc.Format); + return 0; + } + + handle = gdk_d3d12_texture_get_resource_handle (self); + if (!handle) + return 0; + + GDK_DEBUG (D3D12, "Attempting to import %ux%u texture", + texture->width, texture->height); + + glCreateMemoryObjectsEXT (1, &mem_id); + glImportMemoryWin32HandleEXT (mem_id, + 0, + GL_HANDLE_TYPE_D3D12_RESOURCE_EXT, + handle); + + glGenTextures (1, &tex_id); + glBindTexture (GL_TEXTURE_2D, tex_id); + glTexStorageMem2DEXT (GL_TEXTURE_2D, + desc.MipLevels, + gl_internal_format, + desc.Width, + desc.Height, + mem_id, + 0); + + gl_error = glGetError (); + if (gl_error != GL_NO_ERROR) + { + GDK_DEBUG (D3D12, "Failed to import %ux%u texture, got GL error %u", + texture->width, texture->height, + gl_error); + glDeleteTextures (1, &tex_id); + return 0; + } + + *out_mem_id = mem_id; + + return tex_id; +} diff --git a/gdk/win32/gdkd3d12textureprivate.h b/gdk/win32/gdkd3d12textureprivate.h index 544873e8b0..0e38e30f4b 100644 --- a/gdk/win32/gdkd3d12textureprivate.h +++ b/gdk/win32/gdkd3d12textureprivate.h @@ -13,5 +13,9 @@ GdkTexture * gdk_d3d12_texture_new_from_builder (GdkD3D1 HANDLE gdk_d3d12_texture_get_resource_handle (GdkD3D12Texture *self); +guint gdk_d3d12_texture_import_gl (GdkD3D12Texture *self, + GdkGLContext *context, + guint *out_mem_id); + G_END_DECLS diff --git a/gsk/gpu/gskglframe.c b/gsk/gpu/gskglframe.c index 75a65f201d..37b897e38c 100644 --- a/gsk/gpu/gskglframe.c +++ b/gsk/gpu/gskglframe.c @@ -13,6 +13,9 @@ #include "gdkglcontextprivate.h" #include "gdkgltextureprivate.h" +#ifdef GDK_WINDOWING_WIN32 +#include "win32/gdkd3d12textureprivate.h" +#endif struct _GskGLFrame { GskGpuFrame parent_instance; @@ -121,6 +124,25 @@ gsk_gl_frame_upload_texture (GskGpuFrame *frame, (external ? GSK_GPU_IMAGE_EXTERNAL | GSK_GPU_IMAGE_NO_BLIT : 0)); } } +#ifdef GDK_WINDOWING_WIN32 + else if (GDK_IS_D3D12_TEXTURE (texture)) + { + guint tex_id, mem_id; + + tex_id = gdk_d3d12_texture_import_gl (GDK_D3D12_TEXTURE (texture), + GDK_GL_CONTEXT (gsk_gpu_frame_get_context (frame)), + &mem_id); + if (tex_id) + { + return gsk_gl_image_new_for_texture (GSK_GL_DEVICE (gsk_gpu_frame_get_device (frame)), + texture, + tex_id, + mem_id, + TRUE, + 0); + } + } +#endif return GSK_GPU_FRAME_CLASS (gsk_gl_frame_parent_class)->upload_texture (frame, with_mipmap, texture); }