Module: Mesa
Branch: main
Commit: 882a78b8adf782b3a3d58274ece14e1fa9330f46
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=882a78b8adf782b3a3d58274ece14e1fa9330f46

Author: Caleb Cornett <[email protected]>
Date:   Wed Jan 11 10:48:49 2023 -0500

wgl: Add support for Xbox GDK.

This patch is comprised of three main changes:
- Add a "shim" for GDI, since Xbox doesn't expose this library
- New framebuffer file, to support the Xbox "windowing" system
- Implement a custom WndProc hook for Xbox, since SetWindowsHookEx isn't 
supported either

Other than that, it's similar to the previous Xbox commits which mostly disable 
Win32-specific logic.

Co-authored-by: Ethan Lee <[email protected]>
Co-authored-by: David Jacewicz <[email protected]>
Co-authored-by: tieuchanlong <[email protected]>
Reviewed-by: Jesse Natalie <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19022>

---

 src/gallium/frontends/wgl/meson.build              |  44 +--
 src/gallium/frontends/wgl/stw_context.c            |   1 +
 src/gallium/frontends/wgl/stw_context.h            |   1 +
 src/gallium/frontends/wgl/stw_device.c             |   5 +
 src/gallium/frontends/wgl/stw_device.h             |   1 +
 src/gallium/frontends/wgl/stw_ext_context.c        |   1 +
 src/gallium/frontends/wgl/stw_ext_pbuffer.c        |   4 +
 src/gallium/frontends/wgl/stw_ext_rendertexture.c  |   1 +
 src/gallium/frontends/wgl/stw_framebuffer.c        |  42 +++
 src/gallium/frontends/wgl/stw_framebuffer.h        |   5 +
 src/gallium/frontends/wgl/stw_gdishim.c            |  75 ++++++
 src/gallium/frontends/wgl/stw_gdishim.h            | 152 +++++++++++
 src/gallium/frontends/wgl/stw_getprocaddress.c     |   1 +
 src/gallium/frontends/wgl/stw_pixelformat.c        |   1 +
 src/gallium/frontends/wgl/stw_tls.c                |   8 +
 src/gallium/targets/libgl-gdi/stw_wgl.c            |   5 +
 .../d3d12/wgl/d3d12_wgl_framebuffer_xbox.cpp       | 294 +++++++++++++++++++++
 src/gallium/winsys/d3d12/wgl/meson.build           |   8 +-
 src/gallium/winsys/sw/gdi/gdi_sw_winsys.c          |   1 +
 src/gallium/winsys/sw/gdi/meson.build              |   2 +-
 src/meson.build                                    |   1 +
 21 files changed, 632 insertions(+), 21 deletions(-)

diff --git a/src/gallium/frontends/wgl/meson.build 
b/src/gallium/frontends/wgl/meson.build
index c41e97f0db5..5c39bf32a8d 100644
--- a/src/gallium/frontends/wgl/meson.build
+++ b/src/gallium/frontends/wgl/meson.build
@@ -25,27 +25,33 @@ if not with_shared_glapi
   _c_args_wgl += '-D_GLAPI_NO_EXPORTS'
 endif
 
