From 882a78b8adf782b3a3d58274ece14e1fa9330f46 Mon Sep 17 00:00:00 2001 From: Caleb Cornett Date: Wed, 11 Jan 2023 10:48:49 -0500 Subject: [PATCH] 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 Co-authored-by: David Jacewicz Co-authored-by: tieuchanlong Reviewed-by: Jesse Natalie Part-of: --- 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 + .../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 +++++++++ .../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(-) create mode 100644 src/gallium/frontends/wgl/stw_gdishim.c create mode 100644 src/gallium/frontends/wgl/stw_gdishim.h create mode 100644 src/gallium/winsys/d3d12/wgl/d3d12_wgl_framebuffer_xbox.cpp 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 #include +#include #include 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 +#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 #include +#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 +#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 + +/* 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 +#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 #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 + +#include +#include + +#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 = []