Mesa (master): d3d12: Implement winsys framebuffer

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Nov 18 10:43:33 UTC 2020


Module: Mesa
Branch: master
Commit: be4475c4a73dc71c8868f5508064feb6bdec0a22
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=be4475c4a73dc71c8868f5508064feb6bdec0a22

Author: Jesse Natalie <jenatali at ntdev.microsoft.com>
Date:   Sat Apr 25 16:26:56 2020 -0400

d3d12: Implement winsys framebuffer

Reviewed-by: Charmaine Lee <charmainel at vmware.com>
Reviewed-by: Erik Faye-Lund <erik.faye-lund at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7535>

---

 src/gallium/frontends/wgl/stw_device.h             |   6 +
 src/gallium/targets/libgl-d3d12/libgl_d3d12.c      |  12 +-
 src/gallium/targets/libgl-gdi/libgl_gdi.c          |  14 ++
 .../winsys/d3d12/wgl/d3d12_wgl_framebuffer.cpp     | 198 +++++++++++++++++++++
 src/gallium/winsys/d3d12/wgl/d3d12_wgl_public.h    |   5 +
 src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c    |   2 +-
 src/gallium/winsys/d3d12/wgl/meson.build           |   2 +-
 7 files changed, 236 insertions(+), 3 deletions(-)

diff --git a/src/gallium/frontends/wgl/stw_device.h b/src/gallium/frontends/wgl/stw_device.h
index 6c57e874a57..b3620f1db58 100644
--- a/src/gallium/frontends/wgl/stw_device.h
+++ b/src/gallium/frontends/wgl/stw_device.h
@@ -38,6 +38,9 @@
 
 #define STW_MAX_PIXELFORMATS   256
 
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 struct pipe_screen;
 struct st_api;
@@ -129,5 +132,8 @@ stw_unlock_framebuffers(struct stw_device *stw_dev)
    LeaveCriticalSection(&stw_dev->fb_mutex);
 }
 
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* STW_DEVICE_H_ */
diff --git a/src/gallium/targets/libgl-d3d12/libgl_d3d12.c b/src/gallium/targets/libgl-d3d12/libgl_d3d12.c
index f34bc4a6015..fa31e5c0e7d 100644
--- a/src/gallium/targets/libgl-d3d12/libgl_d3d12.c
+++ b/src/gallium/targets/libgl-d3d12/libgl_d3d12.c
@@ -91,6 +91,15 @@ gdi_get_pfd_flags(struct pipe_screen *screen)
 }
 
 
+static struct stw_winsys_framebuffer *
+gdi_create_framebuffer(struct pipe_screen *screen,
+                       HDC hDC,
+                       int iPixelFormat)
+{
+   return d3d12_wgl_create_framebuffer(screen, hDC, iPixelFormat);
+}
+
+
 static const struct stw_winsys stw_winsys = {
    &gdi_screen_create,
    &gdi_present,
@@ -98,7 +107,8 @@ static const struct stw_winsys stw_winsys = {
    NULL, /* shared_surface_open */
    NULL, /* shared_surface_close */
    NULL, /* compose */
-   &gdi_get_pfd_flags
+   &gdi_get_pfd_flags,
+   &gdi_create_framebuffer
 };
 
 
diff --git a/src/gallium/targets/libgl-gdi/libgl_gdi.c b/src/gallium/targets/libgl-gdi/libgl_gdi.c
index 283e147f28f..b9436a43bc9 100644
--- a/src/gallium/targets/libgl-gdi/libgl_gdi.c
+++ b/src/gallium/targets/libgl-gdi/libgl_gdi.c
@@ -229,6 +229,19 @@ gdi_get_pfd_flags(struct pipe_screen *screen)
 }
 
 