+files_libwgl = files(
+  'stw_context.c',
+  'stw_device.c',
+  'stw_ext_context.c',
+  'stw_ext_extensionsstring.c',
+  'stw_ext_interop.c',
+  'stw_ext_pbuffer.c',
+  'stw_ext_pixelformat.c',
+  'stw_ext_rendertexture.c',
+  'stw_ext_swapinterval.c',
+  'stw_framebuffer.c',
+  'stw_getprocaddress.c',
+  'stw_image.c',
+  'stw_nopfuncs.c',
+  'stw_nopfuncs.h',
+  'stw_pixelformat.c',
+  'stw_st.c',
+  'stw_tls.c',
+)
+
+if target_machine.system().startswith('Gaming.Xbox')
+  files_libwgl += files('stw_gdishim.c')
+endif
+
 libwgl = static_library(
   'wgl',
-  files(
-    'stw_context.c',
-    'stw_device.c',
-    'stw_ext_context.c',
-    'stw_ext_extensionsstring.c',
-    'stw_ext_interop.c',
-    'stw_ext_pbuffer.c',
-    'stw_ext_pixelformat.c',
-    'stw_ext_rendertexture.c',
-    'stw_ext_swapinterval.c',
-    'stw_framebuffer.c',
-    'stw_getprocaddress.c',
-    'stw_image.c',
-    'stw_nopfuncs.c',
-    'stw_nopfuncs.h',
-    'stw_pixelformat.c',
-    'stw_st.c',
-    'stw_tls.c',
-  ),
+  files_libwgl,
   c_args : [
     '-D_GDI32_',             # prevent wgl* being declared 
__declspec(dllimport)
     _c_args_wgl
diff --git a/src/gallium/frontends/wgl/stw_context.c 
b/src/gallium/frontends/wgl/stw_context.c
index 6005eac8da7..1be1ee740ca 100644
--- a/src/gallium/frontends/wgl/stw_context.c
+++ b/src/gallium/frontends/wgl/stw_context.c
@@ -42,6 +42,7 @@
 #include "util/u_atomic.h"
 #include "hud/hud_context.h"
 
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_device.h"
 #include "stw_winsys.h"
diff --git a/src/gallium/frontends/wgl/stw_context.h 
b/src/gallium/frontends/wgl/stw_context.h
index f3203b37b07..ab4bbd09949 100644
--- a/src/gallium/frontends/wgl/stw_context.h
+++ b/src/gallium/frontends/wgl/stw_context.h
@@ -30,6 +30,7 @@
 
 #include <windows.h>
 #include <GL/gl.h>
+#include <stw_gdishim.h>
 #include <gldrv.h>
 
 struct hud_context;
diff --git a/src/gallium/frontends/wgl/stw_device.c 
b/src/gallium/frontends/wgl/stw_device.c
index 2db745f3ce6..ecbf08f8fef 100644
--- a/src/gallium/frontends/wgl/stw_device.c
+++ b/src/gallium/frontends/wgl/stw_device.c
@@ -40,6 +40,7 @@
 #include "stw_device.h"
 #include "stw_winsys.h"
 #include "stw_pixelformat.h"
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_tls.h"
 #include "stw_framebuffer.h"
@@ -72,6 +73,7 @@ stw_get_param(struct pipe_frontend_screen *fscreen,
 static int
 get_refresh_rate(void)
 {
+#ifndef _GAMING_XBOX
    DEVMODE devModes;
 
    if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devModes)) {
@@ -82,6 +84,9 @@ get_refresh_rate(void)
       /* reasonable default */
       return 60;
    }
+#else
+   return 60;
+#endif /* _GAMING_XBOX */
 }
 
 static bool
diff --git a/src/gallium/frontends/wgl/stw_device.h 
b/src/gallium/frontends/wgl/stw_device.h
index ee28cd50951..49d5a80dc2c 100644
--- a/src/gallium/frontends/wgl/stw_device.h
+++ b/src/gallium/frontends/wgl/stw_device.h
@@ -35,6 +35,7 @@
 #include "util/u_dynarray.h"
 #include "util/xmlconfig.h"
 #include <GL/gl.h>
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_pixelformat.h"
 
diff --git a/src/gallium/frontends/wgl/stw_ext_context.c 
b/src/gallium/frontends/wgl/stw_ext_context.c
index 3394a2b3f46..c81725e0e39 100644
--- a/src/gallium/frontends/wgl/stw_ext_context.c
+++ b/src/gallium/frontends/wgl/stw_ext_context.c
@@ -30,6 +30,7 @@
 #include <GL/gl.h>
 #include <GL/wglext.h>
 
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_context.h"
 #include "stw_device.h"
diff --git a/src/gallium/frontends/wgl/stw_ext_pbuffer.c 
b/src/gallium/frontends/wgl/stw_ext_pbuffer.c
index 65a14383984..e1db194452f 100644
--- a/src/gallium/frontends/wgl/stw_ext_pbuffer.c
+++ b/src/gallium/frontends/wgl/stw_ext_pbuffer.c
@@ -48,6 +48,7 @@
 static LRESULT CALLBACK
 WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
+#ifndef _GAMING_XBOX
     MINMAXINFO *pMMI;
     switch (uMsg) {
     case WM_GETMINMAXINFO:
@@ -61,6 +62,7 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
     default:
         break;
     }
+#endif /* _GAMING_XBOX */
 
     return DefWindowProc(hWnd, uMsg, wParam, lParam);
 }
