diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c index 2312a6aaec8..12ed0fbfd38 100644 --- a/dlls/d3d8/device.c +++ b/dlls/d3d8/device.c @@ -2764,6 +2764,19 @@ static const IWineD3DDeviceParentVtbl d3d8_wined3d_device_parent_vtbl = device_parent_CreateSwapChain, }; +static void setup_fpu(void) +{ + WORD cw; + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + __asm__ volatile ("fnstcw %0" : "=m" (cw)); + cw = (cw & ~0xf3f) | 0x3f; + __asm__ volatile ("fldcw %0" : : "m" (cw)); +#else + FIXME("FPU setup not implemented for this platform.\n"); +#endif +} + HRESULT device_init(IDirect3DDevice8Impl *device, IWineD3D *wined3d, UINT adapter, D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters) { @@ -2782,6 +2795,8 @@ HRESULT device_init(IDirect3DDevice8Impl *device, IWineD3D *wined3d, UINT adapte } device->handle_table.table_size = D3D8_INITIAL_HANDLE_TABLE_SIZE; + if (!(flags & D3DCREATE_FPU_PRESERVE)) setup_fpu(); + wined3d_mutex_lock(); hr = IWineD3D_CreateDevice(wined3d, adapter, device_type, focus_window, flags, (IUnknown *)device, (IWineD3DDeviceParent *)&device->device_parent_vtbl, &device->WineD3DDevice); diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c index cd2df9a6615..b46ec4e6b0a 100644 --- a/dlls/d3d8/tests/device.c +++ b/dlls/d3d8/tests/device.c @@ -1797,6 +1797,89 @@ done: UnregisterClassA("d3d8_test_wndproc_wc", GetModuleHandleA(NULL)); } +static inline void set_fpu_cw(WORD cw) +{ +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + __asm__ volatile ("fnclex"); + __asm__ volatile ("fldcw %0" : : "m" (cw)); +#endif +} + +static inline WORD get_fpu_cw(void) +{ + WORD cw = 0; +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + __asm__ volatile ("fnstcw %0" : "=m" (cw)); +#endif + return cw; +} + +static void test_fpu_setup(void) +{ + D3DPRESENT_PARAMETERS present_parameters; + IDirect3DDevice8 *device; + D3DDISPLAYMODE d3ddm; + HWND window = NULL; + IDirect3D8 *d3d8; + HRESULT hr; + WORD cw; + + d3d8 = pDirect3DCreate8(D3D_SDK_VERSION); + ok(!!d3d8, "Failed to create a d3d8 object.\n"); + if (!d3d8) return; + + window = CreateWindowA("static", "d3d8_test", WS_CAPTION, 0, 0, 640, 480, 0, 0, 0, 0); + ok(!!window, "Failed to create a window.\n"); + if (!window) goto done; + + hr = IDirect3D8_GetAdapterDisplayMode(d3d8, D3DADAPTER_DEFAULT, &d3ddm); + ok(SUCCEEDED(hr), "GetAdapterDisplayMode failed, hr %#x.\n", hr); + + memset(&present_parameters, 0, sizeof(present_parameters)); + present_parameters.Windowed = TRUE; + present_parameters.hDeviceWindow = window; + present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD; + present_parameters.BackBufferFormat = d3ddm.Format; + + set_fpu_cw(0xf60); + cw = get_fpu_cw(); + ok(cw == 0xf60, "cw is %#x, expected 0xf60.\n", cw); + + hr = IDirect3D8_CreateDevice(d3d8, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, + D3DCREATE_HARDWARE_VERTEXPROCESSING, &present_parameters, &device); + if (FAILED(hr)) + { + skip("Failed to create a device, hr %#x.\n", hr); + set_fpu_cw(0x37f); + goto done; + } + + cw = get_fpu_cw(); + ok(cw == 0x7f, "cw is %#x, expected 0x7f.\n", cw); + + IDirect3DDevice8_Release(device); + + cw = get_fpu_cw(); + ok(cw == 0x7f, "cw is %#x, expected 0x7f.\n", cw); + set_fpu_cw(0xf60); + cw = get_fpu_cw(); + ok(cw == 0xf60, "cw is %#x, expected 0xf60.\n", cw); + + hr = IDirect3D8_CreateDevice(d3d8, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, + D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE, &present_parameters, &device); + ok(SUCCEEDED(hr), "CreateDevice failed, hr %#x.\n", hr); + + cw = get_fpu_cw(); + ok(cw == 0xf60, "cw is %#x, expected 0xf60.\n", cw); + set_fpu_cw(0x37f); + + IDirect3DDevice8_Release(device); + +done: + if (window) DestroyWindow(window); + if (d3d8) IDirect3D8_Release(d3d8); +} + START_TEST(device) { HMODULE d3d8_handle = LoadLibraryA( "d3d8.dll" ); @@ -1819,6 +1902,9 @@ START_TEST(device) } IDirect3D8_Release(d3d8); +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + test_fpu_setup(); +#endif test_display_modes(); test_shader_versions(); test_swapchain();