+static struct stw_winsys_framebuffer *
+gdi_create_framebuffer(struct pipe_screen *screen,
+                       HDC hDC,
+                       int iPixelFormat)
+{
+#ifdef GALLIUM_D3D12
+   if (use_d3d12)
+      return d3d12_wgl_create_framebuffer(screen, hDC, iPixelFormat);
+#endif
+   return NULL;
+}
+
+
 static const struct stw_winsys stw_winsys = {
    &gdi_screen_create,
    &gdi_present,
@@ -241,6 +254,7 @@ static const struct stw_winsys stw_winsys = {
    NULL, /* shared_surface_close */
    NULL, /* compose */
    &gdi_get_pfd_flags,
+   &gdi_create_framebuffer,
 };
 
 
diff --git a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer.cpp b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer.cpp
new file mode 100644
index 00000000000..b625e6dd7e4
--- /dev/null
+++ b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright © Microsoft Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "d3d12_wgl_public.h"
+
+#include <Windows.h>
+#include <dxgi1_4.h>
+#include <d3d12.h>
+#include <wrl.h>
+
+#include "util/u_memory.h"
+#include "util/u_inlines.h"
+#include "frontend/api.h"
+#include "frontend/winsys_handle.h"
+
+#include "stw_device.h"
+#include "stw_pixelformat.h"
+#include "stw_winsys.h"
+
+#include "d3d12/d3d12_format.h"
+#include "d3d12/d3d12_screen.h"
+
+using Microsoft::WRL::ComPtr;
+
+struct d3d12_wgl_framebuffer {
+   struct stw_winsys_framebuffer base;
+
+   struct d3d12_screen *screen;
+   enum pipe_format pformat;
+   HWND window;
+   ComPtr<IDXGISwapChain3> swapchain;
+};
+
+static struct d3d12_wgl_framebuffer *
+d3d12_wgl_framebuffer(struct stw_winsys_framebuffer *fb)
+{
+   return (struct d3d12_wgl_framebuffer *)fb;
+}
+
+static void
+d3d12_wgl_framebuffer_destroy(struct stw_winsys_framebuffer *fb)
+{
+   FREE(fb);
+}
+
+static void
+d3d12_wgl_framebuffer_resize(stw_winsys_framebuffer *fb,
+                             pipe_context *ctx,
+                             pipe_resource *templ)
+{
+   struct d3d12_wgl_framebuffer *framebuffer = d3d12_wgl_framebuffer(fb);
+   struct d3d12_screen *screen = framebuffer->screen;
+
+   DXGI_SWAP_CHAIN_DESC1 desc = {};
+   desc.BufferCount = 2;
+   desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
+   desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
+   desc.Format = d3d12_get_format(templ->format);
+   desc.Width = templ->width0;
+   desc.Height = templ->height0;
+   desc.SampleDesc.Count = 1;
+   desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+
+   framebuffer->pformat = templ->format;
+
+   if (!framebuffer->swapchain) {
+      ComPtr<IDXGISwapChain1> swapchain1;
+      if (FAILED(screen->factory->CreateSwapChainForHwnd(
+         screen->cmdqueue,
+         framebuffer->window,
+         &desc,
+         nullptr,
+         nullptr,
+         &swapchain1))) {
+         debug_printf("D3D12: failed to create swapchain");
+         return;
+      }
+
+      swapchain1.As(&framebuffer->swapchain);
+   }
+   else {
+      struct pipe_fence_handle *fence = NULL;
+
+      /* Ensure all resources are flushed */
+      ctx->flush(ctx, &fence, PIPE_FLUSH_HINT_FINISH);
+      if (fence) {
+         ctx->screen->fence_finish(ctx->screen, ctx, fence, PIPE_TIMEOUT_INFINITE);
+         ctx->screen->fence_reference(ctx->screen, &fence, NULL);
+      }
+
+      if (FAILED(framebuffer->swapchain->ResizeBuffers(2, desc.Width, desc.Height, desc.Format, desc.Flags))) {
+         debug_printf("D3D12: failed to resize swapchain");
+      }
+   }
+}
+
+static boolean
+d3d12_wgl_framebuffer_present(stw_winsys_framebuffer *fb)
+{
+   auto framebuffer = d3d12_wgl_framebuffer(fb);
+   if (!framebuffer->swapchain) {
+      debug_printf("D3D12: Cannot present; no swapchain");
+      return false;
+   }
+
+   if (stw_dev->swap_interval < 1)
+      return S_OK == framebuffer->swapchain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
+   else
+       return S_OK == framebuffer->swapchain->Present(stw_dev->swap_interval, 0);
+}
+
+static struct pipe_resource *
+d3d12_wgl_framebuffer_get_resource(struct stw_winsys_framebuffer *pframebuffer,
+                                   st_attachment_type statt)
+{
+   auto framebuffer = d3d12_wgl_framebuffer(pframebuffer);
+   auto pscreen = &framebuffer->screen->base;
+
+   if (!framebuffer->swapchain)
+      return nullptr;
+
+   UINT index = framebuffer->swapchain->GetCurrentBackBufferIndex();
+   if (statt == ST_ATTACHMENT_FRONT_LEFT)
+      index = !index;
+
+   ID3D12Resource *res;
+   framebuffer->swapchain->GetBuffer(index, IID_PPV_ARGS(&res));
+   if (!res)
+      return nullptr;
+
+   struct winsys_handle handle;
+   memset(&handle, 0, sizeof(handle));
+   handle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
+   handle.com_obj = res;
+
+   D3D12_RESOURCE_DESC res_desc = res->GetDesc();
+
+   struct pipe_resource templ;
+   memset(&templ, 0, sizeof(templ));
+   templ.target = PIPE_TEXTURE_2D;
+   templ.format = framebuffer->pformat;
+   templ.width0 = res_desc.Width;
+   templ.height0 = res_desc.Height;
+   templ.depth0 = 1;
+   templ.array_size = res_desc.DepthOrArraySize;
+   templ.nr_samples = res_desc.SampleDesc.Count;
+   templ.last_level = res_desc.MipLevels - 1;
+   templ.bind = PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_RENDER_TARGET;
+   templ.usage = PIPE_USAGE_DEFAULT;
+   templ.flags = 0;
+
+   return pscreen->resource_from_handle(pscreen, &templ, &handle,
+                                        PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
+}
+
+struct stw_winsys_framebuffer *
+d3d12_wgl_create_framebuffer(struct pipe_screen *screen,
+                             HDC hDC,
+                             int iPixelFormat)
+{
+   const struct stw_pixelformat_info *pfi =
+      stw_pixelformat_get_info(iPixelFormat);
+   if (!(pfi->pfd.dwFlags & PFD_DOUBLEBUFFER))
+      return NULL;
+
+   struct d3d12_wgl_framebuffer *fb = CALLOC_STRUCT(d3d12_wgl_framebuffer);
+   if (!fb)
+      return NULL;
+
+   fb->window = WindowFromDC(hDC);
+   fb->screen = d3d12_screen(screen);
+   fb->base.destroy = d3d12_wgl_framebuffer_destroy;
+   fb->base.resize = d3d12_wgl_framebuffer_resize;
+   fb->base.present = d3d12_wgl_framebuffer_present;
+   fb->base.get_resource = d3d12_wgl_framebuffer_get_resource;
+
+   return &fb->base;
+}
diff --git a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_public.h b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_public.h
index c24e111e1b0..aa0191274ea 100644
--- a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_public.h
+++ b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_public.h
@@ -46,6 +46,11 @@ d3d12_wgl_present(struct pipe_screen *screen,
 unsigned
 d3d12_wgl_get_pfd_flags(struct pipe_screen *screen);
 
+struct stw_winsys_framebuffer *
+d3d12_wgl_create_framebuffer(struct pipe_screen *screen,
+                             HDC hDC,
+                             int iPixelFormat);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c
index 7e84501f780..cf098daa738 100644
--- a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c
+++ b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_winsys.c
@@ -53,5 +53,5 @@ unsigned
 d3d12_wgl_get_pfd_flags(struct pipe_screen *screen)
 {
    (void)screen;
-   return stw_pfd_gdi_support;
+   return stw_pfd_gdi_support | stw_pfd_double_buffer;
 }
diff --git a/src/gallium/winsys/d3d12/wgl/meson.build b/src/gallium/winsys/d3d12/wgl/meson.build
index 9f41560b811..8f05beeb885 100644
--- a/src/gallium/winsys/d3d12/wgl/meson.build
+++ b/src/gallium/winsys/d3d12/wgl/meson.build
@@ -22,7 +22,7 @@
 
 libd3d12winsys = static_library(
   'd3d12winsys',
-  files('d3d12_wgl_winsys.c'),
+  files('d3d12_wgl_framebuffer.cpp', 'd3d12_wgl_winsys.c'),
   include_directories : [inc_src, inc_wgl, inc_include, inc_gallium, inc_gallium_aux, inc_gallium_drivers],
   gnu_symbol_visibility : 'hidden',
 )



More information about the mesa-commit mailing list