@@ -78,8 +80,10 @@ stw_pbuffer_create(const struct stw_pixelformat_info *pfi, 
int iWidth, int iHeig
       WNDCLASS wc;
       memset(&wc, 0, sizeof wc);
       wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
+#ifndef _GAMING_XBOX
       wc.hCursor = LoadCursor(NULL, IDC_ARROW);
       wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+#endif
       wc.lpfnWndProc = WndProc;
       wc.lpszClassName = "wglpbuffer";
       wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
diff --git a/src/gallium/frontends/wgl/stw_ext_rendertexture.c 
b/src/gallium/frontends/wgl/stw_ext_rendertexture.c
index b19c8f15e3f..10d0b285f02 100644
--- a/src/gallium/frontends/wgl/stw_ext_rendertexture.c
+++ b/src/gallium/frontends/wgl/stw_ext_rendertexture.c
@@ -37,6 +37,7 @@
 #include "pipe/p_screen.h"
 #include "pipe/p_state.h"
 
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_context.h"
 #include "stw_device.h"
diff --git a/src/gallium/frontends/wgl/stw_framebuffer.c 
b/src/gallium/frontends/wgl/stw_framebuffer.c
index a2d46eaaf09..474fc55bd29 100644
--- a/src/gallium/frontends/wgl/stw_framebuffer.c
+++ b/src/gallium/frontends/wgl/stw_framebuffer.c
@@ -37,6 +37,7 @@
 #include "frontend/api.h"
 
 #include <GL/gl.h>
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_framebuffer.h"
 #include "stw_device.h"
@@ -178,11 +179,13 @@ stw_framebuffer_get_size(struct stw_framebuffer *fb)
 
    client_pos.x = 0;
    client_pos.y = 0;
+#ifndef _GAMING_XBOX
    if (ClientToScreen(fb->hWnd, &client_pos) &&
        GetWindowRect(fb->hWnd, &window_rect)) {
       fb->client_rect.left = client_pos.x - window_rect.left;
       fb->client_rect.top  = client_pos.y - window_rect.top;
    }
+#endif
 
    fb->client_rect.right  = fb->client_rect.left + fb->width;
    fb->client_rect.bottom = fb->client_rect.top  + fb->height;
@@ -204,6 +207,7 @@ stw_framebuffer_get_size(struct stw_framebuffer *fb)
 }
 
 
