2 * Direct3D wine internal interface main
4 * Copyright 2002-2003 The wine-d3d team
5 * Copyright 2002-2003 Raphael Junqueira
6 * Copyright 2004 Jason Edmeades
7 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
8 * Copyright 2009 Henri Verbeet for CodeWeavers
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d
);
32 WINE_DECLARE_DEBUG_CHANNEL(winediag
);
34 struct wined3d_wndproc
36 struct wined3d
*wined3d
;
41 struct wined3d_device
*device
;
45 struct wined3d_wndproc_table
47 struct wined3d_wndproc
*entries
;
52 struct wined3d_window_hook
59 struct wined3d_hooked_swapchain
61 struct wined3d_swapchain
*swapchain
;
65 struct wined3d_hook_table
67 struct wined3d_window_hook
*hooks
;
71 struct wined3d_hooked_swapchain
*swapchains
;
72 SIZE_T swapchains_size
;
73 SIZE_T swapchain_count
;
76 static struct wined3d_wndproc_table wndproc_table
;
77 static struct wined3d_hook_table hook_table
;
79 static CRITICAL_SECTION wined3d_cs
;
80 static CRITICAL_SECTION_DEBUG wined3d_cs_debug
=
83 {&wined3d_cs_debug
.ProcessLocksList
,
84 &wined3d_cs_debug
.ProcessLocksList
},
85 0, 0, {(DWORD_PTR
)(__FILE__
": wined3d_cs")}
87 static CRITICAL_SECTION wined3d_cs
= {&wined3d_cs_debug
, -1, 0, 0, 0, 0};
89 static CRITICAL_SECTION wined3d_wndproc_cs
;
90 static CRITICAL_SECTION_DEBUG wined3d_wndproc_cs_debug
=
92 0, 0, &wined3d_wndproc_cs
,
93 {&wined3d_wndproc_cs_debug
.ProcessLocksList
,
94 &wined3d_wndproc_cs_debug
.ProcessLocksList
},
95 0, 0, {(DWORD_PTR
)(__FILE__
": wined3d_wndproc_cs")}
97 static CRITICAL_SECTION wined3d_wndproc_cs
= {&wined3d_wndproc_cs_debug
, -1, 0, 0, 0, 0};
99 /* When updating default value here, make sure to update winecfg as well,
100 * where appropriate. */
101 struct wined3d_settings wined3d_settings
=
103 TRUE
, /* Multithreaded CS by default. */
104 MAKEDWORD_VERSION(4, 4), /* Default to OpenGL 4.4 */
105 ORM_FBO
, /* Use FBOs to do offscreen rendering */
106 PCI_VENDOR_NONE
,/* PCI Vendor ID */
107 PCI_DEVICE_NONE
,/* PCI Device ID */
108 0, /* The default of memory is set in init_driver_info */
109 NULL
, /* No wine logo by default */
110 TRUE
, /* Prefer multisample textures to multisample renderbuffers. */
111 ~0u, /* Don't force a specific sample count by default. */
112 FALSE
, /* Don't range check relative addressing indices in float constants. */
113 FALSE
, /* No strict shader math by default. */
114 ~0U, /* No VS shader model limit by default. */
115 ~0U, /* No HS shader model limit by default. */
116 ~0U, /* No DS shader model limit by default. */
117 ~0U, /* No GS shader model limit by default. */
118 ~0U, /* No PS shader model limit by default. */
119 ~0u, /* No CS shader model limit by default. */
120 WINED3D_RENDERER_AUTO
,
121 WINED3D_SHADER_BACKEND_AUTO
,
124 struct wined3d
* CDECL
wined3d_create(DWORD flags
)
126 struct wined3d
*object
;
129 if (!(object
= heap_alloc_zero(FIELD_OFFSET(struct wined3d
, adapters
[1]))))
131 ERR("Failed to allocate wined3d object memory.\n");
135 if (wined3d_settings
.renderer
== WINED3D_RENDERER_NO3D
)
136 flags
|= WINED3D_NO3D
;
138 if (FAILED(hr
= wined3d_init(object
, flags
)))
140 WARN("Failed to initialize wined3d object, hr %#x.\n", hr
);
145 TRACE("Created wined3d object %p.\n", object
);
150 static DWORD
get_config_key(HKEY defkey
, HKEY appkey
, const char *name
, char *buffer
, DWORD size
)
152 if (appkey
&& !RegQueryValueExA(appkey
, name
, 0, NULL
, (BYTE
*)buffer
, &size
)) return 0;
153 if (defkey
&& !RegQueryValueExA(defkey
, name
, 0, NULL
, (BYTE
*)buffer
, &size
)) return 0;
154 return ERROR_FILE_NOT_FOUND
;
157 static DWORD
get_config_key_dword(HKEY defkey
, HKEY appkey
, const char *name
, DWORD
*value
)
159 DWORD type
, data
, size
;
162 if (appkey
&& !RegQueryValueExA(appkey
, name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
) goto success
;
164 if (defkey
&& !RegQueryValueExA(defkey
, name
, 0, &type
, (BYTE
*)&data
, &size
) && type
== REG_DWORD
) goto success
;
166 return ERROR_FILE_NOT_FOUND
;
173 BOOL
wined3d_get_app_name(char *app_name
, unsigned int app_name_size
)
175 char buffer
[MAX_PATH
];
179 len
= GetModuleFileNameA(0, buffer
, ARRAY_SIZE(buffer
));
180 if (!(len
&& len
< MAX_PATH
))
184 if ((p
= strrchr(name
, '/' )))
186 if ((p
= strrchr(name
, '\\')))
189 len
= strlen(name
) + 1;
190 if (app_name_size
< len
)
193 memcpy(app_name
, name
, len
);
197 static BOOL
wined3d_dll_init(HINSTANCE hInstDLL
)
199 DWORD wined3d_context_tls_idx
;
200 char buffer
[MAX_PATH
+10];
201 DWORD size
= sizeof(buffer
);
207 wined3d_context_tls_idx
= TlsAlloc();
208 if (wined3d_context_tls_idx
== TLS_OUT_OF_INDEXES
)
210 DWORD err
= GetLastError();
211 ERR("Failed to allocate context TLS index, err %#x.\n", err
);
214 context_set_tls_idx(wined3d_context_tls_idx
);
216 /* We need our own window class for a fake window which we use to retrieve GL capabilities */
217 /* We might need CS_OWNDC in the future if we notice strange things on Windows.
218 * Various articles/posts about OpenGL problems on Windows recommend this. */
219 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
220 wc
.lpfnWndProc
= DefWindowProcA
;
223 wc
.hInstance
= hInstDLL
;
224 wc
.hIcon
= LoadIconA(NULL
, (const char *)IDI_WINLOGO
);
225 wc
.hCursor
= LoadCursorA(NULL
, (const char *)IDC_ARROW
);
226 wc
.hbrBackground
= NULL
;
227 wc
.lpszMenuName
= NULL
;
228 wc
.lpszClassName
= WINED3D_OPENGL_WINDOW_CLASS_NAME
;
230 if (!RegisterClassA(&wc
))
232 ERR("Failed to register window class 'WineD3D_OpenGL'!\n");
233 if (!TlsFree(wined3d_context_tls_idx
))
235 DWORD err
= GetLastError();
236 ERR("Failed to free context TLS index, err %#x.\n", err
);
241 DisableThreadLibraryCalls(hInstDLL
);
243 /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
244 if ( RegOpenKeyA( HKEY_CURRENT_USER
, "Software\\Wine\\Direct3D", &hkey
) ) hkey
= 0;
246 if (wined3d_get_app_name(buffer
, ARRAY_SIZE(buffer
)))
249 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\Direct3D */
250 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\AppDefaults", &tmpkey
))
252 strcat(buffer
, "\\Direct3D");
253 TRACE("Application name %s.\n", buffer
);
254 if (RegOpenKeyA(tmpkey
, buffer
, &appkey
)) appkey
= 0;
261 if (!get_config_key_dword(hkey
, appkey
, "csmt", &wined3d_settings
.cs_multithreaded
))
262 ERR_(winediag
)("Setting multithreaded command stream to %#x.\n", wined3d_settings
.cs_multithreaded
);
263 if (!get_config_key_dword(hkey
, appkey
, "MaxVersionGL", &tmpvalue
))
265 ERR_(winediag
)("Setting maximum allowed wined3d GL version to %u.%u.\n",
266 tmpvalue
>> 16, tmpvalue
& 0xffff);
267 wined3d_settings
.max_gl_version
= tmpvalue
;
269 if (!get_config_key(hkey
, appkey
, "shader_backend", buffer
, size
))
271 if (!_strnicmp(buffer
, "glsl", -1))
273 ERR_(winediag
)("Using the GLSL shader backend.\n");
274 wined3d_settings
.shader_backend
= WINED3D_SHADER_BACKEND_GLSL
;
276 else if (!_strnicmp(buffer
, "arb", -1))
278 ERR_(winediag
)("Using the ARB shader backend.\n");
279 wined3d_settings
.shader_backend
= WINED3D_SHADER_BACKEND_ARB
;
281 else if (!_strnicmp(buffer
, "none", -1))
283 ERR_(winediag
)("Disabling shader backends.\n");
284 wined3d_settings
.shader_backend
= WINED3D_SHADER_BACKEND_NONE
;
287 else if (!get_config_key(hkey
, appkey
, "UseGLSL", buffer
, size
) && !strcmp(buffer
, "disabled"))
289 wined3d_settings
.shader_backend
= WINED3D_SHADER_BACKEND_ARB
;
291 if (wined3d_settings
.shader_backend
== WINED3D_SHADER_BACKEND_ARB
292 || wined3d_settings
.shader_backend
== WINED3D_SHADER_BACKEND_NONE
)
294 ERR_(winediag
)("The GLSL shader backend has been disabled. You get to keep all the pieces if it breaks.\n");
295 TRACE("Use of GL Shading Language disabled.\n");
297 if (!get_config_key(hkey
, appkey
, "OffscreenRenderingMode", buffer
, size
)
298 && !strcmp(buffer
,"backbuffer"))
299 wined3d_settings
.offscreen_rendering_mode
= ORM_BACKBUFFER
;
300 if ( !get_config_key_dword( hkey
, appkey
, "VideoPciDeviceID", &tmpvalue
) )
302 int pci_device_id
= tmpvalue
;
304 /* A pci device id is 16-bit */
305 if(pci_device_id
> 0xffff)
307 ERR("Invalid value for VideoPciDeviceID. The value should be smaller or equal to 65535 or 0xffff\n");
311 TRACE("Using PCI Device ID %04x\n", pci_device_id
);
312 wined3d_settings
.pci_device_id
= pci_device_id
;
315 if ( !get_config_key_dword( hkey
, appkey
, "VideoPciVendorID", &tmpvalue
) )
317 int pci_vendor_id
= tmpvalue
;
319 /* A pci device id is 16-bit */
320 if(pci_vendor_id
> 0xffff)
322 ERR("Invalid value for VideoPciVendorID. The value should be smaller or equal to 65535 or 0xffff\n");
326 TRACE("Using PCI Vendor ID %04x\n", pci_vendor_id
);
327 wined3d_settings
.pci_vendor_id
= pci_vendor_id
;
330 if ( !get_config_key( hkey
, appkey
, "VideoMemorySize", buffer
, size
) )
332 int TmpVideoMemorySize
= atoi(buffer
);
333 if(TmpVideoMemorySize
> 0)
335 wined3d_settings
.emulated_textureram
= (UINT64
)TmpVideoMemorySize
*1024*1024;
336 TRACE("Use %iMiB = 0x%s bytes for emulated_textureram\n",
338 wine_dbgstr_longlong(wined3d_settings
.emulated_textureram
));
341 ERR("VideoMemorySize is %i but must be >0\n", TmpVideoMemorySize
);
343 if ( !get_config_key( hkey
, appkey
, "WineLogo", buffer
, size
) )
345 size_t len
= strlen(buffer
) + 1;
347 if (!(wined3d_settings
.logo
= heap_alloc(len
)))
348 ERR("Failed to allocate logo path memory.\n");
350 memcpy(wined3d_settings
.logo
, buffer
, len
);
352 if (!get_config_key_dword(hkey
, appkey
, "MultisampleTextures", &wined3d_settings
.multisample_textures
))
353 ERR_(winediag
)("Setting multisample textures to %#x.\n", wined3d_settings
.multisample_textures
);
354 if (!get_config_key_dword(hkey
, appkey
, "SampleCount", &wined3d_settings
.sample_count
))
355 ERR_(winediag
)("Forcing sample count to %u. This may not be compatible with all applications.\n",
356 wined3d_settings
.sample_count
);
357 if (!get_config_key(hkey
, appkey
, "CheckFloatConstants", buffer
, size
)
358 && !strcmp(buffer
, "enabled"))
360 TRACE("Checking relative addressing indices in float constants.\n");
361 wined3d_settings
.check_float_constants
= TRUE
;
363 if (!get_config_key_dword(hkey
, appkey
, "strict_shader_math", &wined3d_settings
.strict_shader_math
))
364 ERR_(winediag
)("Setting strict shader math to %#x.\n", wined3d_settings
.strict_shader_math
);
365 if (!get_config_key_dword(hkey
, appkey
, "MaxShaderModelVS", &wined3d_settings
.max_sm_vs
))
366 TRACE("Limiting VS shader model to %u.\n", wined3d_settings
.max_sm_vs
);
367 if (!get_config_key_dword(hkey
, appkey
, "MaxShaderModelHS", &wined3d_settings
.max_sm_hs
))
368 TRACE("Limiting HS shader model to %u.\n", wined3d_settings
.max_sm_hs
);
369 if (!get_config_key_dword(hkey
, appkey
, "MaxShaderModelDS", &wined3d_settings
.max_sm_ds
))
370 TRACE("Limiting DS shader model to %u.\n", wined3d_settings
.max_sm_ds
);
371 if (!get_config_key_dword(hkey
, appkey
, "MaxShaderModelGS", &wined3d_settings
.max_sm_gs
))
372 TRACE("Limiting GS shader model to %u.\n", wined3d_settings
.max_sm_gs
);
373 if (!get_config_key_dword(hkey
, appkey
, "MaxShaderModelPS", &wined3d_settings
.max_sm_ps
))
374 TRACE("Limiting PS shader model to %u.\n", wined3d_settings
.max_sm_ps
);
375 if (!get_config_key_dword(hkey
, appkey
, "MaxShaderModelCS", &wined3d_settings
.max_sm_cs
))
376 TRACE("Limiting CS shader model to %u.\n", wined3d_settings
.max_sm_cs
);
377 if (!get_config_key(hkey
, appkey
, "renderer", buffer
, size
))
379 if (!strcmp(buffer
, "vulkan"))
381 ERR_(winediag
)("Using the Vulkan renderer.\n");
382 wined3d_settings
.renderer
= WINED3D_RENDERER_VULKAN
;
384 else if (!strcmp(buffer
, "gl"))
386 ERR_(winediag
)("Using the OpenGL renderer.\n");
387 wined3d_settings
.renderer
= WINED3D_RENDERER_OPENGL
;
389 else if (!strcmp(buffer
, "gdi") || !strcmp(buffer
, "no3d"))
391 ERR_(winediag
)("Disabling 3D support.\n");
392 wined3d_settings
.renderer
= WINED3D_RENDERER_NO3D
;
397 if (appkey
) RegCloseKey( appkey
);
398 if (hkey
) RegCloseKey( hkey
);
403 static BOOL
wined3d_dll_destroy(HINSTANCE hInstDLL
)
405 DWORD wined3d_context_tls_idx
= context_get_tls_idx();
408 if (!TlsFree(wined3d_context_tls_idx
))
410 DWORD err
= GetLastError();
411 ERR("Failed to free context TLS index, err %#x.\n", err
);
414 for (i
= 0; i
< wndproc_table
.count
; ++i
)
416 /* Trying to unregister these would be futile. These entries can only
417 * exist if either we skipped them in wined3d_unregister_window() due
418 * to the application replacing the wndproc after the entry was
419 * registered, or if the application still has an active wined3d
420 * device. In the latter case the application has bigger problems than
422 WARN("Leftover wndproc table entry %p.\n", &wndproc_table
.entries
[i
]);
424 heap_free(wndproc_table
.entries
);
426 heap_free(hook_table
.swapchains
);
427 for (i
= 0; i
< hook_table
.hook_count
; ++i
)
429 WARN("Leftover hook table entry %p.\n", &hook_table
.hooks
[i
]);
430 UnhookWindowsHookEx(hook_table
.hooks
[i
].hook
);
432 heap_free(hook_table
.hooks
);
434 heap_free(wined3d_settings
.logo
);
435 UnregisterClassA(WINED3D_OPENGL_WINDOW_CLASS_NAME
, hInstDLL
);
437 DeleteCriticalSection(&wined3d_wndproc_cs
);
438 DeleteCriticalSection(&wined3d_cs
);
442 void WINAPI
wined3d_mutex_lock(void)
444 EnterCriticalSection(&wined3d_cs
);
447 void WINAPI
wined3d_mutex_unlock(void)
449 LeaveCriticalSection(&wined3d_cs
);
452 static void wined3d_wndproc_mutex_lock(void)
454 EnterCriticalSection(&wined3d_wndproc_cs
);
457 static void wined3d_wndproc_mutex_unlock(void)
459 LeaveCriticalSection(&wined3d_wndproc_cs
);
462 static struct wined3d_output
* wined3d_get_output_from_window(const struct wined3d
*wined3d
,
465 unsigned int adapter_idx
, output_idx
;
466 struct wined3d_adapter
*adapter
;
467 MONITORINFOEXW monitor_info
;
470 TRACE("wined3d %p, hwnd %p.\n", wined3d
, hwnd
);
472 monitor
= MonitorFromWindow(hwnd
, MONITOR_DEFAULTTONEAREST
);
473 monitor_info
.cbSize
= sizeof(monitor_info
);
474 if (!GetMonitorInfoW(monitor
, (MONITORINFO
*)&monitor_info
))
476 ERR("GetMonitorInfoW failed, error %#x.\n", GetLastError());
480 for (adapter_idx
= 0; adapter_idx
< wined3d
->adapter_count
; ++adapter_idx
)
482 adapter
= wined3d
->adapters
[adapter_idx
];
483 for (output_idx
= 0; output_idx
< adapter
->output_count
; ++output_idx
)
485 if (!lstrcmpiW(adapter
->outputs
[output_idx
].device_name
, monitor_info
.szDevice
))
486 return &adapter
->outputs
[output_idx
];
490 /* Because wined3d only supports one output right now. A window can be on non-primary outputs
491 * and thus fails to get its correct output. In this case, return the primary output for now */
492 return &wined3d
->adapters
[0]->outputs
[0];
495 static struct wined3d_wndproc
*wined3d_find_wndproc(HWND window
, struct wined3d
*wined3d
)
499 for (i
= 0; i
< wndproc_table
.count
; ++i
)
501 struct wined3d_wndproc
*entry
= &wndproc_table
.entries
[i
];
503 if (entry
->window
== window
&& entry
->wined3d
== wined3d
)
510 BOOL
wined3d_filter_messages(HWND window
, BOOL filter
)
512 struct wined3d_wndproc
*entry
;
515 wined3d_wndproc_mutex_lock();
517 if (!(entry
= wined3d_find_wndproc(window
, NULL
)))
519 wined3d_wndproc_mutex_unlock();
524 entry
->filter
= filter
;
526 wined3d_wndproc_mutex_unlock();
531 static LRESULT CALLBACK
wined3d_wndproc(HWND window
, UINT message
, WPARAM wparam
, LPARAM lparam
)
533 struct wined3d_wndproc
*entry
;
534 struct wined3d_device
*device
;
535 BOOL unicode
, filter
;
538 wined3d_wndproc_mutex_lock();
540 if (!(entry
= wined3d_find_wndproc(window
, NULL
)))
542 wined3d_wndproc_mutex_unlock();
543 ERR("Window %p is not registered with wined3d.\n", window
);
544 return DefWindowProcW(window
, message
, wparam
, lparam
);
547 device
= entry
->device
;
548 unicode
= entry
->unicode
;
549 filter
= entry
->filter
;
551 wined3d_wndproc_mutex_unlock();
555 if (filter
&& message
!= WM_DISPLAYCHANGE
)
557 TRACE("Filtering message: window %p, message %#x, wparam %#lx, lparam %#lx.\n",
558 window
, message
, wparam
, lparam
);
561 return DefWindowProcW(window
, message
, wparam
, lparam
);
562 return DefWindowProcA(window
, message
, wparam
, lparam
);
565 return device_process_message(device
, window
, unicode
, message
, wparam
, lparam
, proc
);
568 return CallWindowProcW(proc
, window
, message
, wparam
, lparam
);
569 return CallWindowProcA(proc
, window
, message
, wparam
, lparam
);
572 static LRESULT CALLBACK
wined3d_hook_proc(int code
, WPARAM wparam
, LPARAM lparam
)
574 struct wined3d_swapchain_desc swapchain_desc
;
575 struct wined3d_swapchain
*swapchain
;
576 struct wined3d_wndproc
*entry
;
577 struct wined3d_output
*output
;
578 MSG
*msg
= (MSG
*)lparam
;
581 /* Handle Alt+Enter. */
582 if (code
== HC_ACTION
&& msg
->message
== WM_SYSKEYDOWN
583 && msg
->wParam
== VK_RETURN
&& (msg
->lParam
& (KF_ALTDOWN
<< 16)))
585 wined3d_wndproc_mutex_lock();
587 for (i
= 0; i
< hook_table
.swapchain_count
; ++i
)
589 swapchain
= hook_table
.swapchains
[i
].swapchain
;
591 if (swapchain
->state
.device_window
!= msg
->hwnd
)
594 if ((entry
= wined3d_find_wndproc(msg
->hwnd
, swapchain
->device
->wined3d
))
595 && (entry
->flags
& (WINED3D_REGISTER_WINDOW_NO_WINDOW_CHANGES
596 | WINED3D_REGISTER_WINDOW_NO_ALT_ENTER
)))
599 wined3d_swapchain_get_desc(swapchain
, &swapchain_desc
);
600 swapchain_desc
.windowed
= !swapchain_desc
.windowed
;
601 if (!(output
= wined3d_get_output_from_window(swapchain
->device
->wined3d
,
602 swapchain
->state
.device_window
)))
604 ERR("Failed to get output from window %p.\n", swapchain
->state
.device_window
);
607 swapchain_desc
.output
= output
;
608 wined3d_swapchain_state_set_fullscreen(&swapchain
->state
, &swapchain_desc
, NULL
);
610 wined3d_wndproc_mutex_unlock();
615 wined3d_wndproc_mutex_unlock();
618 return CallNextHookEx(0, code
, wparam
, lparam
);
621 BOOL CDECL
wined3d_register_window(struct wined3d
*wined3d
, HWND window
,
622 struct wined3d_device
*device
, unsigned int flags
)
624 struct wined3d_wndproc
*entry
;
626 TRACE("wined3d %p, window %p, device %p, flags %#x.\n", wined3d
, window
, device
, flags
);
628 wined3d_wndproc_mutex_lock();
630 if ((entry
= wined3d_find_wndproc(window
, wined3d
)))
633 WARN("Window %p is already registered with wined3d.\n", window
);
634 entry
->flags
= flags
;
635 wined3d_wndproc_mutex_unlock();
639 if (!wined3d_array_reserve((void **)&wndproc_table
.entries
, &wndproc_table
.size
,
640 wndproc_table
.count
+ 1, sizeof(*entry
)))
642 wined3d_wndproc_mutex_unlock();
643 ERR("Failed to grow table.\n");
647 entry
= &wndproc_table
.entries
[wndproc_table
.count
++];
648 entry
->window
= window
;
649 entry
->unicode
= IsWindowUnicode(window
);
652 /* Set a window proc that matches the window. Some applications (e.g.
653 * NoX) replace the window proc after we've set ours, and expect to be
654 * able to call the previous one (ours) directly, without using
655 * CallWindowProc(). */
657 entry
->proc
= (WNDPROC
)SetWindowLongPtrW(window
, GWLP_WNDPROC
, (LONG_PTR
)wined3d_wndproc
);
659 entry
->proc
= (WNDPROC
)SetWindowLongPtrA(window
, GWLP_WNDPROC
, (LONG_PTR
)wined3d_wndproc
);
665 entry
->device
= device
;
666 entry
->wined3d
= wined3d
;
667 entry
->flags
= flags
;
669 wined3d_wndproc_mutex_unlock();
674 static BOOL
restore_wndproc(struct wined3d_wndproc
*entry
)
680 proc
= GetWindowLongPtrW(entry
->window
, GWLP_WNDPROC
);
681 if (proc
!= (LONG_PTR
)wined3d_wndproc
)
683 SetWindowLongPtrW(entry
->window
, GWLP_WNDPROC
, (LONG_PTR
)entry
->proc
);
687 proc
= GetWindowLongPtrA(entry
->window
, GWLP_WNDPROC
);
688 if (proc
!= (LONG_PTR
)wined3d_wndproc
)
690 SetWindowLongPtrA(entry
->window
, GWLP_WNDPROC
, (LONG_PTR
)entry
->proc
);
696 void wined3d_unregister_window(HWND window
)
698 struct wined3d_wndproc
*entry
, *last
;
700 wined3d_wndproc_mutex_lock();
702 if (!(entry
= wined3d_find_wndproc(window
, NULL
)))
704 wined3d_wndproc_mutex_unlock();
705 ERR("Window %p is not registered with wined3d.\n", window
);
709 if (entry
->proc
&& !restore_wndproc(entry
))
711 entry
->device
= NULL
;
712 WARN("Not unregistering window %p, current window proc doesn't match wined3d window proc.\n", window
);
713 wined3d_wndproc_mutex_unlock();
717 last
= &wndproc_table
.entries
[--wndproc_table
.count
];
718 if (entry
!= last
) *entry
= *last
;
720 wined3d_wndproc_mutex_unlock();
723 void CDECL
wined3d_unregister_windows(struct wined3d
*wined3d
)
725 struct wined3d_wndproc
*entry
, *last
;
728 TRACE("wined3d %p.\n", wined3d
);
730 wined3d_wndproc_mutex_lock();
732 while (i
< wndproc_table
.count
)
734 entry
= &wndproc_table
.entries
[i
];
736 if (entry
->wined3d
!= wined3d
)
742 if (entry
->proc
&& !restore_wndproc(entry
))
744 entry
->device
= NULL
;
745 WARN("Not unregistering window %p, current window proc doesn't match wined3d window proc.\n",
751 last
= &wndproc_table
.entries
[--wndproc_table
.count
];
758 wined3d_wndproc_mutex_unlock();
761 static struct wined3d_window_hook
*wined3d_find_hook(DWORD thread_id
)
765 for (i
= 0; i
< hook_table
.hook_count
; ++i
)
767 if (hook_table
.hooks
[i
].thread_id
== thread_id
)
768 return &hook_table
.hooks
[i
];
774 void wined3d_hook_swapchain(struct wined3d_swapchain
*swapchain
)
776 struct wined3d_hooked_swapchain
*swapchain_entry
;
777 struct wined3d_window_hook
*hook
;
779 wined3d_wndproc_mutex_lock();
781 if (!wined3d_array_reserve((void **)&hook_table
.swapchains
, &hook_table
.swapchains_size
,
782 hook_table
.swapchain_count
+ 1, sizeof(*swapchain_entry
)))
784 wined3d_wndproc_mutex_unlock();
788 swapchain_entry
= &hook_table
.swapchains
[hook_table
.swapchain_count
++];
789 swapchain_entry
->swapchain
= swapchain
;
790 swapchain_entry
->thread_id
= GetWindowThreadProcessId(swapchain
->state
.device_window
, NULL
);
792 if ((hook
= wined3d_find_hook(swapchain_entry
->thread_id
)))
795 wined3d_wndproc_mutex_unlock();
799 if (!wined3d_array_reserve((void **)&hook_table
.hooks
, &hook_table
.hooks_size
,
800 hook_table
.hook_count
+ 1, sizeof(*hook
)))
802 --hook_table
.swapchain_count
;
803 wined3d_wndproc_mutex_unlock();
807 hook
= &hook_table
.hooks
[hook_table
.hook_count
++];
808 hook
->thread_id
= swapchain_entry
->thread_id
;
809 hook
->hook
= SetWindowsHookExW(WH_GETMESSAGE
, wined3d_hook_proc
, 0, hook
->thread_id
);
812 wined3d_wndproc_mutex_unlock();
815 void wined3d_unhook_swapchain(struct wined3d_swapchain
*swapchain
)
817 struct wined3d_hooked_swapchain
*swapchain_entry
, *last_swapchain_entry
;
818 struct wined3d_window_hook
*hook
, *last_hook
;
821 wined3d_wndproc_mutex_lock();
823 for (i
= 0; i
< hook_table
.swapchain_count
; ++i
)
825 swapchain_entry
= &hook_table
.swapchains
[i
];
827 if (swapchain_entry
->swapchain
!= swapchain
)
830 if ((hook
= wined3d_find_hook(swapchain_entry
->thread_id
)) && !--hook
->count
)
832 UnhookWindowsHookEx(hook
->hook
);
833 last_hook
= &hook_table
.hooks
[--hook_table
.hook_count
];
834 if (hook
!= last_hook
)
838 last_swapchain_entry
= &hook_table
.swapchains
[--hook_table
.swapchain_count
];
839 if (swapchain_entry
!= last_swapchain_entry
)
840 *swapchain_entry
= *last_swapchain_entry
;
845 wined3d_wndproc_mutex_unlock();
848 /* At process attach */
849 BOOL WINAPI
DllMain(HINSTANCE inst
, DWORD reason
, void *reserved
)
853 case DLL_PROCESS_ATTACH
:
854 return wined3d_dll_init(inst
);
856 case DLL_PROCESS_DETACH
:
858 return wined3d_dll_destroy(inst
);
861 case DLL_THREAD_DETACH
:
862 if (!wined3d_context_gl_set_current(NULL
))
864 ERR("Failed to clear current context.\n");