+#ifndef _GAMING_XBOX
 /**
  * @sa http://msdn.microsoft.com/en-us/library/ms644975(VS.85).aspx
  * @sa http://msdn.microsoft.com/en-us/library/ms644960(VS.85).aspx
@@ -263,6 +267,40 @@ stw_call_window_proc(int nCode, WPARAM wParam, LPARAM 
lParam)
 
    return CallNextHookEx(tls_data->hCallWndProcHook, nCode, wParam, lParam);
 }
+#else
+LRESULT CALLBACK
+stw_call_window_proc_xbox(HWND hWnd, UINT message,
+                          WPARAM wParam, LPARAM lParam)
+{
+   WNDPROC prev_wndproc = NULL;
+
+   /* We check that the stw_dev object is initialized before we try to do
+    * anything with it.  Otherwise, in multi-threaded programs there's a
+    * chance of executing this code before the stw_dev object is fully
+    * initialized.
+    */
+   if (stw_dev && stw_dev->initialized) {
+      if (message == WM_DESTROY) {
+         stw_lock_framebuffers(stw_dev);
+         struct stw_framebuffer *fb = stw_framebuffer_from_hwnd_locked(hWnd);
+         if (fb) {
+            struct stw_context *current_context = stw_current_context();
+            struct st_context *st = current_context &&
+               current_context->current_framebuffer == fb ? 
current_context->st : NULL;
+            prev_wndproc = fb->prev_wndproc;
+            stw_framebuffer_release_locked(fb, st);
+         }
+         stw_unlock_framebuffers(stw_dev);
+      }
+   }
+
+   /* Pass the parameters up the chain, if applicable */
+   if (prev_wndproc)
+      return prev_wndproc(hWnd, message, wParam, lParam);
+
+   return 0;
+}
+#endif /* _GAMING_XBOX */
 
 
 /**
@@ -286,6 +324,10 @@ stw_framebuffer_create(HWND hWnd, const struct 
stw_pixelformat_info *pfi, enum s
       fb->winsys_framebuffer =
          stw_dev->stw_winsys->create_framebuffer(stw_dev->screen, hWnd, 
pfi->iPixelFormat);
 
+#ifdef _GAMING_XBOX
+   fb->prev_wndproc = (WNDPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, 
(LONG_PTR)&stw_call_window_proc_xbox);
+#endif
+
    /*
     * We often need a displayable pixel format to make GDI happy. Set it
     * here (always 1, i.e., out first pixel format) where appropriate.
diff --git a/src/gallium/frontends/wgl/stw_framebuffer.h 
b/src/gallium/frontends/wgl/stw_framebuffer.h
index 140e5bdc523..0a5e7b0f009 100644
--- a/src/gallium/frontends/wgl/stw_framebuffer.h
+++ b/src/gallium/frontends/wgl/stw_framebuffer.h
@@ -132,6 +132,11 @@ struct stw_framebuffer
    int swap_interval;
    int64_t prev_swap_time;
 
+#ifdef _GAMING_XBOX
+   /* For the WndProc hook chain */
+   WNDPROC prev_wndproc;
+#endif
+
    /** 
     * This is protected by stw_device::fb_mutex, not the mutex above.
     * 
diff --git a/src/gallium/frontends/wgl/stw_gdishim.c 
b/src/gallium/frontends/wgl/stw_gdishim.c
new file mode 100644
index 00000000000..9c7906e9c9b
--- /dev/null
+++ b/src/gallium/frontends/wgl/stw_gdishim.c
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+/* Certain Win32-like platforms (i.e. Xbox GDK) do not support the GDI library.
+ * stw_gdishim acts as a shim layer to provide the APIs required for gallium.
+ */
+
+#include "stw_gdishim.h"
+#include "stw_pixelformat.h"
+#include "stw_framebuffer.h"
+
+int GetPixelFormat(HDC hdc)
+{
+   return stw_pixelformat_get(hdc);
+}
+
+int DescribePixelFormat(
+   HDC                     hdc,
+   int                     iPixelFormat,
+   UINT                    nBytes,
+   LPPIXELFORMATDESCRIPTOR ppfd
+)
+{
+   if (iPixelFormat >= stw_pixelformat_get_count(hdc))
+      return 0;
+
+   const struct stw_pixelformat_info* info = 
stw_pixelformat_get_info(iPixelFormat);
+   memcpy(ppfd, &info->pfd, nBytes);
+   return 1;
+}
+
+BOOL SetPixelFormat(
+   HDC                         hdc,
+   int                         format,
+   const PIXELFORMATDESCRIPTOR* ppfd
+)
+{
+// TODO: can we support this?
+#if 0
+   struct stw_framebuffer* fb;
+
+   fb = stw_framebuffer_from_hdc(hdc);
+   if (fb && fb->pfi) {
+      fb->pfi->iPixelFormat = format;
+      stw_framebuffer_unlock(fb);
+      return TRUE;
+   }
+#endif
+   return FALSE;
+}
+
+void StretchDIBits(HDC hdc, unsigned int xDest, unsigned int yDest, unsigned 
int DestWidth, unsigned int DestHeight, unsigned int xSrc, unsigned int ySrc, 
unsigned int SrcWidth, unsigned int SrcHeight, void* lpBits, void* lpbmi, 
unsigned int iUsage, DWORD rop)
+{
+
+}
diff --git a/src/gallium/frontends/wgl/stw_gdishim.h 
b/src/gallium/frontends/wgl/stw_gdishim.h
new file mode 100644
index 00000000000..06ea429a48b
--- /dev/null
+++ b/src/gallium/frontends/wgl/stw_gdishim.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+/* Certain Win32-like platforms (i.e. Xbox GDK) do not support the GDI library.
+ * stw_gdishim acts as a shim layer to provide the APIs required for gallium.
+ */
+
+#ifndef STW_GDISHIM_H
+#define STW_GDISHIM_H
+
+#ifdef _GAMING_XBOX
+
+#include <windows.h>
+
+/* Handles */
+typedef void* HMONITOR;
+
+/* Stubs */
+#define WindowFromDC(hdc) (HWND)hdc
+#define GetDC(hwnd) (HDC)hwnd
+#define ReleaseDC(hwnd, hdc) 1
+
+void StretchDIBits(HDC hdc, unsigned int xDest, unsigned int yDest, unsigned 
int DestWidth, unsigned int DestHeight, unsigned int xSrc, unsigned int ySrc, 
unsigned int SrcWidth, unsigned int SrcHeight, void* lpBits, void* lpbmi, 
unsigned int iUsage, DWORD rop);
+
+/* Layer plane descriptor */
+typedef struct tagLAYERPLANEDESCRIPTOR { // lpd
+   WORD  nSize;
+   WORD  nVersion;
+   DWORD dwFlags;
+   BYTE  iPixelType;
+   BYTE  cColorBits;
+   BYTE  cRedBits;
+   BYTE  cRedShift;
+   BYTE  cGreenBits;
+   BYTE  cGreenShift;
+   BYTE  cBlueBits;
+   BYTE  cBlueShift;
+   BYTE  cAlphaBits;
+   BYTE  cAlphaShift;
+   BYTE  cAccumBits;
+   BYTE  cAccumRedBits;
+   BYTE  cAccumGreenBits;
+   BYTE  cAccumBlueBits;
+   BYTE  cAccumAlphaBits;
+   BYTE  cDepthBits;
+   BYTE  cStencilBits;
+   BYTE  cAuxBuffers;
+   BYTE  iLayerPlane;
+   BYTE  bReserved;
+   COLORREF crTransparent;
+} LAYERPLANEDESCRIPTOR, * PLAYERPLANEDESCRIPTOR, FAR* LPLAYERPLANEDESCRIPTOR;
+
+/* WGL */
+typedef struct _WGLSWAP
+{
+   HDC hdc;
+   UINT uiFlags;
+} WGLSWAP;
+
+#define WGL_SWAPMULTIPLE_MAX 16
+
+WINGDIAPI DWORD WINAPI
+wglSwapMultipleBuffers(UINT n,
+   CONST WGLSWAP* ps);
+
+WINGDIAPI BOOL  WINAPI wglDeleteContext(HGLRC);
+
+/* wglSwapLayerBuffers flags */
+#define WGL_SWAP_MAIN_PLANE     0x00000001
+
+/* Pixel format descriptor */
+typedef struct tagPIXELFORMATDESCRIPTOR
+{
+   WORD  nSize;
+   WORD  nVersion;
+   DWORD dwFlags;
+   BYTE  iPixelType;
+   BYTE  cColorBits;
+   BYTE  cRedBits;
+   BYTE  cRedShift;
+   BYTE  cGreenBits;
+   BYTE  cGreenShift;
+   BYTE  cBlueBits;
+   BYTE  cBlueShift;
+   BYTE  cAlphaBits;
+   BYTE  cAlphaShift;
+   BYTE  cAccumBits;
+   BYTE  cAccumRedBits;
+   BYTE  cAccumGreenBits;
+   BYTE  cAccumBlueBits;
+   BYTE  cAccumAlphaBits;
+   BYTE  cDepthBits;
+   BYTE  cStencilBits;
+   BYTE  cAuxBuffers;
+   BYTE  iLayerType;
+   BYTE  bReserved;
+   DWORD dwLayerMask;
+   DWORD dwVisibleMask;
+   DWORD dwDamageMask;
+} PIXELFORMATDESCRIPTOR, * PPIXELFORMATDESCRIPTOR, FAR* 
LPPIXELFORMATDESCRIPTOR;
+
+/* Bitmap Info */
+typedef struct tagRGBQUAD {
+   BYTE rgbBlue;
+   BYTE rgbGreen;
+   BYTE rgbRed;
+   BYTE rgbReserved;
+} RGBQUAD;
+
+typedef struct tagBITMAPINFO {
+   BITMAPINFOHEADER bmiHeader;
+   RGBQUAD          bmiColors[1];
+} BITMAPINFO, * LPBITMAPINFO, * PBITMAPINFO;
+
+/* Glyph Info */
+
+typedef struct tagGLYPHMETRICSFLOAT {
+  FLOAT      gmfBlackBoxX;
+  FLOAT      gmfBlackBoxY;
+#ifndef _GAMING_XBOX
+  POINTFLOAT gmfptGlyphOrigin;
+#else
+  FLOAT gmfptGlyphOriginX;
+  FLOAT gmfptGlyphOriginY;
+#endif
+  FLOAT      gmfCellIncX;
+  FLOAT      gmfCellIncY;
+} GLYPHMETRICSFLOAT, *PGLYPHMETRICSFLOAT, *LPGLYPHMETRICSFLOAT;
+
+#endif /* _GAMING_XBOX */
+
+#endif /* STW_PIXELFORMAT_H */
diff --git a/src/gallium/frontends/wgl/stw_getprocaddress.c 
b/src/gallium/frontends/wgl/stw_getprocaddress.c
index d77b3520dbd..9f3014d726e 100644
--- a/src/gallium/frontends/wgl/stw_getprocaddress.c
+++ b/src/gallium/frontends/wgl/stw_getprocaddress.c
@@ -35,6 +35,7 @@
 
 #include "glapi/glapi.h"
 #include "stw_device.h"
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_nopfuncs.h"
 
diff --git a/src/gallium/frontends/wgl/stw_pixelformat.c 
b/src/gallium/frontends/wgl/stw_pixelformat.c
index ca6a1340b42..73073e636e4 100644
--- a/src/gallium/frontends/wgl/stw_pixelformat.c
+++ b/src/gallium/frontends/wgl/stw_pixelformat.c
@@ -34,6 +34,7 @@
 #include "util/u_memory.h"
 
 #include <GL/gl.h>
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_device.h"
 #include "stw_framebuffer.h"
diff --git a/src/gallium/frontends/wgl/stw_tls.c 
b/src/gallium/frontends/wgl/stw_tls.c
index 1b2b80725af..0e8c177aa66 100644
--- a/src/gallium/frontends/wgl/stw_tls.c
+++ b/src/gallium/frontends/wgl/stw_tls.c
@@ -73,6 +73,7 @@ stw_tls_init(void)
     * XXX: Except for the current thread since it there is an explicit
     * stw_tls_init_thread() call for it later on.
     */
+#ifndef _GAMING_XBOX
    if (1) {
       DWORD dwCurrentProcessId = GetCurrentProcessId();
       DWORD dwCurrentThreadId = GetCurrentThreadId();
@@ -103,6 +104,7 @@ stw_tls_init(void)
          CloseHandle(hSnapshot);
       }
    }
+#endif /* _GAMING_XBOX */
 
    return TRUE;
 }
@@ -127,10 +129,14 @@ stw_tls_data_create(DWORD dwThreadId)
 
    data->dwThreadId = dwThreadId;
 
+#ifndef _GAMING_XBOX
    data->hCallWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC,
                                              stw_call_window_proc,
                                              NULL,
                                              dwThreadId);
+#else
+   data->hCallWndProcHook = NULL;
+#endif
    if (data->hCallWndProcHook == NULL) {
       goto no_hook;
    }
@@ -161,10 +167,12 @@ stw_tls_data_destroy(struct stw_tls_data *data)
       debug_printf("%s(0x%04lx)\n", __func__, data->dwThreadId);
    }
 
+#ifndef _GAMING_XBOX
    if (data->hCallWndProcHook) {
       UnhookWindowsHookEx(data->hCallWndProcHook);
       data->hCallWndProcHook = NULL;
    }
+#endif
 
    free(data);
 }
diff --git a/src/gallium/targets/libgl-gdi/stw_wgl.c 
b/src/gallium/targets/libgl-gdi/stw_wgl.c
index 619acb9822a..25a4b18ed6f 100644
--- a/src/gallium/targets/libgl-gdi/stw_wgl.c
+++ b/src/gallium/targets/libgl-gdi/stw_wgl.c
@@ -42,6 +42,7 @@
 #include <GL/gl.h>
 
 #include "util/u_debug.h"
+#include "stw_gdishim.h"
 #include "gldrv.h"
 #include "stw_context.h"
 #include "stw_pixelformat.h"
@@ -223,6 +224,7 @@ wglUseFontBitmapsW(
    DWORD count,
    DWORD listBase )
 {
+#ifndef _GAMING_XBOX
    GLYPHMETRICS gm;
    MAT2 tra;
    FIXED one, minus_one, zero;
@@ -273,6 +275,9 @@ wglUseFontBitmapsW(
    free(buffer);
 
    return result;
+#else
+   return FALSE;
+#endif /* _GAMING_XBOX */
 }
 
 WINGDIAPI BOOL APIENTRY
diff --git a/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer_xbox.cpp 
b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer_xbox.cpp
new file mode 100644
index 00000000000..753e8fb2b42
--- /dev/null
+++ b/src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer_xbox.cpp
@@ -0,0 +1,294 @@
+/*
+ * 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 <new>
+
+#include <windows.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_resource.h"
+#include "d3d12/d3d12_screen.h"
+
+constexpr uint32_t num_buffers = 2;
+static int current_backbuffer_index = 0;
+static bool has_signaled_first_time = false;
+static int cached_interval = 1;
+
+struct d3d12_wgl_framebuffer {
+   struct stw_winsys_framebuffer base;
+
+   struct d3d12_screen *screen;
+   enum pipe_format pformat;
+   ID3D12Resource *images[num_buffers];
+   D3D12_CPU_DESCRIPTOR_HANDLE rtvs[num_buffers];
+   ID3D12DescriptorHeap *rtvHeap;
+   pipe_resource *buffers[num_buffers];
+};
+
+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,
+                              pipe_context *ctx)
+{
+   struct d3d12_wgl_framebuffer *framebuffer = d3d12_wgl_framebuffer(fb);
+   struct pipe_fence_handle *fence = NULL;
+
+   if (ctx) {
+      /* 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);
+      }
+   }
+
+   framebuffer->rtvHeap->Release();
+   for (int i = 0; i < num_buffers; ++i) {
+      if (framebuffer->buffers[i]) {
+         d3d12_resource_release(d3d12_resource(framebuffer->buffers[i]));
+         pipe_resource_reference(&framebuffer->buffers[i], NULL);
+      }
+   }
+
+   delete framebuffer;
+}
+
+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);
+
+   if (framebuffer->rtvHeap == NULL) {
+      D3D12_DESCRIPTOR_HEAP_DESC descHeapDesc = {};
+      descHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
+      descHeapDesc.NumDescriptors = num_buffers;
+      framebuffer->screen->dev->CreateDescriptorHeap(&descHeapDesc,
+                                                     
IID_PPV_ARGS(&framebuffer->rtvHeap));
+   }
+
+   // Release the old images
+   for (int i = 0; i < num_buffers; i++) {
+      if (framebuffer->buffers[i]) {
+         d3d12_resource_release(d3d12_resource(framebuffer->buffers[i]));
+         pipe_resource_reference(&framebuffer->buffers[i], NULL);
+      }
+   }
+
+   D3D12_HEAP_PROPERTIES heapProps = {};
+   heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
+
+   D3D12_RESOURCE_DESC resDesc;
+   resDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+   resDesc.Width = templ->width0;
+   resDesc.Height = templ->height0;
+   resDesc.Alignment = 0;
+   resDesc.DepthOrArraySize = 1;
+   resDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
+   resDesc.Format = d3d12_get_format(templ->format);
+   resDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+   resDesc.MipLevels = 1;
+   resDesc.SampleDesc.Count = 1;
+   resDesc.SampleDesc.Quality = 0;
+
+   D3D12_CLEAR_VALUE optimizedClearValue = {};
+   optimizedClearValue.Format = resDesc.Format;
+
+   D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
+   rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
+   rtvDesc.Format = resDesc.Format;
+   rtvDesc.Texture2D.MipSlice = 0;
+   rtvDesc.Texture2D.PlaneSlice = 0;
+
+   for (int i = 0; i < num_buffers; i++) {
+      if (FAILED(framebuffer->screen->dev->CreateCommittedResource(
+         &heapProps,
+         D3D12_HEAP_FLAG_ALLOW_DISPLAY,
+         &resDesc,
+         D3D12_RESOURCE_STATE_PRESENT,
+         &optimizedClearValue,
+         IID_PPV_ARGS(&framebuffer->images[i])
+      ))) {
+         assert(0);
+      }
+
+      framebuffer->rtvs[i].ptr =
+         framebuffer->rtvHeap->GetCPUDescriptorHandleForHeapStart().ptr +
+         ((int64_t)i * 
framebuffer->screen->dev->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV));
+
+      framebuffer->screen->dev->CreateRenderTargetView(
+         framebuffer->images[i],
+         &rtvDesc,
+         framebuffer->rtvs[i]
+      );
+   }
+
+   framebuffer->pformat = templ->format;
+}
+
+static boolean
+d3d12_wgl_framebuffer_present(stw_winsys_framebuffer *fb, int interval)
+{
+   auto framebuffer = d3d12_wgl_framebuffer(fb);
+   D3D12XBOX_PRESENT_PLANE_PARAMETERS planeParams = {};
+   planeParams.Token = framebuffer->screen->frame_token;
+   planeParams.ResourceCount = 1;
+   planeParams.ppResources = &framebuffer->images[current_backbuffer_index];
+
+   D3D12XBOX_PRESENT_PARAMETERS presentParams = {};
+   presentParams.Flags = (interval == 0) ?
+      D3D12XBOX_PRESENT_FLAG_IMMEDIATE :
+      D3D12XBOX_PRESENT_FLAG_NONE;
+
+   if (cached_interval != interval) {
+      framebuffer->screen->dev->SetFrameIntervalX(
+         nullptr,
+         D3D12XBOX_FRAME_INTERVAL_60_HZ,
+         interval,
+         D3D12XBOX_FRAME_INTERVAL_FLAG_NONE
+      );
+      cached_interval = interval;
+   }
+
+   framebuffer->screen->cmdqueue->PresentX(1, &planeParams, &presentParams);
+
+   current_backbuffer_index = !current_backbuffer_index;
+
+   framebuffer->screen->frame_token = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL;
+   framebuffer->screen->dev->WaitFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, 
INFINITE,
+                                             nullptr, 
D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE,
+                                             
&framebuffer->screen->frame_token);
+
+   return true;
+}
+
+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;
+
+   UINT index = current_backbuffer_index;
+   if (statt == ST_ATTACHMENT_FRONT_LEFT)
+      index = !index;
+
+   if (framebuffer->buffers[index]) {
+      pipe_reference(NULL, &framebuffer->buffers[index]->reference);
+      return framebuffer->buffers[index];
+   }
+
+   ID3D12Resource *res = framebuffer->images[index];
+
+   struct winsys_handle handle;
+   memset(&handle, 0, sizeof(handle));
+   handle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
+   handle.format = framebuffer->pformat;
+   handle.com_obj = res;
+
+   D3D12_RESOURCE_DESC res_desc = GetDesc(res);
+
+   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;
+
+   pipe_resource_reference(&framebuffer->buffers[index],
+      pscreen->resource_from_handle(pscreen, &templ, &handle,
+         PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));
+   return framebuffer->buffers[index];
+}
+
+struct stw_winsys_framebuffer*
+d3d12_wgl_create_framebuffer(struct pipe_screen *screen,
+                             HWND hWnd,
+                             int iPixelFormat)
+{
+   const struct stw_pixelformat_info *pfi =
+      stw_pixelformat_get_info(iPixelFormat);
+   if (!(pfi->pfd.dwFlags & PFD_DOUBLEBUFFER) ||
+      (pfi->pfd.dwFlags & PFD_SUPPORT_GDI))
+      return NULL;
+
+   struct d3d12_wgl_framebuffer *fb = CALLOC_STRUCT(d3d12_wgl_framebuffer);
+   if (!fb)
+      return NULL;
+
+   new (fb) struct d3d12_wgl_framebuffer();
+
+   fb->screen = d3d12_screen(screen);
+   fb->images[0] = NULL;
+   fb->images[1] = NULL;
+   fb->rtvHeap = NULL;
+   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;
+
+   // Xbox applications must manually handle Suspend/Resume events on the 
Command Queue.
+   // To allow the application to access the queue, we store a pointer in the 
HWND's user data.
+   SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) fb->screen->cmdqueue);
+
+   // Schedule the frame interval and origin frame event
+   fb->screen->dev->SetFrameIntervalX(
+      nullptr,
+      D3D12XBOX_FRAME_INTERVAL_60_HZ,
+      cached_interval,
+      D3D12XBOX_FRAME_INTERVAL_FLAG_NONE
+   );
+   fb->screen->dev->ScheduleFrameEventX(
+      D3D12XBOX_FRAME_EVENT_ORIGIN,
+      0,
+      nullptr,
+      D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE
+   );
+
+   return &fb->base;
+}
diff --git a/src/gallium/winsys/d3d12/wgl/meson.build 
b/src/gallium/winsys/d3d12/wgl/meson.build
index 15769b5b19a..c313fe8a8a5 100644
--- a/src/gallium/winsys/d3d12/wgl/meson.build
+++ b/src/gallium/winsys/d3d12/wgl/meson.build
@@ -19,10 +19,16 @@
 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 # IN THE SOFTWARE.
 
+files_libd3d12winsys = files('d3d12_wgl_winsys.c')
+if target_machine.system().startswith('Gaming.Xbox')
+  files_libd3d12winsys += files('d3d12_wgl_framebuffer_xbox.cpp')
+else
+  files_libd3d12winsys += files('d3d12_wgl_framebuffer.cpp')
+endif
 
 libd3d12winsys = static_library(
   'd3d12winsys',
-  files('d3d12_wgl_framebuffer.cpp', 'd3d12_wgl_winsys.c'),
+  files_libd3d12winsys,
   include_directories : [inc_src, inc_wgl, inc_include, inc_gallium, 
inc_gallium_aux, inc_gallium_drivers],
   dependencies : [dep_dxheaders, idep_nir_headers],
   gnu_symbol_visibility : 'hidden',
diff --git a/src/gallium/winsys/sw/gdi/gdi_sw_winsys.c 
b/src/gallium/winsys/sw/gdi/gdi_sw_winsys.c
index 49a138c9f06..7077862d4f3 100644
--- a/src/gallium/winsys/sw/gdi/gdi_sw_winsys.c
+++ b/src/gallium/winsys/sw/gdi/gdi_sw_winsys.c
@@ -44,6 +44,7 @@
 #include "util/u_memory.h"
 #include "frontend/sw_winsys.h"
 #include "gdi_sw_winsys.h"
+#include "wgl/stw_gdishim.h"
 
 
 struct gdi_sw_displaytarget
diff --git a/src/gallium/winsys/sw/gdi/meson.build 
b/src/gallium/winsys/sw/gdi/meson.build
index ac6c7cf0aa2..93a199af413 100644
--- a/src/gallium/winsys/sw/gdi/meson.build
+++ b/src/gallium/winsys/sw/gdi/meson.build
@@ -22,6 +22,6 @@ libwsgdi = static_library(
   'wsgdi',
   'gdi_sw_winsys.c',
   include_directories : [
-    inc_src, inc_include, inc_gallium, inc_gallium_aux, inc_gallium_drivers,
+    inc_src, inc_include, inc_gallium, inc_gallium_aux, inc_gallium_drivers, 
inc_frontends
   ],
 )
diff --git a/src/meson.build b/src/meson.build
index e5510452775..14f916fa3e8 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -26,6 +26,7 @@ inc_gallium_aux = include_directories('gallium/auxiliary')
 inc_amd_common = include_directories('amd/common')
 inc_tool = include_directories('tool')
 inc_virtio_gpu = include_directories('virtio/virtio-gpu')
+inc_frontends = include_directories('gallium/frontends')
 pps_datasources = []
 pps_includes = []
 

Reply via email to