xref: /reactos/dll/directx/wine/d3d9/device.c (revision 4a7f3bdb)
1 /*
2  * IDirect3DDevice9 implementation
3  *
4  * Copyright 2002-2005 Jason Edmeades
5  * Copyright 2002-2005 Raphael Junqueira
6  * Copyright 2005 Oliver Stieber
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include "d3d9_private.h"
24 
25 #include <winuser.h>
26 
27 static void STDMETHODCALLTYPE d3d9_null_wined3d_object_destroyed(void *parent) {}
28 
29 const struct wined3d_parent_ops d3d9_null_wined3d_parent_ops =
30 {
31     d3d9_null_wined3d_object_destroyed,
32 };
33 
34 D3DFORMAT d3dformat_from_wined3dformat(enum wined3d_format_id format)
35 {
36     BYTE *c = (BYTE *)&format;
37 
38     /* Don't translate FOURCC formats */
39     if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;
40 
41     switch(format)
42     {
43         case WINED3DFMT_UNKNOWN: return D3DFMT_UNKNOWN;
44         case WINED3DFMT_B8G8R8_UNORM: return D3DFMT_R8G8B8;
45         case WINED3DFMT_B8G8R8A8_UNORM: return D3DFMT_A8R8G8B8;
46         case WINED3DFMT_B8G8R8X8_UNORM: return D3DFMT_X8R8G8B8;
47         case WINED3DFMT_B5G6R5_UNORM: return D3DFMT_R5G6B5;
48         case WINED3DFMT_B5G5R5X1_UNORM: return D3DFMT_X1R5G5B5;
49         case WINED3DFMT_B5G5R5A1_UNORM: return D3DFMT_A1R5G5B5;
50         case WINED3DFMT_B4G4R4A4_UNORM: return D3DFMT_A4R4G4B4;
51         case WINED3DFMT_B2G3R3_UNORM: return D3DFMT_R3G3B2;
52         case WINED3DFMT_A8_UNORM: return D3DFMT_A8;
53         case WINED3DFMT_B2G3R3A8_UNORM: return D3DFMT_A8R3G3B2;
54         case WINED3DFMT_B4G4R4X4_UNORM: return D3DFMT_X4R4G4B4;
55         case WINED3DFMT_R10G10B10A2_UNORM: return D3DFMT_A2B10G10R10;
56         case WINED3DFMT_R8G8B8A8_UNORM: return D3DFMT_A8B8G8R8;
57         case WINED3DFMT_R8G8B8X8_UNORM: return D3DFMT_X8B8G8R8;
58         case WINED3DFMT_R16G16_UNORM: return D3DFMT_G16R16;
59         case WINED3DFMT_B10G10R10A2_UNORM: return D3DFMT_A2R10G10B10;
60         case WINED3DFMT_R16G16B16A16_UNORM: return D3DFMT_A16B16G16R16;
61         case WINED3DFMT_P8_UINT_A8_UNORM: return D3DFMT_A8P8;
62         case WINED3DFMT_P8_UINT: return D3DFMT_P8;
63         case WINED3DFMT_L8_UNORM: return D3DFMT_L8;
64         case WINED3DFMT_L8A8_UNORM: return D3DFMT_A8L8;
65         case WINED3DFMT_L4A4_UNORM: return D3DFMT_A4L4;
66         case WINED3DFMT_R8G8_SNORM: return D3DFMT_V8U8;
67         case WINED3DFMT_R5G5_SNORM_L6_UNORM: return D3DFMT_L6V5U5;
68         case WINED3DFMT_R8G8_SNORM_L8X8_UNORM: return D3DFMT_X8L8V8U8;
69         case WINED3DFMT_R8G8B8A8_SNORM: return D3DFMT_Q8W8V8U8;
70         case WINED3DFMT_R16G16_SNORM: return D3DFMT_V16U16;
71         case WINED3DFMT_R10G10B10_SNORM_A2_UNORM: return D3DFMT_A2W10V10U10;
72         case WINED3DFMT_D16_LOCKABLE: return D3DFMT_D16_LOCKABLE;
73         case WINED3DFMT_D32_UNORM: return D3DFMT_D32;
74         case WINED3DFMT_S1_UINT_D15_UNORM: return D3DFMT_D15S1;
75         case WINED3DFMT_D24_UNORM_S8_UINT: return D3DFMT_D24S8;
76         case WINED3DFMT_X8D24_UNORM: return D3DFMT_D24X8;
77         case WINED3DFMT_S4X4_UINT_D24_UNORM: return D3DFMT_D24X4S4;
78         case WINED3DFMT_D16_UNORM: return D3DFMT_D16;
79         case WINED3DFMT_L16_UNORM: return D3DFMT_L16;
80         case WINED3DFMT_D32_FLOAT: return D3DFMT_D32F_LOCKABLE;
81         case WINED3DFMT_S8_UINT_D24_FLOAT: return D3DFMT_D24FS8;
82         case WINED3DFMT_R16_UINT: return D3DFMT_INDEX16;
83         case WINED3DFMT_R32_UINT: return D3DFMT_INDEX32;
84         case WINED3DFMT_R16G16B16A16_SNORM: return D3DFMT_Q16W16V16U16;
85         case WINED3DFMT_R16_FLOAT: return D3DFMT_R16F;
86         case WINED3DFMT_R16G16_FLOAT: return D3DFMT_G16R16F;
87         case WINED3DFMT_R16G16B16A16_FLOAT: return D3DFMT_A16B16G16R16F;
88         case WINED3DFMT_R32_FLOAT: return D3DFMT_R32F;
89         case WINED3DFMT_R32G32_FLOAT: return D3DFMT_G32R32F;
90         case WINED3DFMT_R32G32B32A32_FLOAT: return D3DFMT_A32B32G32R32F;
91         case WINED3DFMT_R8G8_SNORM_Cx: return D3DFMT_CxV8U8;
92         default:
93             FIXME("Unhandled wined3d format %#x.\n", format);
94             return D3DFMT_UNKNOWN;
95     }
96 }
97 
98 enum wined3d_format_id wined3dformat_from_d3dformat(D3DFORMAT format)
99 {
100     BYTE *c = (BYTE *)&format;
101 
102     /* Don't translate FOURCC formats */
103     if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;
104 
105     switch(format)
106     {
107         case D3DFMT_UNKNOWN: return WINED3DFMT_UNKNOWN;
108         case D3DFMT_R8G8B8: return WINED3DFMT_B8G8R8_UNORM;
109         case D3DFMT_A8R8G8B8: return WINED3DFMT_B8G8R8A8_UNORM;
110         case D3DFMT_X8R8G8B8: return WINED3DFMT_B8G8R8X8_UNORM;
111         case D3DFMT_R5G6B5: return WINED3DFMT_B5G6R5_UNORM;
112         case D3DFMT_X1R5G5B5: return WINED3DFMT_B5G5R5X1_UNORM;
113         case D3DFMT_A1R5G5B5: return WINED3DFMT_B5G5R5A1_UNORM;
114         case D3DFMT_A4R4G4B4: return WINED3DFMT_B4G4R4A4_UNORM;
115         case D3DFMT_R3G3B2: return WINED3DFMT_B2G3R3_UNORM;
116         case D3DFMT_A8: return WINED3DFMT_A8_UNORM;
117         case D3DFMT_A8R3G3B2: return WINED3DFMT_B2G3R3A8_UNORM;
118         case D3DFMT_X4R4G4B4: return WINED3DFMT_B4G4R4X4_UNORM;
119         case D3DFMT_A2B10G10R10: return WINED3DFMT_R10G10B10A2_UNORM;
120         case D3DFMT_A8B8G8R8: return WINED3DFMT_R8G8B8A8_UNORM;
121         case D3DFMT_X8B8G8R8: return WINED3DFMT_R8G8B8X8_UNORM;
122         case D3DFMT_G16R16: return WINED3DFMT_R16G16_UNORM;
123         case D3DFMT_A2R10G10B10: return WINED3DFMT_B10G10R10A2_UNORM;
124         case D3DFMT_A16B16G16R16: return WINED3DFMT_R16G16B16A16_UNORM;
125         case D3DFMT_A8P8: return WINED3DFMT_P8_UINT_A8_UNORM;
126         case D3DFMT_P8: return WINED3DFMT_P8_UINT;
127         case D3DFMT_L8: return WINED3DFMT_L8_UNORM;
128         case D3DFMT_A8L8: return WINED3DFMT_L8A8_UNORM;
129         case D3DFMT_A4L4: return WINED3DFMT_L4A4_UNORM;
130         case D3DFMT_V8U8: return WINED3DFMT_R8G8_SNORM;
131         case D3DFMT_L6V5U5: return WINED3DFMT_R5G5_SNORM_L6_UNORM;
132         case D3DFMT_X8L8V8U8: return WINED3DFMT_R8G8_SNORM_L8X8_UNORM;
133         case D3DFMT_Q8W8V8U8: return WINED3DFMT_R8G8B8A8_SNORM;
134         case D3DFMT_V16U16: return WINED3DFMT_R16G16_SNORM;
135         case D3DFMT_A2W10V10U10: return WINED3DFMT_R10G10B10_SNORM_A2_UNORM;
136         case D3DFMT_D16_LOCKABLE: return WINED3DFMT_D16_LOCKABLE;
137         case D3DFMT_D32: return WINED3DFMT_D32_UNORM;
138         case D3DFMT_D15S1: return WINED3DFMT_S1_UINT_D15_UNORM;
139         case D3DFMT_D24S8: return WINED3DFMT_D24_UNORM_S8_UINT;
140         case D3DFMT_D24X8: return WINED3DFMT_X8D24_UNORM;
141         case D3DFMT_D24X4S4: return WINED3DFMT_S4X4_UINT_D24_UNORM;
142         case D3DFMT_D16: return WINED3DFMT_D16_UNORM;
143         case D3DFMT_L16: return WINED3DFMT_L16_UNORM;
144         case D3DFMT_D32F_LOCKABLE: return WINED3DFMT_D32_FLOAT;
145         case D3DFMT_D24FS8: return WINED3DFMT_S8_UINT_D24_FLOAT;
146         case D3DFMT_INDEX16: return WINED3DFMT_R16_UINT;
147         case D3DFMT_INDEX32: return WINED3DFMT_R32_UINT;
148         case D3DFMT_Q16W16V16U16: return WINED3DFMT_R16G16B16A16_SNORM;
149         case D3DFMT_R16F: return WINED3DFMT_R16_FLOAT;
150         case D3DFMT_G16R16F: return WINED3DFMT_R16G16_FLOAT;
151         case D3DFMT_A16B16G16R16F: return WINED3DFMT_R16G16B16A16_FLOAT;
152         case D3DFMT_R32F: return WINED3DFMT_R32_FLOAT;
153         case D3DFMT_G32R32F: return WINED3DFMT_R32G32_FLOAT;
154         case D3DFMT_A32B32G32R32F: return WINED3DFMT_R32G32B32A32_FLOAT;
155         case D3DFMT_CxV8U8: return WINED3DFMT_R8G8_SNORM_Cx;
156         default:
157             FIXME("Unhandled D3DFORMAT %#x.\n", format);
158             return WINED3DFMT_UNKNOWN;
159     }
160 }
161 
162 static UINT vertex_count_from_primitive_count(D3DPRIMITIVETYPE primitive_type, UINT primitive_count)
163 {
164     switch (primitive_type)
165     {
166         case D3DPT_POINTLIST:
167             return primitive_count;
168 
169         case D3DPT_LINELIST:
170             return primitive_count * 2;
171 
172         case D3DPT_LINESTRIP:
173             return primitive_count + 1;
174 
175         case D3DPT_TRIANGLELIST:
176             return primitive_count * 3;
177 
178         case D3DPT_TRIANGLESTRIP:
179         case D3DPT_TRIANGLEFAN:
180             return primitive_count + 2;
181 
182         default:
183             FIXME("Unhandled primitive type %#x.\n", primitive_type);
184             return 0;
185     }
186 }
187 
188 void present_parameters_from_wined3d_swapchain_desc(D3DPRESENT_PARAMETERS *present_parameters,
189         const struct wined3d_swapchain_desc *swapchain_desc)
190 {
191     present_parameters->BackBufferWidth = swapchain_desc->backbuffer_width;
192     present_parameters->BackBufferHeight = swapchain_desc->backbuffer_height;
193     present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(swapchain_desc->backbuffer_format);
194     present_parameters->BackBufferCount = swapchain_desc->backbuffer_count;
195     present_parameters->MultiSampleType = swapchain_desc->multisample_type;
196     present_parameters->MultiSampleQuality = swapchain_desc->multisample_quality;
197     present_parameters->SwapEffect = swapchain_desc->swap_effect;
198     present_parameters->hDeviceWindow = swapchain_desc->device_window;
199     present_parameters->Windowed = swapchain_desc->windowed;
200     present_parameters->EnableAutoDepthStencil = swapchain_desc->enable_auto_depth_stencil;
201     present_parameters->AutoDepthStencilFormat
202             = d3dformat_from_wined3dformat(swapchain_desc->auto_depth_stencil_format);
203     present_parameters->Flags = swapchain_desc->flags & D3DPRESENTFLAGS_MASK;
204     present_parameters->FullScreen_RefreshRateInHz = swapchain_desc->refresh_rate;
205     present_parameters->PresentationInterval = swapchain_desc->swap_interval;
206 }
207 
208 static BOOL wined3d_swapchain_desc_from_present_parameters(struct wined3d_swapchain_desc *swapchain_desc,
209         const D3DPRESENT_PARAMETERS *present_parameters, BOOL extended)
210 {
211     D3DSWAPEFFECT highest_swapeffect = extended ? D3DSWAPEFFECT_FLIPEX : D3DSWAPEFFECT_COPY;
212     UINT highest_bb_count = extended ? 30 : 3;
213 
214     if (!present_parameters->SwapEffect || present_parameters->SwapEffect > highest_swapeffect)
215     {
216         WARN("Invalid swap effect %u passed.\n", present_parameters->SwapEffect);
217         return FALSE;
218     }
219     if (present_parameters->BackBufferCount > highest_bb_count
220             || (present_parameters->SwapEffect == D3DSWAPEFFECT_COPY
221             && present_parameters->BackBufferCount > 1))
222     {
223         WARN("Invalid backbuffer count %u.\n", present_parameters->BackBufferCount);
224         return FALSE;
225     }
226 
227     swapchain_desc->backbuffer_width = present_parameters->BackBufferWidth;
228     swapchain_desc->backbuffer_height = present_parameters->BackBufferHeight;
229     swapchain_desc->backbuffer_format = wined3dformat_from_d3dformat(present_parameters->BackBufferFormat);
230     swapchain_desc->backbuffer_count = max(1, present_parameters->BackBufferCount);
231     swapchain_desc->multisample_type = present_parameters->MultiSampleType;
232     swapchain_desc->multisample_quality = present_parameters->MultiSampleQuality;
233     swapchain_desc->swap_effect = present_parameters->SwapEffect;
234     swapchain_desc->device_window = present_parameters->hDeviceWindow;
235     swapchain_desc->windowed = present_parameters->Windowed;
236     swapchain_desc->enable_auto_depth_stencil = present_parameters->EnableAutoDepthStencil;
237     swapchain_desc->auto_depth_stencil_format
238             = wined3dformat_from_d3dformat(present_parameters->AutoDepthStencilFormat);
239     swapchain_desc->flags
240             = (present_parameters->Flags & D3DPRESENTFLAGS_MASK) | WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH;
241     swapchain_desc->refresh_rate = present_parameters->FullScreen_RefreshRateInHz;
242     swapchain_desc->swap_interval = present_parameters->PresentationInterval;
243     swapchain_desc->auto_restore_display_mode = TRUE;
244 
245     if (present_parameters->Flags & ~D3DPRESENTFLAGS_MASK)
246         FIXME("Unhandled flags %#x.\n", present_parameters->Flags & ~D3DPRESENTFLAGS_MASK);
247 
248     return TRUE;
249 }
250 
251 void d3dcaps_from_wined3dcaps(D3DCAPS9 *caps, const WINED3DCAPS *wined3d_caps)
252 {
253     static const DWORD ps_minor_version[] = {0, 4, 0, 0};
254     static const DWORD vs_minor_version[] = {0, 1, 0, 0};
255     static const DWORD texture_filter_caps =
256         D3DPTFILTERCAPS_MINFPOINT      | D3DPTFILTERCAPS_MINFLINEAR    | D3DPTFILTERCAPS_MINFANISOTROPIC |
257         D3DPTFILTERCAPS_MINFPYRAMIDALQUAD                              | D3DPTFILTERCAPS_MINFGAUSSIANQUAD|
258         D3DPTFILTERCAPS_MIPFPOINT      | D3DPTFILTERCAPS_MIPFLINEAR    | D3DPTFILTERCAPS_MAGFPOINT       |
259         D3DPTFILTERCAPS_MAGFLINEAR     |D3DPTFILTERCAPS_MAGFANISOTROPIC|D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD|
260         D3DPTFILTERCAPS_MAGFGAUSSIANQUAD;
261 
262     caps->DeviceType                        = (D3DDEVTYPE)wined3d_caps->DeviceType;
263     caps->AdapterOrdinal                    = wined3d_caps->AdapterOrdinal;
264     caps->Caps                              = wined3d_caps->Caps;
265     caps->Caps2                             = wined3d_caps->Caps2;
266     caps->Caps3                             = wined3d_caps->Caps3;
267     caps->PresentationIntervals             = wined3d_caps->PresentationIntervals;
268     caps->CursorCaps                        = wined3d_caps->CursorCaps;
269     caps->DevCaps                           = wined3d_caps->DevCaps;
270     caps->PrimitiveMiscCaps                 = wined3d_caps->PrimitiveMiscCaps;
271     caps->RasterCaps                        = wined3d_caps->RasterCaps;
272     caps->ZCmpCaps                          = wined3d_caps->ZCmpCaps;
273     caps->SrcBlendCaps                      = wined3d_caps->SrcBlendCaps;
274     caps->DestBlendCaps                     = wined3d_caps->DestBlendCaps;
275     caps->AlphaCmpCaps                      = wined3d_caps->AlphaCmpCaps;
276     caps->ShadeCaps                         = wined3d_caps->ShadeCaps;
277     caps->TextureCaps                       = wined3d_caps->TextureCaps;
278     caps->TextureFilterCaps                 = wined3d_caps->TextureFilterCaps;
279     caps->CubeTextureFilterCaps             = wined3d_caps->CubeTextureFilterCaps;
280     caps->VolumeTextureFilterCaps           = wined3d_caps->VolumeTextureFilterCaps;
281     caps->TextureAddressCaps                = wined3d_caps->TextureAddressCaps;
282     caps->VolumeTextureAddressCaps          = wined3d_caps->VolumeTextureAddressCaps;
283     caps->LineCaps                          = wined3d_caps->LineCaps;
284     caps->MaxTextureWidth                   = wined3d_caps->MaxTextureWidth;
285     caps->MaxTextureHeight                  = wined3d_caps->MaxTextureHeight;
286     caps->MaxVolumeExtent                   = wined3d_caps->MaxVolumeExtent;
287     caps->MaxTextureRepeat                  = wined3d_caps->MaxTextureRepeat;
288     caps->MaxTextureAspectRatio             = wined3d_caps->MaxTextureAspectRatio;
289     caps->MaxAnisotropy                     = wined3d_caps->MaxAnisotropy;
290     caps->MaxVertexW                        = wined3d_caps->MaxVertexW;
291     caps->GuardBandLeft                     = wined3d_caps->GuardBandLeft;
292     caps->GuardBandTop                      = wined3d_caps->GuardBandTop;
293     caps->GuardBandRight                    = wined3d_caps->GuardBandRight;
294     caps->GuardBandBottom                   = wined3d_caps->GuardBandBottom;
295     caps->ExtentsAdjust                     = wined3d_caps->ExtentsAdjust;
296     caps->StencilCaps                       = wined3d_caps->StencilCaps;
297     caps->FVFCaps                           = wined3d_caps->FVFCaps;
298     caps->TextureOpCaps                     = wined3d_caps->TextureOpCaps;
299     caps->MaxTextureBlendStages             = wined3d_caps->MaxTextureBlendStages;
300     caps->MaxSimultaneousTextures           = wined3d_caps->MaxSimultaneousTextures;
301     caps->VertexProcessingCaps              = wined3d_caps->VertexProcessingCaps;
302     caps->MaxActiveLights                   = wined3d_caps->MaxActiveLights;
303     caps->MaxUserClipPlanes                 = wined3d_caps->MaxUserClipPlanes;
304     caps->MaxVertexBlendMatrices            = wined3d_caps->MaxVertexBlendMatrices;
305     caps->MaxVertexBlendMatrixIndex         = wined3d_caps->MaxVertexBlendMatrixIndex;
306     caps->MaxPointSize                      = wined3d_caps->MaxPointSize;
307     caps->MaxPrimitiveCount                 = wined3d_caps->MaxPrimitiveCount;
308     caps->MaxVertexIndex                    = wined3d_caps->MaxVertexIndex;
309     caps->MaxStreams                        = wined3d_caps->MaxStreams;
310     caps->MaxStreamStride                   = wined3d_caps->MaxStreamStride;
311     caps->VertexShaderVersion               = wined3d_caps->VertexShaderVersion;
312     caps->MaxVertexShaderConst              = wined3d_caps->MaxVertexShaderConst;
313     caps->PixelShaderVersion                = wined3d_caps->PixelShaderVersion;
314     caps->PixelShader1xMaxValue             = wined3d_caps->PixelShader1xMaxValue;
315     caps->DevCaps2                          = wined3d_caps->DevCaps2;
316     caps->MaxNpatchTessellationLevel        = wined3d_caps->MaxNpatchTessellationLevel;
317     caps->MasterAdapterOrdinal              = wined3d_caps->MasterAdapterOrdinal;
318     caps->AdapterOrdinalInGroup             = wined3d_caps->AdapterOrdinalInGroup;
319     caps->NumberOfAdaptersInGroup           = wined3d_caps->NumberOfAdaptersInGroup;
320     caps->DeclTypes                         = wined3d_caps->DeclTypes;
321     caps->NumSimultaneousRTs                = wined3d_caps->NumSimultaneousRTs;
322     caps->StretchRectFilterCaps             = wined3d_caps->StretchRectFilterCaps;
323     caps->VS20Caps.Caps                     = wined3d_caps->VS20Caps.caps;
324     caps->VS20Caps.DynamicFlowControlDepth  = wined3d_caps->VS20Caps.dynamic_flow_control_depth;
325     caps->VS20Caps.NumTemps                 = wined3d_caps->VS20Caps.temp_count;
326     caps->VS20Caps.StaticFlowControlDepth   = wined3d_caps->VS20Caps.static_flow_control_depth;
327     caps->PS20Caps.Caps                     = wined3d_caps->PS20Caps.caps;
328     caps->PS20Caps.DynamicFlowControlDepth  = wined3d_caps->PS20Caps.dynamic_flow_control_depth;
329     caps->PS20Caps.NumTemps                 = wined3d_caps->PS20Caps.temp_count;
330     caps->PS20Caps.StaticFlowControlDepth   = wined3d_caps->PS20Caps.static_flow_control_depth;
331     caps->PS20Caps.NumInstructionSlots      = wined3d_caps->PS20Caps.instruction_slot_count;
332     caps->VertexTextureFilterCaps           = wined3d_caps->VertexTextureFilterCaps;
333     caps->MaxVShaderInstructionsExecuted    = wined3d_caps->MaxVShaderInstructionsExecuted;
334     caps->MaxPShaderInstructionsExecuted    = wined3d_caps->MaxPShaderInstructionsExecuted;
335     caps->MaxVertexShader30InstructionSlots = wined3d_caps->MaxVertexShader30InstructionSlots;
336     caps->MaxPixelShader30InstructionSlots  = wined3d_caps->MaxPixelShader30InstructionSlots;
337 
338     /* Some functionality is implemented in d3d9.dll, not wined3d.dll. Add the needed caps. */
339     caps->DevCaps2 |= D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES;
340 
341     /* Filter wined3d caps. */
342     caps->TextureFilterCaps &= texture_filter_caps;
343     caps->CubeTextureFilterCaps &= texture_filter_caps;
344     caps->VolumeTextureFilterCaps &= texture_filter_caps;
345 
346     caps->DevCaps &=
347         D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY |
348         D3DDEVCAPS_TLVERTEXVIDEOMEMORY | D3DDEVCAPS_TEXTURESYSTEMMEMORY| D3DDEVCAPS_TEXTUREVIDEOMEMORY   |
349         D3DDEVCAPS_DRAWPRIMTLVERTEX    | D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_TEXTURENONLOCALVIDMEM|
350         D3DDEVCAPS_DRAWPRIMITIVES2     | D3DDEVCAPS_SEPARATETEXTUREMEMORIES                              |
351         D3DDEVCAPS_DRAWPRIMITIVES2EX   | D3DDEVCAPS_HWTRANSFORMANDLIGHT| D3DDEVCAPS_CANBLTSYSTONONLOCAL  |
352         D3DDEVCAPS_HWRASTERIZATION     | D3DDEVCAPS_PUREDEVICE         | D3DDEVCAPS_QUINTICRTPATCHES     |
353         D3DDEVCAPS_RTPATCHES           | D3DDEVCAPS_RTPATCHHANDLEZERO  | D3DDEVCAPS_NPATCHES;
354 
355     caps->ShadeCaps &=
356         D3DPSHADECAPS_COLORGOURAUDRGB  | D3DPSHADECAPS_SPECULARGOURAUDRGB |
357         D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_FOGGOURAUD;
358 
359     caps->RasterCaps &=
360         D3DPRASTERCAPS_DITHER          | D3DPRASTERCAPS_ZTEST          | D3DPRASTERCAPS_FOGVERTEX        |
361         D3DPRASTERCAPS_FOGTABLE        | D3DPRASTERCAPS_MIPMAPLODBIAS  | D3DPRASTERCAPS_ZBUFFERLESSHSR   |
362         D3DPRASTERCAPS_FOGRANGE        | D3DPRASTERCAPS_ANISOTROPY     | D3DPRASTERCAPS_WBUFFER          |
363         D3DPRASTERCAPS_WFOG            | D3DPRASTERCAPS_ZFOG           | D3DPRASTERCAPS_COLORPERSPECTIVE |
364         D3DPRASTERCAPS_SCISSORTEST     | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS                              |
365         D3DPRASTERCAPS_DEPTHBIAS       | D3DPRASTERCAPS_MULTISAMPLE_TOGGLE;
366 
367     caps->DevCaps2 &=
368         D3DDEVCAPS2_STREAMOFFSET       | D3DDEVCAPS2_DMAPNPATCH        | D3DDEVCAPS2_ADAPTIVETESSRTPATCH |
369         D3DDEVCAPS2_ADAPTIVETESSNPATCH | D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES                       |
370         D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH| D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;
371 
372     caps->Caps2 &=
373         D3DCAPS2_FULLSCREENGAMMA       | D3DCAPS2_CANCALIBRATEGAMMA    | D3DCAPS2_RESERVED               |
374         D3DCAPS2_CANMANAGERESOURCE     | D3DCAPS2_DYNAMICTEXTURES      | D3DCAPS2_CANAUTOGENMIPMAP;
375 
376     caps->VertexProcessingCaps &=
377         D3DVTXPCAPS_TEXGEN             | D3DVTXPCAPS_MATERIALSOURCE7   | D3DVTXPCAPS_DIRECTIONALLIGHTS   |
378         D3DVTXPCAPS_POSITIONALLIGHTS   | D3DVTXPCAPS_LOCALVIEWER       | D3DVTXPCAPS_TWEENING            |
379         D3DVTXPCAPS_TEXGEN_SPHEREMAP   | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER;
380 
381     caps->TextureCaps &=
382         D3DPTEXTURECAPS_PERSPECTIVE    | D3DPTEXTURECAPS_POW2          | D3DPTEXTURECAPS_ALPHA           |
383         D3DPTEXTURECAPS_SQUAREONLY     | D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE                        |
384         D3DPTEXTURECAPS_ALPHAPALETTE   | D3DPTEXTURECAPS_NONPOW2CONDITIONAL                              |
385         D3DPTEXTURECAPS_PROJECTED      | D3DPTEXTURECAPS_CUBEMAP       | D3DPTEXTURECAPS_VOLUMEMAP       |
386         D3DPTEXTURECAPS_MIPMAP         | D3DPTEXTURECAPS_MIPVOLUMEMAP  | D3DPTEXTURECAPS_MIPCUBEMAP      |
387         D3DPTEXTURECAPS_CUBEMAP_POW2   | D3DPTEXTURECAPS_VOLUMEMAP_POW2| D3DPTEXTURECAPS_NOPROJECTEDBUMPENV;
388 
389     caps->MaxVertexShaderConst = min(D3D9_MAX_VERTEX_SHADER_CONSTANTF, caps->MaxVertexShaderConst);
390     caps->NumSimultaneousRTs = min(D3D9_MAX_SIMULTANEOUS_RENDERTARGETS, caps->NumSimultaneousRTs);
391 
392     if (caps->PixelShaderVersion > 3)
393     {
394         caps->PixelShaderVersion = D3DPS_VERSION(3, 0);
395     }
396     else
397     {
398         DWORD major = caps->PixelShaderVersion;
399         caps->PixelShaderVersion = D3DPS_VERSION(major, ps_minor_version[major]);
400     }
401 
402     if (caps->VertexShaderVersion > 3)
403     {
404         caps->VertexShaderVersion = D3DVS_VERSION(3, 0);
405     }
406     else
407     {
408         DWORD major = caps->VertexShaderVersion;
409         caps->VertexShaderVersion = D3DVS_VERSION(major, vs_minor_version[major]);
410     }
411 }
412 
413 static HRESULT WINAPI d3d9_device_QueryInterface(IDirect3DDevice9Ex *iface, REFIID riid, void **out)
414 {
415     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
416 
417     if (IsEqualGUID(riid, &IID_IDirect3DDevice9)
418             || IsEqualGUID(riid, &IID_IUnknown))
419     {
420         IDirect3DDevice9Ex_AddRef(iface);
421         *out = iface;
422         return S_OK;
423     }
424 
425     if (IsEqualGUID(riid, &IID_IDirect3DDevice9Ex))
426     {
427         struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
428 
429         /* Find out if the creating d3d9 interface was created with Direct3DCreate9Ex.
430          * It doesn't matter with which function the device was created. */
431         if (!device->d3d_parent->extended)
432         {
433             WARN("IDirect3D9 instance wasn't created with CreateDirect3D9Ex, returning E_NOINTERFACE.\n");
434             *out = NULL;
435             return E_NOINTERFACE;
436         }
437 
438         IDirect3DDevice9Ex_AddRef(iface);
439         *out = iface;
440         return S_OK;
441     }
442 
443     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
444 
445     *out = NULL;
446     return E_NOINTERFACE;
447 }
448 
449 static ULONG WINAPI d3d9_device_AddRef(IDirect3DDevice9Ex *iface)
450 {
451     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
452     ULONG refcount = InterlockedIncrement(&device->refcount);
453 
454     TRACE("%p increasing refcount to %u.\n", iface, refcount);
455 
456     return refcount;
457 }
458 
459 static ULONG WINAPI DECLSPEC_HOTPATCH d3d9_device_Release(IDirect3DDevice9Ex *iface)
460 {
461     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
462     ULONG refcount;
463 
464     if (device->in_destruction)
465         return 0;
466 
467     refcount = InterlockedDecrement(&device->refcount);
468 
469     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
470 
471     if (!refcount)
472     {
473         unsigned i;
474         device->in_destruction = TRUE;
475 
476         wined3d_mutex_lock();
477         for (i = 0; i < device->fvf_decl_count; ++i)
478         {
479             wined3d_vertex_declaration_decref(device->fvf_decls[i].decl);
480         }
481         HeapFree(GetProcessHeap(), 0, device->fvf_decls);
482 
483         if (device->vertex_buffer)
484             wined3d_buffer_decref(device->vertex_buffer);
485         if (device->index_buffer)
486             wined3d_buffer_decref(device->index_buffer);
487 
488         HeapFree(GetProcessHeap(), 0, device->implicit_swapchains);
489 
490         wined3d_device_uninit_3d(device->wined3d_device);
491         wined3d_device_release_focus_window(device->wined3d_device);
492         wined3d_device_decref(device->wined3d_device);
493         wined3d_mutex_unlock();
494 
495         IDirect3D9Ex_Release(&device->d3d_parent->IDirect3D9Ex_iface);
496 
497         HeapFree(GetProcessHeap(), 0, device);
498     }
499 
500     return refcount;
501 }
502 
503 static HRESULT WINAPI d3d9_device_TestCooperativeLevel(IDirect3DDevice9Ex *iface)
504 {
505     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
506 
507     TRACE("iface %p.\n", iface);
508 
509     TRACE("device state: %#x.\n", device->device_state);
510 
511     if (device->d3d_parent->extended)
512         return D3D_OK;
513 
514     switch (device->device_state)
515     {
516         default:
517         case D3D9_DEVICE_STATE_OK:
518             return D3D_OK;
519         case D3D9_DEVICE_STATE_LOST:
520             return D3DERR_DEVICELOST;
521         case D3D9_DEVICE_STATE_NOT_RESET:
522             return D3DERR_DEVICENOTRESET;
523     }
524 }
525 
526 static UINT WINAPI d3d9_device_GetAvailableTextureMem(IDirect3DDevice9Ex *iface)
527 {
528     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
529     UINT ret;
530 
531     TRACE("iface %p.\n", iface);
532 
533     wined3d_mutex_lock();
534     ret = wined3d_device_get_available_texture_mem(device->wined3d_device);
535     wined3d_mutex_unlock();
536 
537     return ret;
538 }
539 
540 static HRESULT WINAPI d3d9_device_EvictManagedResources(IDirect3DDevice9Ex *iface)
541 {
542     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
543 
544     TRACE("iface %p.\n", iface);
545 
546     wined3d_mutex_lock();
547     wined3d_device_evict_managed_resources(device->wined3d_device);
548     wined3d_mutex_unlock();
549 
550     return D3D_OK;
551 }
552 
553 static HRESULT WINAPI d3d9_device_GetDirect3D(IDirect3DDevice9Ex *iface, IDirect3D9 **d3d9)
554 {
555     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
556 
557     TRACE("iface %p, d3d9 %p.\n", iface, d3d9);
558 
559     if (!d3d9)
560         return D3DERR_INVALIDCALL;
561 
562     return IDirect3D9Ex_QueryInterface(&device->d3d_parent->IDirect3D9Ex_iface, &IID_IDirect3D9, (void **)d3d9);
563 }
564 
565 static HRESULT WINAPI d3d9_device_GetDeviceCaps(IDirect3DDevice9Ex *iface, D3DCAPS9 *caps)
566 {
567     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
568     WINED3DCAPS wined3d_caps;
569     HRESULT hr;
570 
571     TRACE("iface %p, caps %p.\n", iface, caps);
572 
573     if (!caps)
574         return D3DERR_INVALIDCALL;
575 
576     memset(caps, 0, sizeof(*caps));
577 
578     wined3d_mutex_lock();
579     hr = wined3d_device_get_device_caps(device->wined3d_device, &wined3d_caps);
580     wined3d_mutex_unlock();
581 
582     d3dcaps_from_wined3dcaps(caps, &wined3d_caps);
583 
584     return hr;
585 }
586 
587 static HRESULT WINAPI d3d9_device_GetDisplayMode(IDirect3DDevice9Ex *iface, UINT swapchain, D3DDISPLAYMODE *mode)
588 {
589     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
590     struct wined3d_display_mode wined3d_mode;
591     HRESULT hr;
592 
593     TRACE("iface %p, swapchain %u, mode %p.\n", iface, swapchain, mode);
594 
595     wined3d_mutex_lock();
596     hr = wined3d_device_get_display_mode(device->wined3d_device, swapchain, &wined3d_mode, NULL);
597     wined3d_mutex_unlock();
598 
599     if (SUCCEEDED(hr))
600     {
601         mode->Width = wined3d_mode.width;
602         mode->Height = wined3d_mode.height;
603         mode->RefreshRate = wined3d_mode.refresh_rate;
604         mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
605     }
606 
607     return hr;
608 }
609 
610 static HRESULT WINAPI d3d9_device_GetCreationParameters(IDirect3DDevice9Ex *iface,
611         D3DDEVICE_CREATION_PARAMETERS *parameters)
612 {
613     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
614 
615     TRACE("iface %p, parameters %p.\n", iface, parameters);
616 
617     wined3d_mutex_lock();
618     wined3d_device_get_creation_parameters(device->wined3d_device,
619             (struct wined3d_device_creation_parameters *)parameters);
620     wined3d_mutex_unlock();
621 
622     return D3D_OK;
623 }
624 
625 static HRESULT WINAPI d3d9_device_SetCursorProperties(IDirect3DDevice9Ex *iface,
626         UINT hotspot_x, UINT hotspot_y, IDirect3DSurface9 *bitmap)
627 {
628     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
629     struct d3d9_surface *bitmap_impl = unsafe_impl_from_IDirect3DSurface9(bitmap);
630     HRESULT hr;
631 
632     TRACE("iface %p, hotspot_x %u, hotspot_y %u, bitmap %p.\n",
633             iface, hotspot_x, hotspot_y, bitmap);
634 
635     if (!bitmap)
636     {
637         WARN("No cursor bitmap, returning D3DERR_INVALIDCALL.\n");
638         return D3DERR_INVALIDCALL;
639     }
640 
641     wined3d_mutex_lock();
642     hr = wined3d_device_set_cursor_properties(device->wined3d_device,
643             hotspot_x, hotspot_y, bitmap_impl->wined3d_texture, bitmap_impl->sub_resource_idx);
644     wined3d_mutex_unlock();
645 
646     return hr;
647 }
648 
649 static void WINAPI d3d9_device_SetCursorPosition(IDirect3DDevice9Ex *iface, int x, int y, DWORD flags)
650 {
651     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
652 
653     TRACE("iface %p, x %u, y %u, flags %#x.\n", iface, x, y, flags);
654 
655     wined3d_mutex_lock();
656     wined3d_device_set_cursor_position(device->wined3d_device, x, y, flags);
657     wined3d_mutex_unlock();
658 }
659 
660 static BOOL WINAPI d3d9_device_ShowCursor(IDirect3DDevice9Ex *iface, BOOL show)
661 {
662     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
663     BOOL ret;
664 
665     TRACE("iface %p, show %#x.\n", iface, show);
666 
667     wined3d_mutex_lock();
668     ret = wined3d_device_show_cursor(device->wined3d_device, show);
669     wined3d_mutex_unlock();
670 
671     return ret;
672 }
673 
674 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_CreateAdditionalSwapChain(IDirect3DDevice9Ex *iface,
675         D3DPRESENT_PARAMETERS *present_parameters, IDirect3DSwapChain9 **swapchain)
676 {
677     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
678     struct wined3d_swapchain_desc desc;
679     struct d3d9_swapchain *object;
680     UINT i, count;
681     HRESULT hr;
682 
683     TRACE("iface %p, present_parameters %p, swapchain %p.\n",
684             iface, present_parameters, swapchain);
685 
686     if (!present_parameters->Windowed)
687     {
688         WARN("Trying to create an additional fullscreen swapchain, returning D3DERR_INVALIDCALL.\n");
689         return D3DERR_INVALIDCALL;
690     }
691 
692     wined3d_mutex_lock();
693     count = wined3d_device_get_swapchain_count(device->wined3d_device);
694     for (i = 0; i < count; ++i)
695     {
696         struct wined3d_swapchain *wined3d_swapchain;
697 
698         wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, i);
699         wined3d_swapchain_get_desc(wined3d_swapchain, &desc);
700 
701         if (!desc.windowed)
702         {
703             wined3d_mutex_unlock();
704             WARN("Trying to create an additional swapchain in fullscreen mode, returning D3DERR_INVALIDCALL.\n");
705             return D3DERR_INVALIDCALL;
706         }
707     }
708     wined3d_mutex_unlock();
709 
710     if (!wined3d_swapchain_desc_from_present_parameters(&desc, present_parameters,
711             device->d3d_parent->extended))
712         return D3DERR_INVALIDCALL;
713     if (SUCCEEDED(hr = d3d9_swapchain_create(device, &desc, &object)))
714         *swapchain = (IDirect3DSwapChain9 *)&object->IDirect3DSwapChain9Ex_iface;
715     present_parameters_from_wined3d_swapchain_desc(present_parameters, &desc);
716 
717     return hr;
718 }
719 
720 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_GetSwapChain(IDirect3DDevice9Ex *iface,
721         UINT swapchain_idx, IDirect3DSwapChain9 **swapchain)
722 {
723     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
724     HRESULT hr;
725 
726     TRACE("iface %p, swapchain_idx %u, swapchain %p.\n", iface, swapchain_idx, swapchain);
727 
728     wined3d_mutex_lock();
729     if (swapchain_idx < device->implicit_swapchain_count)
730     {
731         *swapchain = (IDirect3DSwapChain9 *)&device->implicit_swapchains[swapchain_idx]->IDirect3DSwapChain9Ex_iface;
732         IDirect3DSwapChain9Ex_AddRef(*swapchain);
733         hr = D3D_OK;
734     }
735     else
736     {
737         *swapchain = NULL;
738         hr = D3DERR_INVALIDCALL;
739     }
740     wined3d_mutex_unlock();
741 
742     return hr;
743 }
744 
745 static UINT WINAPI d3d9_device_GetNumberOfSwapChains(IDirect3DDevice9Ex *iface)
746 {
747     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
748     UINT count;
749 
750     TRACE("iface %p.\n", iface);
751 
752     wined3d_mutex_lock();
753     count = wined3d_device_get_swapchain_count(device->wined3d_device);
754     wined3d_mutex_unlock();
755 
756     return count;
757 }
758 
759 static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource)
760 {
761     struct wined3d_resource_desc desc;
762     IDirect3DBaseTexture9 *texture;
763     struct d3d9_surface *surface;
764     IUnknown *parent;
765 
766     wined3d_resource_get_desc(resource, &desc);
767     if (desc.pool != WINED3D_POOL_DEFAULT)
768         return D3D_OK;
769 
770     if (desc.resource_type != WINED3D_RTYPE_TEXTURE_2D)
771     {
772         WARN("Resource %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", resource);
773         return D3DERR_INVALIDCALL;
774     }
775 
776     parent = wined3d_resource_get_parent(resource);
777     if (parent && SUCCEEDED(IUnknown_QueryInterface(parent, &IID_IDirect3DBaseTexture9, (void **)&texture)))
778     {
779         IDirect3DBaseTexture9_Release(texture);
780         WARN("Texture %p (resource %p) in pool D3DPOOL_DEFAULT blocks the Reset call.\n", texture, resource);
781         return D3DERR_INVALIDCALL;
782     }
783 
784     surface = wined3d_texture_get_sub_resource_parent(wined3d_texture_from_resource(resource), 0);
785     if (!surface->resource.refcount)
786         return D3D_OK;
787 
788     WARN("Surface %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", surface);
789     return D3DERR_INVALIDCALL;
790 }
791 
792 static HRESULT d3d9_device_get_swapchains(struct d3d9_device *device)
793 {
794     UINT i, new_swapchain_count = wined3d_device_get_swapchain_count(device->wined3d_device);
795     struct wined3d_swapchain *wined3d_swapchain;
796 
797     if (!(device->implicit_swapchains = HeapAlloc(GetProcessHeap(), 0,
798             new_swapchain_count * sizeof(*device->implicit_swapchains))))
799         return E_OUTOFMEMORY;
800 
801     for (i = 0; i < new_swapchain_count; ++i)
802     {
803         wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, i);
804         device->implicit_swapchains[i] = wined3d_swapchain_get_parent(wined3d_swapchain);
805     }
806     device->implicit_swapchain_count = new_swapchain_count;
807 
808     return D3D_OK;
809 }
810 
811 static HRESULT d3d9_device_reset(struct d3d9_device *device,
812         D3DPRESENT_PARAMETERS *present_parameters, D3DDISPLAYMODEEX *mode)
813 {
814     BOOL extended = device->d3d_parent->extended;
815     struct wined3d_swapchain_desc swapchain_desc;
816     struct wined3d_display_mode wined3d_mode;
817     HRESULT hr;
818 
819 
820     if (!extended && device->device_state == D3D9_DEVICE_STATE_LOST)
821     {
822         WARN("App not active, returning D3DERR_DEVICELOST.\n");
823         return D3DERR_DEVICELOST;
824     }
825 
826     if (mode)
827     {
828         wined3d_mode.width = mode->Width;
829         wined3d_mode.height = mode->Height;
830         wined3d_mode.refresh_rate = mode->RefreshRate;
831         wined3d_mode.format_id = wined3dformat_from_d3dformat(mode->Format);
832         wined3d_mode.scanline_ordering = mode->ScanLineOrdering;
833     }
834 
835     if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, present_parameters, extended))
836         return D3DERR_INVALIDCALL;
837 
838     wined3d_mutex_lock();
839 
840     if (device->vertex_buffer)
841     {
842         wined3d_buffer_decref(device->vertex_buffer);
843         device->vertex_buffer = NULL;
844         device->vertex_buffer_size = 0;
845     }
846 
847     if (device->index_buffer)
848     {
849         wined3d_buffer_decref(device->index_buffer);
850         device->index_buffer = NULL;
851         device->index_buffer_size = 0;
852     }
853 
854     if (SUCCEEDED(hr = wined3d_device_reset(device->wined3d_device, &swapchain_desc,
855             mode ? &wined3d_mode : NULL, reset_enum_callback, !extended)))
856     {
857         HeapFree(GetProcessHeap(), 0, device->implicit_swapchains);
858 
859         if (!extended)
860         {
861             wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_ZENABLE,
862                     !!swapchain_desc.enable_auto_depth_stencil);
863         }
864 
865         if (FAILED(hr = d3d9_device_get_swapchains(device)))
866         {
867             device->device_state = D3D9_DEVICE_STATE_NOT_RESET;
868         }
869         else
870         {
871             wined3d_swapchain_get_desc(device->implicit_swapchains[0]->wined3d_swapchain, &swapchain_desc);
872             present_parameters->BackBufferWidth = swapchain_desc.backbuffer_width;
873             present_parameters->BackBufferHeight = swapchain_desc.backbuffer_height;
874             present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(swapchain_desc.backbuffer_format);
875             present_parameters->BackBufferCount = swapchain_desc.backbuffer_count;
876 
877             device->device_state = D3D9_DEVICE_STATE_OK;
878         }
879     }
880     else if (!extended)
881     {
882         device->device_state = D3D9_DEVICE_STATE_NOT_RESET;
883     }
884 
885     wined3d_mutex_unlock();
886 
887     return hr;
888 }
889 
890 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_Reset(IDirect3DDevice9Ex *iface,
891         D3DPRESENT_PARAMETERS *present_parameters)
892 {
893     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
894 
895     TRACE("iface %p, present_parameters %p.\n", iface, present_parameters);
896 
897     return d3d9_device_reset(device, present_parameters, NULL);
898 }
899 
900 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_Present(IDirect3DDevice9Ex *iface,
901         const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
902 {
903     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
904     UINT i;
905     HRESULT hr;
906 
907     TRACE("iface %p, src_rect %p, dst_rect %p, dst_window_override %p, dirty_region %p.\n",
908             iface, src_rect, dst_rect, dst_window_override, dirty_region);
909 
910     if (device->device_state != D3D9_DEVICE_STATE_OK)
911         return device->d3d_parent->extended ? S_PRESENT_OCCLUDED : D3DERR_DEVICELOST;
912 
913     if (dirty_region)
914         FIXME("Ignoring dirty_region %p.\n", dirty_region);
915 
916     wined3d_mutex_lock();
917     for (i = 0; i < device->implicit_swapchain_count; ++i)
918     {
919         if (FAILED(hr = wined3d_swapchain_present(device->implicit_swapchains[i]->wined3d_swapchain,
920                 src_rect, dst_rect, dst_window_override, 0)))
921         {
922             wined3d_mutex_unlock();
923             return hr;
924         }
925     }
926     wined3d_mutex_unlock();
927 
928     return D3D_OK;
929 }
930 
931 static HRESULT WINAPI d3d9_device_GetBackBuffer(IDirect3DDevice9Ex *iface, UINT swapchain,
932         UINT backbuffer_idx, D3DBACKBUFFER_TYPE backbuffer_type, IDirect3DSurface9 **backbuffer)
933 {
934     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
935     HRESULT hr;
936 
937     TRACE("iface %p, swapchain %u, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
938             iface, swapchain, backbuffer_idx, backbuffer_type, backbuffer);
939 
940     /* backbuffer_type is ignored by native. */
941 
942     /* No need to check for backbuffer == NULL, Windows crashes in that case. */
943     *backbuffer = NULL;
944 
945     wined3d_mutex_lock();
946     if (swapchain >= device->implicit_swapchain_count)
947     {
948         wined3d_mutex_unlock();
949         WARN("Swapchain index %u is out of range, returning D3DERR_INVALIDCALL.\n", swapchain);
950         return D3DERR_INVALIDCALL;
951     }
952 
953     hr = IDirect3DSwapChain9Ex_GetBackBuffer(&device->implicit_swapchains[swapchain]->IDirect3DSwapChain9Ex_iface,
954             backbuffer_idx, backbuffer_type, backbuffer);
955     wined3d_mutex_unlock();
956 
957     return hr;
958 }
959 
960 static HRESULT WINAPI d3d9_device_GetRasterStatus(IDirect3DDevice9Ex *iface,
961         UINT swapchain, D3DRASTER_STATUS *raster_status)
962 {
963     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
964     HRESULT hr;
965 
966     TRACE("iface %p, swapchain %u, raster_status %p.\n", iface, swapchain, raster_status);
967 
968     wined3d_mutex_lock();
969     hr = wined3d_device_get_raster_status(device->wined3d_device,
970             swapchain, (struct wined3d_raster_status *)raster_status);
971     wined3d_mutex_unlock();
972 
973     return hr;
974 }
975 
976 static HRESULT WINAPI d3d9_device_SetDialogBoxMode(IDirect3DDevice9Ex *iface, BOOL enable)
977 {
978     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
979     HRESULT hr;
980 
981     TRACE("iface %p, enable %#x.\n", iface, enable);
982 
983     wined3d_mutex_lock();
984     hr = wined3d_device_set_dialog_box_mode(device->wined3d_device, enable);
985     wined3d_mutex_unlock();
986 
987     return hr;
988 }
989 
990 static void WINAPI d3d9_device_SetGammaRamp(IDirect3DDevice9Ex *iface,
991         UINT swapchain, DWORD flags, const D3DGAMMARAMP *ramp)
992 {
993     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
994 
995     TRACE("iface %p, swapchain %u, flags %#x, ramp %p.\n", iface, swapchain, flags, ramp);
996 
997     /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
998     wined3d_mutex_lock();
999     wined3d_device_set_gamma_ramp(device->wined3d_device, swapchain, flags, (const struct wined3d_gamma_ramp *)ramp);
1000     wined3d_mutex_unlock();
1001 }
1002 
1003 static void WINAPI d3d9_device_GetGammaRamp(IDirect3DDevice9Ex *iface, UINT swapchain, D3DGAMMARAMP *ramp)
1004 {
1005     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1006 
1007     TRACE("iface %p, swapchain %u, ramp %p.\n", iface, swapchain, ramp);
1008 
1009     /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
1010     wined3d_mutex_lock();
1011     wined3d_device_get_gamma_ramp(device->wined3d_device, swapchain, (struct wined3d_gamma_ramp *)ramp);
1012     wined3d_mutex_unlock();
1013 }
1014 
1015 static HRESULT WINAPI d3d9_device_CreateTexture(IDirect3DDevice9Ex *iface,
1016         UINT width, UINT height, UINT levels, DWORD usage, D3DFORMAT format,
1017         D3DPOOL pool, IDirect3DTexture9 **texture, HANDLE *shared_handle)
1018 {
1019     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1020     struct d3d9_texture *object;
1021     BOOL set_mem = FALSE;
1022     HRESULT hr;
1023 
1024     TRACE("iface %p, width %u, height %u, levels %u, usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
1025             iface, width, height, levels, usage, format, pool, texture, shared_handle);
1026 
1027     *texture = NULL;
1028     if (shared_handle)
1029     {
1030         if (!device->d3d_parent->extended)
1031         {
1032             WARN("Trying to create a shared or user memory texture on a non-ex device.\n");
1033             return E_NOTIMPL;
1034         }
1035 
1036         if (pool == D3DPOOL_SYSTEMMEM)
1037         {
1038             if (levels != 1)
1039                 return D3DERR_INVALIDCALL;
1040             set_mem = TRUE;
1041         }
1042         else
1043         {
1044             if (pool != D3DPOOL_DEFAULT)
1045             {
1046                 WARN("Trying to create a shared texture in pool %#x.\n", pool);
1047                 return D3DERR_INVALIDCALL;
1048             }
1049             FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1050         }
1051     }
1052 
1053     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1054     if (!object)
1055         return D3DERR_OUTOFVIDEOMEMORY;
1056 
1057     hr = texture_init(object, device, width, height, levels, usage, format, pool);
1058     if (FAILED(hr))
1059     {
1060         WARN("Failed to initialize texture, hr %#x.\n", hr);
1061         HeapFree(GetProcessHeap(), 0, object);
1062         return hr;
1063     }
1064 
1065     if (set_mem)
1066         wined3d_texture_update_desc(object->wined3d_texture, width, height,
1067                 wined3dformat_from_d3dformat(format), WINED3D_MULTISAMPLE_NONE, 0,
1068                 *shared_handle, 0);
1069 
1070     TRACE("Created texture %p.\n", object);
1071     *texture = (IDirect3DTexture9 *)&object->IDirect3DBaseTexture9_iface;
1072 
1073     return D3D_OK;
1074 }
1075 
1076 static HRESULT WINAPI d3d9_device_CreateVolumeTexture(IDirect3DDevice9Ex *iface,
1077         UINT width, UINT height, UINT depth, UINT levels, DWORD usage, D3DFORMAT format,
1078         D3DPOOL pool, IDirect3DVolumeTexture9 **texture, HANDLE *shared_handle)
1079 {
1080     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1081     struct d3d9_texture *object;
1082     HRESULT hr;
1083 
1084     TRACE("iface %p, width %u, height %u, depth %u, levels %u, "
1085             "usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
1086             iface, width, height, depth, levels,
1087             usage, format, pool, texture, shared_handle);
1088 
1089     *texture = NULL;
1090     if (shared_handle)
1091     {
1092         if (!device->d3d_parent->extended)
1093         {
1094             WARN("Trying to create a shared volume texture on a non-ex device.\n");
1095             return E_NOTIMPL;
1096         }
1097 
1098         if (pool != D3DPOOL_DEFAULT)
1099         {
1100             WARN("Trying to create a shared volume texture in pool %#x.\n", pool);
1101             return D3DERR_INVALIDCALL;
1102         }
1103         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1104     }
1105 
1106     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1107     if (!object)
1108         return D3DERR_OUTOFVIDEOMEMORY;
1109 
1110     hr = volumetexture_init(object, device, width, height, depth, levels, usage, format, pool);
1111     if (FAILED(hr))
1112     {
1113         WARN("Failed to initialize volume texture, hr %#x.\n", hr);
1114         HeapFree(GetProcessHeap(), 0, object);
1115         return hr;
1116     }
1117 
1118     TRACE("Created volume texture %p.\n", object);
1119     *texture = (IDirect3DVolumeTexture9 *)&object->IDirect3DBaseTexture9_iface;
1120 
1121     return D3D_OK;
1122 }
1123 
1124 static HRESULT WINAPI d3d9_device_CreateCubeTexture(IDirect3DDevice9Ex *iface,
1125         UINT edge_length, UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool,
1126         IDirect3DCubeTexture9 **texture, HANDLE *shared_handle)
1127 {
1128     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1129     struct d3d9_texture *object;
1130     HRESULT hr;
1131 
1132     TRACE("iface %p, edge_length %u, levels %u, usage %#x, format %#x, pool %#x, texture %p, shared_handle %p.\n",
1133             iface, edge_length, levels, usage, format, pool, texture, shared_handle);
1134 
1135     *texture = NULL;
1136     if (shared_handle)
1137     {
1138         if (!device->d3d_parent->extended)
1139         {
1140             WARN("Trying to create a shared cube texture on a non-ex device.\n");
1141             return E_NOTIMPL;
1142         }
1143 
1144         if (pool != D3DPOOL_DEFAULT)
1145         {
1146             WARN("Trying to create a shared cube texture in pool %#x.\n", pool);
1147             return D3DERR_INVALIDCALL;
1148         }
1149         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1150     }
1151 
1152     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1153     if (!object)
1154         return D3DERR_OUTOFVIDEOMEMORY;
1155 
1156     hr = cubetexture_init(object, device, edge_length, levels, usage, format, pool);
1157     if (FAILED(hr))
1158     {
1159         WARN("Failed to initialize cube texture, hr %#x.\n", hr);
1160         HeapFree(GetProcessHeap(), 0, object);
1161         return hr;
1162     }
1163 
1164     TRACE("Created cube texture %p.\n", object);
1165     *texture = (IDirect3DCubeTexture9 *)&object->IDirect3DBaseTexture9_iface;
1166 
1167     return D3D_OK;
1168 }
1169 
1170 static HRESULT WINAPI d3d9_device_CreateVertexBuffer(IDirect3DDevice9Ex *iface, UINT size,
1171         DWORD usage, DWORD fvf, D3DPOOL pool, IDirect3DVertexBuffer9 **buffer,
1172         HANDLE *shared_handle)
1173 {
1174     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1175     struct d3d9_vertexbuffer *object;
1176     HRESULT hr;
1177 
1178     TRACE("iface %p, size %u, usage %#x, fvf %#x, pool %#x, buffer %p, shared_handle %p.\n",
1179             iface, size, usage, fvf, pool, buffer, shared_handle);
1180 
1181     if (shared_handle)
1182     {
1183         if (!device->d3d_parent->extended)
1184         {
1185             WARN("Trying to create a shared vertex buffer on a non-ex device.\n");
1186             return E_NOTIMPL;
1187         }
1188 
1189         if (pool != D3DPOOL_DEFAULT)
1190         {
1191             WARN("Trying to create a shared vertex buffer in pool %#x.\n", pool);
1192             return D3DERR_NOTAVAILABLE;
1193         }
1194         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1195     }
1196 
1197     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1198     if (!object)
1199         return D3DERR_OUTOFVIDEOMEMORY;
1200 
1201     hr = vertexbuffer_init(object, device, size, usage, fvf, pool);
1202     if (FAILED(hr))
1203     {
1204         WARN("Failed to initialize vertex buffer, hr %#x.\n", hr);
1205         HeapFree(GetProcessHeap(), 0, object);
1206         return hr;
1207     }
1208 
1209     TRACE("Created vertex buffer %p.\n", object);
1210     *buffer = &object->IDirect3DVertexBuffer9_iface;
1211 
1212     return D3D_OK;
1213 }
1214 
1215 static HRESULT WINAPI d3d9_device_CreateIndexBuffer(IDirect3DDevice9Ex *iface, UINT size,
1216         DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DIndexBuffer9 **buffer,
1217         HANDLE *shared_handle)
1218 {
1219     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1220     struct d3d9_indexbuffer *object;
1221     HRESULT hr;
1222 
1223     TRACE("iface %p, size %u, usage %#x, format %#x, pool %#x, buffer %p, shared_handle %p.\n",
1224             iface, size, usage, format, pool, buffer, shared_handle);
1225 
1226     if (shared_handle)
1227     {
1228         if (!device->d3d_parent->extended)
1229         {
1230             WARN("Trying to create a shared index buffer on a non-ex device.\n");
1231             return E_NOTIMPL;
1232         }
1233 
1234         if (pool != D3DPOOL_DEFAULT)
1235         {
1236             WARN("Trying to create a shared index buffer in pool %#x.\n", pool);
1237             return D3DERR_NOTAVAILABLE;
1238         }
1239         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1240     }
1241 
1242     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
1243     if (!object)
1244         return D3DERR_OUTOFVIDEOMEMORY;
1245 
1246     hr = indexbuffer_init(object, device, size, usage, format, pool);
1247     if (FAILED(hr))
1248     {
1249         WARN("Failed to initialize index buffer, hr %#x.\n", hr);
1250         HeapFree(GetProcessHeap(), 0, object);
1251         return hr;
1252     }
1253 
1254     TRACE("Created index buffer %p.\n", object);
1255     *buffer = &object->IDirect3DIndexBuffer9_iface;
1256 
1257     return D3D_OK;
1258 }
1259 
1260 static HRESULT d3d9_device_create_surface(struct d3d9_device *device, UINT width, UINT height,
1261         D3DFORMAT format, DWORD flags, IDirect3DSurface9 **surface, UINT usage, D3DPOOL pool,
1262         D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality, void *user_mem)
1263 {
1264     struct wined3d_resource_desc desc;
1265     struct d3d9_surface *surface_impl;
1266     struct wined3d_texture *texture;
1267     HRESULT hr;
1268 
1269     TRACE("device %p, width %u, height %u, format %#x, flags %#x, surface %p.\n"
1270             "usage %#x, pool %#x, multisample_type %#x, multisample_quality %u.\n",
1271             device, width, height, format, flags, surface, usage, pool,
1272             multisample_type, multisample_quality);
1273 
1274     desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1275     desc.format = wined3dformat_from_d3dformat(format);
1276     desc.multisample_type = multisample_type;
1277     desc.multisample_quality = multisample_quality;
1278     desc.usage = usage & WINED3DUSAGE_MASK;
1279     desc.pool = pool;
1280     desc.width = width;
1281     desc.height = height;
1282     desc.depth = 1;
1283     desc.size = 0;
1284 
1285     if (is_gdi_compat_wined3dformat(desc.format))
1286         flags |= WINED3D_TEXTURE_CREATE_GET_DC;
1287 
1288     wined3d_mutex_lock();
1289 
1290     if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &desc,
1291             1, 1, flags, NULL, NULL, &d3d9_null_wined3d_parent_ops, &texture)))
1292     {
1293         wined3d_mutex_unlock();
1294         WARN("Failed to create texture, hr %#x.\n", hr);
1295         if (hr == WINED3DERR_NOTAVAILABLE)
1296             hr = D3DERR_INVALIDCALL;
1297         return hr;
1298     }
1299 
1300     surface_impl = wined3d_texture_get_sub_resource_parent(texture, 0);
1301     surface_impl->parent_device = &device->IDirect3DDevice9Ex_iface;
1302     *surface = &surface_impl->IDirect3DSurface9_iface;
1303     IDirect3DSurface9_AddRef(*surface);
1304 
1305     if (user_mem)
1306         wined3d_texture_update_desc(texture, width, height,
1307                 desc.format, multisample_type, multisample_quality, user_mem, 0);
1308 
1309     wined3d_texture_decref(texture);
1310 
1311     wined3d_mutex_unlock();
1312 
1313     return D3D_OK;
1314 }
1315 
1316 BOOL is_gdi_compat_wined3dformat(enum wined3d_format_id format)
1317 {
1318     switch (format)
1319     {
1320         case WINED3DFMT_B8G8R8A8_UNORM:
1321         case WINED3DFMT_B8G8R8X8_UNORM:
1322         case WINED3DFMT_B5G6R5_UNORM:
1323         case WINED3DFMT_B5G5R5X1_UNORM:
1324         case WINED3DFMT_B5G5R5A1_UNORM:
1325         case WINED3DFMT_B8G8R8_UNORM:
1326             return TRUE;
1327         default:
1328             return FALSE;
1329     }
1330 }
1331 
1332 static HRESULT WINAPI d3d9_device_CreateRenderTarget(IDirect3DDevice9Ex *iface, UINT width, UINT height,
1333         D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality,
1334         BOOL lockable, IDirect3DSurface9 **surface, HANDLE *shared_handle)
1335 {
1336     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1337     DWORD flags = 0;
1338 
1339     TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, multisample_quality %u.\n"
1340             "lockable %#x, surface %p, shared_handle %p.\n",
1341             iface, width, height, format, multisample_type, multisample_quality,
1342             lockable, surface, shared_handle);
1343 
1344     *surface = NULL;
1345     if (shared_handle)
1346     {
1347         if (!device->d3d_parent->extended)
1348         {
1349             WARN("Trying to create a shared render target on a non-ex device.\n");
1350             return E_NOTIMPL;
1351         }
1352 
1353         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1354     }
1355 
1356     if (lockable)
1357         flags |= WINED3D_TEXTURE_CREATE_MAPPABLE;
1358 
1359     return d3d9_device_create_surface(device, width, height, format, flags, surface,
1360             D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT, multisample_type, multisample_quality, NULL);
1361 }
1362 
1363 static HRESULT WINAPI d3d9_device_CreateDepthStencilSurface(IDirect3DDevice9Ex *iface, UINT width, UINT height,
1364         D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality,
1365         BOOL discard, IDirect3DSurface9 **surface, HANDLE *shared_handle)
1366 {
1367     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1368     DWORD flags = WINED3D_TEXTURE_CREATE_MAPPABLE;
1369 
1370     TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, multisample_quality %u.\n"
1371             "discard %#x, surface %p, shared_handle %p.\n",
1372             iface, width, height, format, multisample_type, multisample_quality,
1373             discard, surface, shared_handle);
1374 
1375     *surface = NULL;
1376     if (shared_handle)
1377     {
1378         if (!device->d3d_parent->extended)
1379         {
1380             WARN("Trying to create a shared depth stencil on a non-ex device.\n");
1381             return E_NOTIMPL;
1382         }
1383 
1384         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1385     }
1386 
1387     if (discard)
1388         flags |= WINED3D_TEXTURE_CREATE_DISCARD;
1389 
1390     return d3d9_device_create_surface(device, width, height, format, flags, surface,
1391             D3DUSAGE_DEPTHSTENCIL, D3DPOOL_DEFAULT, multisample_type, multisample_quality, NULL);
1392 }
1393 
1394 
1395 static HRESULT WINAPI d3d9_device_UpdateSurface(IDirect3DDevice9Ex *iface,
1396         IDirect3DSurface9 *src_surface, const RECT *src_rect,
1397         IDirect3DSurface9 *dst_surface, const POINT *dst_point)
1398 {
1399     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1400     struct d3d9_surface *src = unsafe_impl_from_IDirect3DSurface9(src_surface);
1401     struct d3d9_surface *dst = unsafe_impl_from_IDirect3DSurface9(dst_surface);
1402     struct wined3d_sub_resource_desc src_desc, dst_desc;
1403     struct wined3d_box src_box;
1404     HRESULT hr;
1405 
1406     TRACE("iface %p, src_surface %p, src_rect %p, dst_surface %p, dst_point %p.\n",
1407             iface, src_surface, src_rect, dst_surface, dst_point);
1408 
1409     wined3d_mutex_lock();
1410 
1411     wined3d_texture_get_sub_resource_desc(src->wined3d_texture, src->sub_resource_idx, &src_desc);
1412     wined3d_texture_get_sub_resource_desc(dst->wined3d_texture, dst->sub_resource_idx, &dst_desc);
1413     if (src_desc.format != dst_desc.format)
1414     {
1415         wined3d_mutex_unlock();
1416         WARN("Surface formats (%#x/%#x) don't match.\n",
1417                 d3dformat_from_wined3dformat(src_desc.format),
1418                 d3dformat_from_wined3dformat(dst_desc.format));
1419         return D3DERR_INVALIDCALL;
1420     }
1421 
1422     if (src_rect)
1423         wined3d_box_set(&src_box, src_rect->left, src_rect->top, src_rect->right, src_rect->bottom, 0, 1);
1424     else
1425         wined3d_box_set(&src_box, 0, 0, src_desc.width, src_desc.height, 0, 1);
1426 
1427     hr = wined3d_device_copy_sub_resource_region(device->wined3d_device,
1428             wined3d_texture_get_resource(dst->wined3d_texture), dst->sub_resource_idx, dst_point ? dst_point->x : 0,
1429             dst_point ? dst_point->y : 0, 0, wined3d_texture_get_resource(src->wined3d_texture),
1430             src->sub_resource_idx, &src_box);
1431     wined3d_mutex_unlock();
1432 
1433     if (FAILED(hr))
1434         return D3DERR_INVALIDCALL;
1435 
1436     return hr;
1437 }
1438 
1439 static HRESULT WINAPI d3d9_device_UpdateTexture(IDirect3DDevice9Ex *iface,
1440         IDirect3DBaseTexture9 *src_texture, IDirect3DBaseTexture9 *dst_texture)
1441 {
1442     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1443     struct d3d9_texture *src_impl, *dst_impl;
1444     HRESULT hr;
1445 
1446     TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
1447 
1448     src_impl = unsafe_impl_from_IDirect3DBaseTexture9(src_texture);
1449     dst_impl = unsafe_impl_from_IDirect3DBaseTexture9(dst_texture);
1450 
1451     wined3d_mutex_lock();
1452     hr = wined3d_device_update_texture(device->wined3d_device,
1453             src_impl->wined3d_texture, dst_impl->wined3d_texture);
1454     wined3d_mutex_unlock();
1455 
1456     return hr;
1457 }
1458 
1459 static HRESULT WINAPI d3d9_device_GetRenderTargetData(IDirect3DDevice9Ex *iface,
1460         IDirect3DSurface9 *render_target, IDirect3DSurface9 *dst_surface)
1461 {
1462     struct d3d9_surface *rt_impl = unsafe_impl_from_IDirect3DSurface9(render_target);
1463     struct d3d9_surface *dst_impl = unsafe_impl_from_IDirect3DSurface9(dst_surface);
1464     struct wined3d_sub_resource_desc wined3d_desc;
1465     RECT dst_rect, src_rect;
1466     HRESULT hr;
1467 
1468     TRACE("iface %p, render_target %p, dst_surface %p.\n", iface, render_target, dst_surface);
1469 
1470     if (!render_target || !dst_surface)
1471         return D3DERR_INVALIDCALL;
1472 
1473     wined3d_mutex_lock();
1474     wined3d_texture_get_sub_resource_desc(dst_impl->wined3d_texture, dst_impl->sub_resource_idx, &wined3d_desc);
1475     SetRect(&dst_rect, 0, 0, wined3d_desc.width, wined3d_desc.height);
1476 
1477     wined3d_texture_get_sub_resource_desc(rt_impl->wined3d_texture, rt_impl->sub_resource_idx, &wined3d_desc);
1478     SetRect(&src_rect, 0, 0, wined3d_desc.width, wined3d_desc.height);
1479 
1480     /* TODO: Check surface sizes, pools, etc. */
1481     if (wined3d_desc.multisample_type)
1482         hr = D3DERR_INVALIDCALL;
1483     else
1484         hr = wined3d_texture_blt(dst_impl->wined3d_texture, dst_impl->sub_resource_idx, &dst_rect,
1485                 rt_impl->wined3d_texture, rt_impl->sub_resource_idx, &src_rect, 0, NULL, WINED3D_TEXF_POINT);
1486     wined3d_mutex_unlock();
1487 
1488     return hr;
1489 }
1490 
1491 static HRESULT WINAPI d3d9_device_GetFrontBufferData(IDirect3DDevice9Ex *iface,
1492         UINT swapchain, IDirect3DSurface9 *dst_surface)
1493 {
1494     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1495     struct d3d9_surface *dst_impl = unsafe_impl_from_IDirect3DSurface9(dst_surface);
1496     HRESULT hr = D3DERR_INVALIDCALL;
1497 
1498     TRACE("iface %p, swapchain %u, dst_surface %p.\n", iface, swapchain, dst_surface);
1499 
1500     wined3d_mutex_lock();
1501     if (swapchain < device->implicit_swapchain_count)
1502         hr = wined3d_swapchain_get_front_buffer_data(device->implicit_swapchains[swapchain]->wined3d_swapchain,
1503                 dst_impl->wined3d_texture, dst_impl->sub_resource_idx);
1504     wined3d_mutex_unlock();
1505 
1506     return hr;
1507 }
1508 
1509 static HRESULT WINAPI d3d9_device_StretchRect(IDirect3DDevice9Ex *iface, IDirect3DSurface9 *src_surface,
1510         const RECT *src_rect, IDirect3DSurface9 *dst_surface, const RECT *dst_rect, D3DTEXTUREFILTERTYPE filter)
1511 {
1512     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1513     struct d3d9_surface *src = unsafe_impl_from_IDirect3DSurface9(src_surface);
1514     struct d3d9_surface *dst = unsafe_impl_from_IDirect3DSurface9(dst_surface);
1515     struct wined3d_sub_resource_desc src_desc, dst_desc;
1516     HRESULT hr = D3DERR_INVALIDCALL;
1517     RECT d, s;
1518 
1519     TRACE("iface %p, src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %#x.\n",
1520             iface, src_surface, src_rect, dst_surface, dst_rect, filter);
1521 
1522     wined3d_mutex_lock();
1523     wined3d_texture_get_sub_resource_desc(dst->wined3d_texture, dst->sub_resource_idx, &dst_desc);
1524     if (!dst_rect)
1525     {
1526         SetRect(&d, 0, 0, dst_desc.width, dst_desc.height);
1527         dst_rect = &d;
1528     }
1529 
1530     wined3d_texture_get_sub_resource_desc(src->wined3d_texture, src->sub_resource_idx, &src_desc);
1531     if (!src_rect)
1532     {
1533         SetRect(&s, 0, 0, src_desc.width, src_desc.height);
1534         src_rect = &s;
1535     }
1536 
1537     if (src_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
1538     {
1539         if (device->in_scene)
1540         {
1541             WARN("Rejecting depth / stencil blit while in scene.\n");
1542             goto done;
1543         }
1544 
1545         if (src_rect->left || src_rect->top || src_rect->right != src_desc.width
1546                 || src_rect->bottom != src_desc.height)
1547         {
1548             WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
1549                     wine_dbgstr_rect(src_rect));
1550             goto done;
1551         }
1552 
1553         if (dst_rect->left || dst_rect->top || dst_rect->right != dst_desc.width
1554                 || dst_rect->bottom != dst_desc.height)
1555         {
1556             WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
1557                     wine_dbgstr_rect(dst_rect));
1558             goto done;
1559         }
1560 
1561         if (src_desc.width != dst_desc.width || src_desc.height != dst_desc.height)
1562         {
1563             WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
1564             goto done;
1565         }
1566     }
1567 
1568     hr = wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, dst_rect,
1569             src->wined3d_texture, src->sub_resource_idx, src_rect, 0, NULL, filter);
1570     if (hr == WINEDDERR_INVALIDRECT)
1571         hr = D3DERR_INVALIDCALL;
1572 
1573 done:
1574     wined3d_mutex_unlock();
1575     return hr;
1576 }
1577 
1578 static HRESULT WINAPI d3d9_device_ColorFill(IDirect3DDevice9Ex *iface,
1579         IDirect3DSurface9 *surface, const RECT *rect, D3DCOLOR color)
1580 {
1581     const struct wined3d_color c =
1582     {
1583         ((color >> 16) & 0xff) / 255.0f,
1584         ((color >>  8) & 0xff) / 255.0f,
1585         (color & 0xff) / 255.0f,
1586         ((color >> 24) & 0xff) / 255.0f,
1587     };
1588     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1589     struct d3d9_surface *surface_impl = unsafe_impl_from_IDirect3DSurface9(surface);
1590     struct wined3d_sub_resource_desc desc;
1591     struct wined3d_rendertarget_view *rtv;
1592     HRESULT hr;
1593 
1594     TRACE("iface %p, surface %p, rect %p, color 0x%08x.\n", iface, surface, rect, color);
1595 
1596     wined3d_mutex_lock();
1597 
1598     if (FAILED(wined3d_texture_get_sub_resource_desc(surface_impl->wined3d_texture,
1599             surface_impl->sub_resource_idx, &desc)))
1600     {
1601         wined3d_mutex_unlock();
1602         return D3DERR_INVALIDCALL;
1603     }
1604 
1605     if (desc.pool != WINED3D_POOL_DEFAULT)
1606     {
1607         wined3d_mutex_unlock();
1608         WARN("Colorfill is not allowed on surfaces in pool %#x, returning D3DERR_INVALIDCALL.\n", desc.pool);
1609         return D3DERR_INVALIDCALL;
1610     }
1611     if ((desc.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_TEXTURE)) == WINED3DUSAGE_TEXTURE)
1612     {
1613         wined3d_mutex_unlock();
1614         WARN("Colorfill is not allowed on non-RT textures, returning D3DERR_INVALIDCALL.\n");
1615         return D3DERR_INVALIDCALL;
1616     }
1617     if (desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
1618     {
1619         wined3d_mutex_unlock();
1620         WARN("Colorfill is not allowed on depth stencil surfaces, returning D3DERR_INVALIDCALL.\n");
1621         return D3DERR_INVALIDCALL;
1622     }
1623 
1624     rtv = d3d9_surface_acquire_rendertarget_view(surface_impl);
1625     hr = wined3d_device_clear_rendertarget_view(device->wined3d_device,
1626             rtv, rect, WINED3DCLEAR_TARGET, &c, 0.0f, 0);
1627     d3d9_surface_release_rendertarget_view(surface_impl, rtv);
1628 
1629     wined3d_mutex_unlock();
1630 
1631     return hr;
1632 }
1633 
1634 static HRESULT WINAPI d3d9_device_CreateOffscreenPlainSurface(IDirect3DDevice9Ex *iface,
1635         UINT width, UINT height, D3DFORMAT format, D3DPOOL pool, IDirect3DSurface9 **surface,
1636         HANDLE *shared_handle)
1637 {
1638     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1639     void *user_mem = NULL;
1640 
1641     TRACE("iface %p, width %u, height %u, format %#x, pool %#x, surface %p, shared_handle %p.\n",
1642             iface, width, height, format, pool, surface, shared_handle);
1643 
1644     *surface = NULL;
1645     if (pool == D3DPOOL_MANAGED)
1646     {
1647         WARN("Attempting to create a managed offscreen plain surface.\n");
1648         return D3DERR_INVALIDCALL;
1649     }
1650 
1651     if (shared_handle)
1652     {
1653         if (!device->d3d_parent->extended)
1654         {
1655             WARN("Trying to create a shared or user memory surface on a non-ex device.\n");
1656             return E_NOTIMPL;
1657         }
1658 
1659         if (pool == D3DPOOL_SYSTEMMEM)
1660             user_mem = *shared_handle;
1661         else
1662         {
1663             if (pool != D3DPOOL_DEFAULT)
1664             {
1665                 WARN("Trying to create a shared surface in pool %#x.\n", pool);
1666                 return D3DERR_INVALIDCALL;
1667             }
1668             FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
1669         }
1670     }
1671 
1672     /* FIXME: Offscreen surfaces are supposed to be always lockable,
1673      * regardless of the pool they're created in. Should we set dynamic usage
1674      * here? */
1675     return d3d9_device_create_surface(device, width, height, format,
1676             WINED3D_TEXTURE_CREATE_MAPPABLE, surface, 0, pool, D3DMULTISAMPLE_NONE, 0, user_mem);
1677 }
1678 
1679 static HRESULT WINAPI d3d9_device_SetRenderTarget(IDirect3DDevice9Ex *iface, DWORD idx, IDirect3DSurface9 *surface)
1680 {
1681     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1682     struct d3d9_surface *surface_impl = unsafe_impl_from_IDirect3DSurface9(surface);
1683     struct wined3d_rendertarget_view *rtv;
1684     HRESULT hr;
1685 
1686     TRACE("iface %p, idx %u, surface %p.\n", iface, idx, surface);
1687 
1688     if (idx >= D3D9_MAX_SIMULTANEOUS_RENDERTARGETS)
1689     {
1690         WARN("Invalid index %u specified.\n", idx);
1691         return D3DERR_INVALIDCALL;
1692     }
1693 
1694     if (!idx && !surface_impl)
1695     {
1696         WARN("Trying to set render target 0 to NULL.\n");
1697         return D3DERR_INVALIDCALL;
1698     }
1699 
1700     if (surface_impl && d3d9_surface_get_device(surface_impl) != device)
1701     {
1702         WARN("Render target surface does not match device.\n");
1703         return D3DERR_INVALIDCALL;
1704     }
1705 
1706     wined3d_mutex_lock();
1707     rtv = surface_impl ? d3d9_surface_acquire_rendertarget_view(surface_impl) : NULL;
1708     hr = wined3d_device_set_rendertarget_view(device->wined3d_device, idx, rtv, TRUE);
1709     d3d9_surface_release_rendertarget_view(surface_impl, rtv);
1710     wined3d_mutex_unlock();
1711 
1712     return hr;
1713 }
1714 
1715 static HRESULT WINAPI d3d9_device_GetRenderTarget(IDirect3DDevice9Ex *iface, DWORD idx, IDirect3DSurface9 **surface)
1716 {
1717     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1718     struct wined3d_rendertarget_view *wined3d_rtv;
1719     struct d3d9_surface *surface_impl;
1720     HRESULT hr = D3D_OK;
1721 
1722     TRACE("iface %p, idx %u, surface %p.\n", iface, idx, surface);
1723 
1724     if (!surface)
1725         return D3DERR_INVALIDCALL;
1726 
1727     if (idx >= D3D9_MAX_SIMULTANEOUS_RENDERTARGETS)
1728     {
1729         WARN("Invalid index %u specified.\n", idx);
1730         return D3DERR_INVALIDCALL;
1731     }
1732 
1733     wined3d_mutex_lock();
1734     if ((wined3d_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, idx)))
1735     {
1736         /* We want the sub resource parent here, since the view itself may be
1737          * internal to wined3d and may not have a parent. */
1738         surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_rtv);
1739         *surface = &surface_impl->IDirect3DSurface9_iface;
1740         IDirect3DSurface9_AddRef(*surface);
1741     }
1742     else
1743     {
1744         hr = D3DERR_NOTFOUND;
1745         *surface = NULL;
1746     }
1747     wined3d_mutex_unlock();
1748 
1749     return hr;
1750 }
1751 
1752 static HRESULT WINAPI d3d9_device_SetDepthStencilSurface(IDirect3DDevice9Ex *iface, IDirect3DSurface9 *depth_stencil)
1753 {
1754     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1755     struct d3d9_surface *ds_impl = unsafe_impl_from_IDirect3DSurface9(depth_stencil);
1756     struct wined3d_rendertarget_view *rtv;
1757 
1758     TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
1759 
1760     wined3d_mutex_lock();
1761     rtv = ds_impl ? d3d9_surface_acquire_rendertarget_view(ds_impl) : NULL;
1762     wined3d_device_set_depth_stencil_view(device->wined3d_device, rtv);
1763     d3d9_surface_release_rendertarget_view(ds_impl, rtv);
1764     wined3d_mutex_unlock();
1765 
1766     return D3D_OK;
1767 }
1768 
1769 static HRESULT WINAPI d3d9_device_GetDepthStencilSurface(IDirect3DDevice9Ex *iface, IDirect3DSurface9 **depth_stencil)
1770 {
1771     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1772     struct wined3d_rendertarget_view *wined3d_dsv;
1773     struct d3d9_surface *surface_impl;
1774     HRESULT hr = D3D_OK;
1775 
1776     TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
1777 
1778     if (!depth_stencil)
1779         return D3DERR_INVALIDCALL;
1780 
1781     wined3d_mutex_lock();
1782     if ((wined3d_dsv = wined3d_device_get_depth_stencil_view(device->wined3d_device)))
1783     {
1784         /* We want the sub resource parent here, since the view itself may be
1785          * internal to wined3d and may not have a parent. */
1786         surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_dsv);
1787         *depth_stencil = &surface_impl->IDirect3DSurface9_iface;
1788         IDirect3DSurface9_AddRef(*depth_stencil);
1789     }
1790     else
1791     {
1792         hr = D3DERR_NOTFOUND;
1793         *depth_stencil = NULL;
1794     }
1795     wined3d_mutex_unlock();
1796 
1797     return hr;
1798 }
1799 
1800 static HRESULT WINAPI d3d9_device_BeginScene(IDirect3DDevice9Ex *iface)
1801 {
1802     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1803     HRESULT hr;
1804 
1805     TRACE("iface %p.\n", iface);
1806 
1807     wined3d_mutex_lock();
1808     if (SUCCEEDED(hr = wined3d_device_begin_scene(device->wined3d_device)))
1809         device->in_scene = TRUE;
1810     wined3d_mutex_unlock();
1811 
1812     return hr;
1813 }
1814 
1815 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_EndScene(IDirect3DDevice9Ex *iface)
1816 {
1817     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1818     HRESULT hr;
1819 
1820     TRACE("iface %p.\n", iface);
1821 
1822     wined3d_mutex_lock();
1823     if (SUCCEEDED(hr = wined3d_device_end_scene(device->wined3d_device)))
1824         device->in_scene = FALSE;
1825     wined3d_mutex_unlock();
1826 
1827     return hr;
1828 }
1829 
1830 static HRESULT WINAPI d3d9_device_Clear(IDirect3DDevice9Ex *iface, DWORD rect_count,
1831         const D3DRECT *rects, DWORD flags, D3DCOLOR color, float z, DWORD stencil)
1832 {
1833     const struct wined3d_color c =
1834     {
1835         ((color >> 16) & 0xff) / 255.0f,
1836         ((color >>  8) & 0xff) / 255.0f,
1837         (color & 0xff) / 255.0f,
1838         ((color >> 24) & 0xff) / 255.0f,
1839     };
1840     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1841     HRESULT hr;
1842 
1843     TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %u.\n",
1844             iface, rect_count, rects, flags, color, z, stencil);
1845 
1846     if (rect_count && !rects)
1847     {
1848         WARN("count %u with NULL rects.\n", rect_count);
1849         rect_count = 0;
1850     }
1851 
1852     wined3d_mutex_lock();
1853     hr = wined3d_device_clear(device->wined3d_device, rect_count, (const RECT *)rects, flags, &c, z, stencil);
1854     wined3d_mutex_unlock();
1855 
1856     return hr;
1857 }
1858 
1859 static HRESULT WINAPI d3d9_device_SetTransform(IDirect3DDevice9Ex *iface,
1860         D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1861 {
1862     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1863 
1864     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1865 
1866     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1867     wined3d_mutex_lock();
1868     wined3d_device_set_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1869     wined3d_mutex_unlock();
1870 
1871     return D3D_OK;
1872 }
1873 
1874 static HRESULT WINAPI d3d9_device_GetTransform(IDirect3DDevice9Ex *iface,
1875         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
1876 {
1877     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1878 
1879     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1880 
1881     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1882     wined3d_mutex_lock();
1883     wined3d_device_get_transform(device->wined3d_device, state, (struct wined3d_matrix *)matrix);
1884     wined3d_mutex_unlock();
1885 
1886     return D3D_OK;
1887 }
1888 
1889 static HRESULT WINAPI d3d9_device_MultiplyTransform(IDirect3DDevice9Ex *iface,
1890         D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1891 {
1892     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1893 
1894     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1895 
1896     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1897     wined3d_mutex_lock();
1898     wined3d_device_multiply_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1899     wined3d_mutex_unlock();
1900 
1901     return D3D_OK;
1902 }
1903 
1904 static HRESULT WINAPI d3d9_device_SetViewport(IDirect3DDevice9Ex *iface, const D3DVIEWPORT9 *viewport)
1905 {
1906     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1907     struct wined3d_viewport vp;
1908 
1909     TRACE("iface %p, viewport %p.\n", iface, viewport);
1910 
1911     vp.x = viewport->X;
1912     vp.y = viewport->Y;
1913     vp.width = viewport->Width;
1914     vp.height = viewport->Height;
1915     vp.min_z = viewport->MinZ;
1916     vp.max_z = viewport->MaxZ;
1917 
1918     wined3d_mutex_lock();
1919     wined3d_device_set_viewport(device->wined3d_device, &vp);
1920     wined3d_mutex_unlock();
1921 
1922     return D3D_OK;
1923 }
1924 
1925 static HRESULT WINAPI d3d9_device_GetViewport(IDirect3DDevice9Ex *iface, D3DVIEWPORT9 *viewport)
1926 {
1927     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1928     struct wined3d_viewport wined3d_viewport;
1929 
1930     TRACE("iface %p, viewport %p.\n", iface, viewport);
1931 
1932     wined3d_mutex_lock();
1933     wined3d_device_get_viewport(device->wined3d_device, &wined3d_viewport);
1934     wined3d_mutex_unlock();
1935 
1936     viewport->X = wined3d_viewport.x;
1937     viewport->Y = wined3d_viewport.y;
1938     viewport->Width = wined3d_viewport.width;
1939     viewport->Height = wined3d_viewport.height;
1940     viewport->MinZ = wined3d_viewport.min_z;
1941     viewport->MaxZ = wined3d_viewport.max_z;
1942 
1943     return D3D_OK;
1944 }
1945 
1946 static HRESULT WINAPI d3d9_device_SetMaterial(IDirect3DDevice9Ex *iface, const D3DMATERIAL9 *material)
1947 {
1948     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1949 
1950     TRACE("iface %p, material %p.\n", iface, material);
1951 
1952     /* Note: D3DMATERIAL9 is compatible with struct wined3d_material. */
1953     wined3d_mutex_lock();
1954     wined3d_device_set_material(device->wined3d_device, (const struct wined3d_material *)material);
1955     wined3d_mutex_unlock();
1956 
1957     return D3D_OK;
1958 }
1959 
1960 static HRESULT WINAPI d3d9_device_GetMaterial(IDirect3DDevice9Ex *iface, D3DMATERIAL9 *material)
1961 {
1962     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1963 
1964     TRACE("iface %p, material %p.\n", iface, material);
1965 
1966     /* Note: D3DMATERIAL9 is compatible with struct wined3d_material. */
1967     wined3d_mutex_lock();
1968     wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
1969     wined3d_mutex_unlock();
1970 
1971     return D3D_OK;
1972 }
1973 
1974 static HRESULT WINAPI d3d9_device_SetLight(IDirect3DDevice9Ex *iface, DWORD index, const D3DLIGHT9 *light)
1975 {
1976     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1977     HRESULT hr;
1978 
1979     TRACE("iface %p, index %u, light %p.\n", iface, index, light);
1980 
1981     /* Note: D3DLIGHT9 is compatible with struct wined3d_light. */
1982     wined3d_mutex_lock();
1983     hr = wined3d_device_set_light(device->wined3d_device, index, (const struct wined3d_light *)light);
1984     wined3d_mutex_unlock();
1985 
1986     return hr;
1987 }
1988 
1989 static HRESULT WINAPI d3d9_device_GetLight(IDirect3DDevice9Ex *iface, DWORD index, D3DLIGHT9 *light)
1990 {
1991     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
1992     HRESULT hr;
1993 
1994     TRACE("iface %p, index %u, light %p.\n", iface, index, light);
1995 
1996     /* Note: D3DLIGHT9 is compatible with struct wined3d_light. */
1997     wined3d_mutex_lock();
1998     hr = wined3d_device_get_light(device->wined3d_device, index, (struct wined3d_light *)light);
1999     wined3d_mutex_unlock();
2000 
2001     return hr;
2002 }
2003 
2004 static HRESULT WINAPI d3d9_device_LightEnable(IDirect3DDevice9Ex *iface, DWORD index, BOOL enable)
2005 {
2006     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2007     HRESULT hr;
2008 
2009     TRACE("iface %p, index %u, enable %#x.\n", iface, index, enable);
2010 
2011     wined3d_mutex_lock();
2012     hr = wined3d_device_set_light_enable(device->wined3d_device, index, enable);
2013     wined3d_mutex_unlock();
2014 
2015     return hr;
2016 }
2017 
2018 static HRESULT WINAPI d3d9_device_GetLightEnable(IDirect3DDevice9Ex *iface, DWORD index, BOOL *enable)
2019 {
2020     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2021     HRESULT hr;
2022 
2023     TRACE("iface %p, index %u, enable %p.\n", iface, index, enable);
2024 
2025     wined3d_mutex_lock();
2026     hr = wined3d_device_get_light_enable(device->wined3d_device, index, enable);
2027     wined3d_mutex_unlock();
2028 
2029     return hr;
2030 }
2031 
2032 static HRESULT WINAPI d3d9_device_SetClipPlane(IDirect3DDevice9Ex *iface, DWORD index, const float *plane)
2033 {
2034     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2035     HRESULT hr;
2036 
2037     TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
2038 
2039     index = min(index, device->max_user_clip_planes - 1);
2040 
2041     wined3d_mutex_lock();
2042     hr = wined3d_device_set_clip_plane(device->wined3d_device, index, (const struct wined3d_vec4 *)plane);
2043     wined3d_mutex_unlock();
2044 
2045     return hr;
2046 }
2047 
2048 static HRESULT WINAPI d3d9_device_GetClipPlane(IDirect3DDevice9Ex *iface, DWORD index, float *plane)
2049 {
2050     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2051     HRESULT hr;
2052 
2053     TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
2054 
2055     index = min(index, device->max_user_clip_planes - 1);
2056 
2057     wined3d_mutex_lock();
2058     hr = wined3d_device_get_clip_plane(device->wined3d_device, index, (struct wined3d_vec4 *)plane);
2059     wined3d_mutex_unlock();
2060 
2061     return hr;
2062 }
2063 
2064 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_SetRenderState(IDirect3DDevice9Ex *iface,
2065         D3DRENDERSTATETYPE state, DWORD value)
2066 {
2067     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2068 
2069     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2070 
2071     wined3d_mutex_lock();
2072     wined3d_device_set_render_state(device->wined3d_device, state, value);
2073     wined3d_mutex_unlock();
2074 
2075     return D3D_OK;
2076 }
2077 
2078 static HRESULT WINAPI d3d9_device_GetRenderState(IDirect3DDevice9Ex *iface,
2079         D3DRENDERSTATETYPE state, DWORD *value)
2080 {
2081     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2082 
2083     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2084 
2085     wined3d_mutex_lock();
2086     *value = wined3d_device_get_render_state(device->wined3d_device, state);
2087     wined3d_mutex_unlock();
2088 
2089     return D3D_OK;
2090 }
2091 
2092 static HRESULT WINAPI d3d9_device_CreateStateBlock(IDirect3DDevice9Ex *iface,
2093         D3DSTATEBLOCKTYPE type, IDirect3DStateBlock9 **stateblock)
2094 {
2095     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2096     struct d3d9_stateblock *object;
2097     HRESULT hr;
2098 
2099     TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
2100 
2101     if (type != D3DSBT_ALL && type != D3DSBT_PIXELSTATE && type != D3DSBT_VERTEXSTATE)
2102     {
2103         WARN("Unexpected stateblock type, returning D3DERR_INVALIDCALL.\n");
2104         return D3DERR_INVALIDCALL;
2105     }
2106 
2107     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2108     if (!object)
2109         return E_OUTOFMEMORY;
2110 
2111     hr = stateblock_init(object, device, type, NULL);
2112     if (FAILED(hr))
2113     {
2114         WARN("Failed to initialize stateblock, hr %#x.\n", hr);
2115         HeapFree(GetProcessHeap(), 0, object);
2116         return hr;
2117     }
2118 
2119     TRACE("Created stateblock %p.\n", object);
2120     *stateblock = &object->IDirect3DStateBlock9_iface;
2121 
2122     return D3D_OK;
2123 }
2124 
2125 static HRESULT WINAPI d3d9_device_BeginStateBlock(IDirect3DDevice9Ex *iface)
2126 {
2127     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2128     HRESULT hr;
2129 
2130     TRACE("iface %p.\n", iface);
2131 
2132     wined3d_mutex_lock();
2133     hr = wined3d_device_begin_stateblock(device->wined3d_device);
2134     wined3d_mutex_unlock();
2135 
2136     return hr;
2137 }
2138 
2139 static HRESULT WINAPI d3d9_device_EndStateBlock(IDirect3DDevice9Ex *iface, IDirect3DStateBlock9 **stateblock)
2140 {
2141     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2142     struct wined3d_stateblock *wined3d_stateblock;
2143     struct d3d9_stateblock *object;
2144     HRESULT hr;
2145 
2146     TRACE("iface %p, stateblock %p.\n", iface, stateblock);
2147 
2148     wined3d_mutex_lock();
2149     hr = wined3d_device_end_stateblock(device->wined3d_device, &wined3d_stateblock);
2150     wined3d_mutex_unlock();
2151     if (FAILED(hr))
2152     {
2153        WARN("Failed to end the state block, hr %#x.\n", hr);
2154        return hr;
2155     }
2156 
2157     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2158     if (!object)
2159     {
2160         wined3d_mutex_lock();
2161         wined3d_stateblock_decref(wined3d_stateblock);
2162         wined3d_mutex_unlock();
2163         return E_OUTOFMEMORY;
2164     }
2165 
2166     hr = stateblock_init(object, device, 0, wined3d_stateblock);
2167     if (FAILED(hr))
2168     {
2169         WARN("Failed to initialize stateblock, hr %#x.\n", hr);
2170         wined3d_mutex_lock();
2171         wined3d_stateblock_decref(wined3d_stateblock);
2172         wined3d_mutex_unlock();
2173         HeapFree(GetProcessHeap(), 0, object);
2174         return hr;
2175     }
2176 
2177     TRACE("Created stateblock %p.\n", object);
2178     *stateblock = &object->IDirect3DStateBlock9_iface;
2179 
2180     return D3D_OK;
2181 }
2182 
2183 static HRESULT WINAPI d3d9_device_SetClipStatus(IDirect3DDevice9Ex *iface, const D3DCLIPSTATUS9 *clip_status)
2184 {
2185     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2186     HRESULT hr;
2187 
2188     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
2189 
2190     wined3d_mutex_lock();
2191     hr = wined3d_device_set_clip_status(device->wined3d_device, (const struct wined3d_clip_status *)clip_status);
2192     wined3d_mutex_unlock();
2193 
2194     return hr;
2195 }
2196 
2197 static HRESULT WINAPI d3d9_device_GetClipStatus(IDirect3DDevice9Ex *iface, D3DCLIPSTATUS9 *clip_status)
2198 {
2199     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2200     HRESULT hr;
2201 
2202     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
2203 
2204     wined3d_mutex_lock();
2205     hr = wined3d_device_get_clip_status(device->wined3d_device, (struct wined3d_clip_status *)clip_status);
2206     wined3d_mutex_unlock();
2207 
2208     return hr;
2209 }
2210 
2211 static HRESULT WINAPI d3d9_device_GetTexture(IDirect3DDevice9Ex *iface, DWORD stage, IDirect3DBaseTexture9 **texture)
2212 {
2213     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2214     struct wined3d_texture *wined3d_texture = NULL;
2215     struct d3d9_texture *texture_impl;
2216 
2217     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
2218 
2219     if (!texture)
2220         return D3DERR_INVALIDCALL;
2221 
2222     wined3d_mutex_lock();
2223     if ((wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
2224     {
2225         texture_impl = wined3d_texture_get_parent(wined3d_texture);
2226         *texture = &texture_impl->IDirect3DBaseTexture9_iface;
2227         IDirect3DBaseTexture9_AddRef(*texture);
2228     }
2229     else
2230     {
2231         *texture = NULL;
2232     }
2233     wined3d_mutex_unlock();
2234 
2235     return D3D_OK;
2236 }
2237 
2238 static HRESULT WINAPI d3d9_device_SetTexture(IDirect3DDevice9Ex *iface, DWORD stage, IDirect3DBaseTexture9 *texture)
2239 {
2240     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2241     struct d3d9_texture *texture_impl;
2242     HRESULT hr;
2243 
2244     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
2245 
2246     texture_impl = unsafe_impl_from_IDirect3DBaseTexture9(texture);
2247 
2248     wined3d_mutex_lock();
2249     hr = wined3d_device_set_texture(device->wined3d_device, stage,
2250             texture_impl ? texture_impl->wined3d_texture : NULL);
2251     wined3d_mutex_unlock();
2252 
2253     return hr;
2254 }
2255 
2256 static const enum wined3d_texture_stage_state tss_lookup[] =
2257 {
2258     WINED3D_TSS_INVALID,                    /*  0, unused */
2259     WINED3D_TSS_COLOR_OP,                   /*  1, D3DTSS_COLOROP */
2260     WINED3D_TSS_COLOR_ARG1,                 /*  2, D3DTSS_COLORARG1 */
2261     WINED3D_TSS_COLOR_ARG2,                 /*  3, D3DTSS_COLORARG2 */
2262     WINED3D_TSS_ALPHA_OP,                   /*  4, D3DTSS_ALPHAOP */
2263     WINED3D_TSS_ALPHA_ARG1,                 /*  5, D3DTSS_ALPHAARG1 */
2264     WINED3D_TSS_ALPHA_ARG2,                 /*  6, D3DTSS_ALPHAARG2 */
2265     WINED3D_TSS_BUMPENV_MAT00,              /*  7, D3DTSS_BUMPENVMAT00 */
2266     WINED3D_TSS_BUMPENV_MAT01,              /*  8, D3DTSS_BUMPENVMAT01 */
2267     WINED3D_TSS_BUMPENV_MAT10,              /*  9, D3DTSS_BUMPENVMAT10 */
2268     WINED3D_TSS_BUMPENV_MAT11,              /* 10, D3DTSS_BUMPENVMAT11 */
2269     WINED3D_TSS_TEXCOORD_INDEX,             /* 11, D3DTSS_TEXCOORDINDEX */
2270     WINED3D_TSS_INVALID,                    /* 12, unused */
2271     WINED3D_TSS_INVALID,                    /* 13, unused */
2272     WINED3D_TSS_INVALID,                    /* 14, unused */
2273     WINED3D_TSS_INVALID,                    /* 15, unused */
2274     WINED3D_TSS_INVALID,                    /* 16, unused */
2275     WINED3D_TSS_INVALID,                    /* 17, unused */
2276     WINED3D_TSS_INVALID,                    /* 18, unused */
2277     WINED3D_TSS_INVALID,                    /* 19, unused */
2278     WINED3D_TSS_INVALID,                    /* 20, unused */
2279     WINED3D_TSS_INVALID,                    /* 21, unused */
2280     WINED3D_TSS_BUMPENV_LSCALE,             /* 22, D3DTSS_BUMPENVLSCALE */
2281     WINED3D_TSS_BUMPENV_LOFFSET,            /* 23, D3DTSS_BUMPENVLOFFSET */
2282     WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS,    /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
2283     WINED3D_TSS_INVALID,                    /* 25, unused */
2284     WINED3D_TSS_COLOR_ARG0,                 /* 26, D3DTSS_COLORARG0 */
2285     WINED3D_TSS_ALPHA_ARG0,                 /* 27, D3DTSS_ALPHAARG0 */
2286     WINED3D_TSS_RESULT_ARG,                 /* 28, D3DTSS_RESULTARG */
2287     WINED3D_TSS_INVALID,                    /* 29, unused */
2288     WINED3D_TSS_INVALID,                    /* 30, unused */
2289     WINED3D_TSS_INVALID,                    /* 31, unused */
2290     WINED3D_TSS_CONSTANT,                   /* 32, D3DTSS_CONSTANT */
2291 };
2292 
2293 static HRESULT WINAPI d3d9_device_GetTextureStageState(IDirect3DDevice9Ex *iface,
2294         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
2295 {
2296     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2297 
2298     TRACE("iface %p, stage %u, state %#x, value %p.\n", iface, stage, state, value);
2299 
2300     if (state >= sizeof(tss_lookup) / sizeof(*tss_lookup))
2301     {
2302         WARN("Invalid state %#x passed.\n", state);
2303         return D3D_OK;
2304     }
2305 
2306     wined3d_mutex_lock();
2307     *value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, tss_lookup[state]);
2308     wined3d_mutex_unlock();
2309 
2310     return D3D_OK;
2311 }
2312 
2313 static HRESULT WINAPI d3d9_device_SetTextureStageState(IDirect3DDevice9Ex *iface,
2314         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
2315 {
2316     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2317 
2318     TRACE("iface %p, stage %u, state %#x, value %#x.\n", iface, stage, state, value);
2319 
2320     if (state >= sizeof(tss_lookup) / sizeof(*tss_lookup))
2321     {
2322         WARN("Invalid state %#x passed.\n", state);
2323         return D3D_OK;
2324     }
2325 
2326     wined3d_mutex_lock();
2327     wined3d_device_set_texture_stage_state(device->wined3d_device, stage, tss_lookup[state], value);
2328     wined3d_mutex_unlock();
2329 
2330     return D3D_OK;
2331 }
2332 
2333 static HRESULT WINAPI d3d9_device_GetSamplerState(IDirect3DDevice9Ex *iface,
2334         DWORD sampler, D3DSAMPLERSTATETYPE state, DWORD *value)
2335 {
2336     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2337 
2338     TRACE("iface %p, sampler %u, state %#x, value %p.\n", iface, sampler, state, value);
2339 
2340     wined3d_mutex_lock();
2341     *value = wined3d_device_get_sampler_state(device->wined3d_device, sampler, state);
2342     wined3d_mutex_unlock();
2343 
2344     return D3D_OK;
2345 }
2346 
2347 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_SetSamplerState(IDirect3DDevice9Ex *iface,
2348         DWORD sampler, D3DSAMPLERSTATETYPE state, DWORD value)
2349 {
2350     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2351 
2352     TRACE("iface %p, sampler %u, state %#x, value %#x.\n", iface, sampler, state, value);
2353 
2354     wined3d_mutex_lock();
2355     wined3d_device_set_sampler_state(device->wined3d_device, sampler, state, value);
2356     wined3d_mutex_unlock();
2357 
2358     return D3D_OK;
2359 }
2360 
2361 static HRESULT WINAPI d3d9_device_ValidateDevice(IDirect3DDevice9Ex *iface, DWORD *pass_count)
2362 {
2363     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2364     HRESULT hr;
2365 
2366     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
2367 
2368     wined3d_mutex_lock();
2369     hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
2370     wined3d_mutex_unlock();
2371 
2372     return hr;
2373 }
2374 
2375 static HRESULT WINAPI d3d9_device_SetPaletteEntries(IDirect3DDevice9Ex *iface,
2376         UINT palette_idx, const PALETTEENTRY *entries)
2377 {
2378     WARN("iface %p, palette_idx %u, entries %p unimplemented.\n", iface, palette_idx, entries);
2379 
2380     /* The d3d9 palette API is non-functional on Windows. Getters and setters are implemented,
2381      * and some drivers allow the creation of P8 surfaces. These surfaces can be copied to
2382      * other P8 surfaces with StretchRect, but cannot be converted to (A)RGB.
2383      *
2384      * Some older(dx7) cards may have support for P8 textures, but games cannot rely on this. */
2385     return D3D_OK;
2386 }
2387 
2388 static HRESULT WINAPI d3d9_device_GetPaletteEntries(IDirect3DDevice9Ex *iface,
2389         UINT palette_idx, PALETTEENTRY *entries)
2390 {
2391     FIXME("iface %p, palette_idx %u, entries %p unimplemented.\n", iface, palette_idx, entries);
2392 
2393     return D3DERR_INVALIDCALL;
2394 }
2395 
2396 static HRESULT WINAPI d3d9_device_SetCurrentTexturePalette(IDirect3DDevice9Ex *iface, UINT palette_idx)
2397 {
2398     WARN("iface %p, palette_idx %u unimplemented.\n", iface, palette_idx);
2399 
2400     return D3D_OK;
2401 }
2402 
2403 static HRESULT WINAPI d3d9_device_GetCurrentTexturePalette(IDirect3DDevice9Ex *iface, UINT *palette_idx)
2404 {
2405     FIXME("iface %p, palette_idx %p.\n", iface, palette_idx);
2406 
2407     return D3DERR_INVALIDCALL;
2408 }
2409 
2410 static HRESULT WINAPI d3d9_device_SetScissorRect(IDirect3DDevice9Ex *iface, const RECT *rect)
2411 {
2412     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2413 
2414     TRACE("iface %p, rect %p.\n", iface, rect);
2415 
2416     wined3d_mutex_lock();
2417     wined3d_device_set_scissor_rect(device->wined3d_device, rect);
2418     wined3d_mutex_unlock();
2419 
2420     return D3D_OK;
2421 }
2422 
2423 static HRESULT WINAPI d3d9_device_GetScissorRect(IDirect3DDevice9Ex *iface, RECT *rect)
2424 {
2425     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2426 
2427     TRACE("iface %p, rect %p.\n", iface, rect);
2428 
2429     wined3d_mutex_lock();
2430     wined3d_device_get_scissor_rect(device->wined3d_device, rect);
2431     wined3d_mutex_unlock();
2432 
2433     return D3D_OK;
2434 }
2435 
2436 static HRESULT WINAPI d3d9_device_SetSoftwareVertexProcessing(IDirect3DDevice9Ex *iface, BOOL software)
2437 {
2438     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2439 
2440     TRACE("iface %p, software %#x.\n", iface, software);
2441 
2442     wined3d_mutex_lock();
2443     wined3d_device_set_software_vertex_processing(device->wined3d_device, software);
2444     wined3d_mutex_unlock();
2445 
2446     return D3D_OK;
2447 }
2448 
2449 static BOOL WINAPI d3d9_device_GetSoftwareVertexProcessing(IDirect3DDevice9Ex *iface)
2450 {
2451     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2452     BOOL ret;
2453 
2454     TRACE("iface %p.\n", iface);
2455 
2456     wined3d_mutex_lock();
2457     ret = wined3d_device_get_software_vertex_processing(device->wined3d_device);
2458     wined3d_mutex_unlock();
2459 
2460     return ret;
2461 }
2462 
2463 static HRESULT WINAPI d3d9_device_SetNPatchMode(IDirect3DDevice9Ex *iface, float segment_count)
2464 {
2465     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2466     HRESULT hr;
2467 
2468     TRACE("iface %p, segment_count %.8e.\n", iface, segment_count);
2469 
2470     wined3d_mutex_lock();
2471     hr = wined3d_device_set_npatch_mode(device->wined3d_device, segment_count);
2472     wined3d_mutex_unlock();
2473 
2474     return hr;
2475 }
2476 
2477 static float WINAPI d3d9_device_GetNPatchMode(IDirect3DDevice9Ex *iface)
2478 {
2479     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2480     float ret;
2481 
2482     TRACE("iface %p.\n", iface);
2483 
2484     wined3d_mutex_lock();
2485     ret = wined3d_device_get_npatch_mode(device->wined3d_device);
2486     wined3d_mutex_unlock();
2487 
2488     return ret;
2489 }
2490 
2491 static HRESULT WINAPI d3d9_device_DrawPrimitive(IDirect3DDevice9Ex *iface,
2492         D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count)
2493 {
2494     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2495     HRESULT hr;
2496 
2497     TRACE("iface %p, primitive_type %#x, start_vertex %u, primitive_count %u.\n",
2498             iface, primitive_type, start_vertex, primitive_count);
2499 
2500     wined3d_mutex_lock();
2501     if (!device->has_vertex_declaration)
2502     {
2503         wined3d_mutex_unlock();
2504         WARN("Called without a valid vertex declaration set.\n");
2505         return D3DERR_INVALIDCALL;
2506     }
2507     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2508     hr = wined3d_device_draw_primitive(device->wined3d_device, start_vertex,
2509             vertex_count_from_primitive_count(primitive_type, primitive_count));
2510     wined3d_mutex_unlock();
2511 
2512     return hr;
2513 }
2514 
2515 static HRESULT WINAPI d3d9_device_DrawIndexedPrimitive(IDirect3DDevice9Ex *iface,
2516         D3DPRIMITIVETYPE primitive_type, INT base_vertex_idx, UINT min_vertex_idx,
2517         UINT vertex_count, UINT start_idx, UINT primitive_count)
2518 {
2519     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2520     HRESULT hr;
2521 
2522     TRACE("iface %p, primitive_type %#x, base_vertex_idx %u, min_vertex_idx %u, "
2523             "vertex_count %u, start_idx %u, primitive_count %u.\n",
2524             iface, primitive_type, base_vertex_idx, min_vertex_idx,
2525             vertex_count, start_idx, primitive_count);
2526 
2527     wined3d_mutex_lock();
2528     if (!device->has_vertex_declaration)
2529     {
2530         wined3d_mutex_unlock();
2531         WARN("Called without a valid vertex declaration set.\n");
2532         return D3DERR_INVALIDCALL;
2533     }
2534     wined3d_device_set_base_vertex_index(device->wined3d_device, base_vertex_idx);
2535     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2536     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, start_idx,
2537             vertex_count_from_primitive_count(primitive_type, primitive_count));
2538     wined3d_mutex_unlock();
2539 
2540     return hr;
2541 }
2542 
2543 /* The caller is responsible for wined3d locking */
2544 static HRESULT d3d9_device_prepare_vertex_buffer(struct d3d9_device *device, UINT min_size)
2545 {
2546     HRESULT hr;
2547 
2548     if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
2549     {
2550         UINT size = max(device->vertex_buffer_size * 2, min_size);
2551         struct wined3d_buffer *buffer;
2552 
2553         TRACE("Growing vertex buffer to %u bytes.\n", size);
2554 
2555         hr = wined3d_buffer_create_vb(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
2556                 WINED3D_POOL_DEFAULT, NULL, &d3d9_null_wined3d_parent_ops, &buffer);
2557         if (FAILED(hr))
2558         {
2559             ERR("(%p) wined3d_buffer_create_vb failed with hr = %08x.\n", device, hr);
2560             return hr;
2561         }
2562 
2563         if (device->vertex_buffer)
2564             wined3d_buffer_decref(device->vertex_buffer);
2565 
2566         device->vertex_buffer = buffer;
2567         device->vertex_buffer_size = size;
2568         device->vertex_buffer_pos = 0;
2569     }
2570     return D3D_OK;
2571 }
2572 
2573 static HRESULT WINAPI d3d9_device_DrawPrimitiveUP(IDirect3DDevice9Ex *iface,
2574         D3DPRIMITIVETYPE primitive_type, UINT primitive_count, const void *data, UINT stride)
2575 {
2576     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2577     HRESULT hr;
2578     UINT vtx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
2579     struct wined3d_map_desc wined3d_map_desc;
2580     struct wined3d_box wined3d_box = {0};
2581     UINT size = vtx_count * stride;
2582     struct wined3d_resource *vb;
2583     UINT vb_pos, align;
2584 
2585     TRACE("iface %p, primitive_type %#x, primitive_count %u, data %p, stride %u.\n",
2586             iface, primitive_type, primitive_count, data, stride);
2587 
2588     if (!primitive_count)
2589     {
2590         WARN("primitive_count is 0, returning D3D_OK\n");
2591         return D3D_OK;
2592     }
2593 
2594     wined3d_mutex_lock();
2595 
2596     if (!device->has_vertex_declaration)
2597     {
2598         wined3d_mutex_unlock();
2599         WARN("Called without a valid vertex declaration set.\n");
2600         return D3DERR_INVALIDCALL;
2601     }
2602 
2603     hr = d3d9_device_prepare_vertex_buffer(device, size);
2604     if (FAILED(hr))
2605         goto done;
2606 
2607     vb_pos = device->vertex_buffer_pos;
2608     align = vb_pos % stride;
2609     if (align) align = stride - align;
2610     if (vb_pos + size + align > device->vertex_buffer_size)
2611         vb_pos = 0;
2612     else
2613         vb_pos += align;
2614 
2615     wined3d_box.left = vb_pos;
2616     wined3d_box.right = vb_pos + size;
2617     vb = wined3d_buffer_get_resource(device->vertex_buffer);
2618     if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
2619             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD)))
2620         goto done;
2621     memcpy(wined3d_map_desc.data, data, size);
2622     wined3d_resource_unmap(vb, 0);
2623     device->vertex_buffer_pos = vb_pos + size;
2624 
2625     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
2626     if (FAILED(hr))
2627         goto done;
2628 
2629     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2630     hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vtx_count);
2631     wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
2632 
2633 done:
2634     wined3d_mutex_unlock();
2635     return hr;
2636 }
2637 
2638 /* The caller is responsible for wined3d locking */
2639 static HRESULT d3d9_device_prepare_index_buffer(struct d3d9_device *device, UINT min_size)
2640 {
2641     HRESULT hr;
2642 
2643     if (device->index_buffer_size < min_size || !device->index_buffer)
2644     {
2645         UINT size = max(device->index_buffer_size * 2, min_size);
2646         struct wined3d_buffer *buffer;
2647 
2648         TRACE("Growing index buffer to %u bytes.\n", size);
2649 
2650         hr = wined3d_buffer_create_ib(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
2651                 WINED3D_POOL_DEFAULT, NULL, &d3d9_null_wined3d_parent_ops, &buffer);
2652         if (FAILED(hr))
2653         {
2654             ERR("(%p) wined3d_buffer_create_ib failed with hr = %08x.\n", device, hr);
2655             return hr;
2656         }
2657 
2658         if (device->index_buffer)
2659             wined3d_buffer_decref(device->index_buffer);
2660 
2661         device->index_buffer = buffer;
2662         device->index_buffer_size = size;
2663         device->index_buffer_pos = 0;
2664     }
2665     return D3D_OK;
2666 }
2667 
2668 static HRESULT WINAPI d3d9_device_DrawIndexedPrimitiveUP(IDirect3DDevice9Ex *iface,
2669         D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
2670         UINT primitive_count, const void *index_data, D3DFORMAT index_format,
2671         const void *vertex_data, UINT vertex_stride)
2672 {
2673     UINT idx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
2674     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2675     UINT idx_fmt_size = index_format == D3DFMT_INDEX16 ? 2 : 4;
2676     UINT vtx_size = vertex_count * vertex_stride;
2677     UINT idx_size = idx_count * idx_fmt_size;
2678     struct wined3d_map_desc wined3d_map_desc;
2679     struct wined3d_box wined3d_box = {0};
2680     struct wined3d_resource *ib, *vb;
2681     UINT vb_pos, ib_pos, align;
2682     HRESULT hr;
2683 
2684     TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, primitive_count %u, "
2685             "index_data %p, index_format %#x, vertex_data %p, vertex_stride %u.\n",
2686             iface, primitive_type, min_vertex_idx, vertex_count, primitive_count,
2687             index_data, index_format, vertex_data, vertex_stride);
2688 
2689     if (!primitive_count)
2690     {
2691         WARN("primitive_count is 0, returning D3D_OK.\n");
2692         return D3D_OK;
2693     }
2694 
2695     wined3d_mutex_lock();
2696 
2697     if (!device->has_vertex_declaration)
2698     {
2699         wined3d_mutex_unlock();
2700         WARN("Called without a valid vertex declaration set.\n");
2701         return D3DERR_INVALIDCALL;
2702     }
2703 
2704     hr = d3d9_device_prepare_vertex_buffer(device, vtx_size);
2705     if (FAILED(hr))
2706         goto done;
2707 
2708     vb_pos = device->vertex_buffer_pos;
2709     align = vb_pos % vertex_stride;
2710     if (align) align = vertex_stride - align;
2711     if (vb_pos + vtx_size + align > device->vertex_buffer_size)
2712         vb_pos = 0;
2713     else
2714         vb_pos += align;
2715 
2716     wined3d_box.left = vb_pos;
2717     wined3d_box.right = vb_pos + vtx_size;
2718     vb = wined3d_buffer_get_resource(device->vertex_buffer);
2719     if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
2720             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD)))
2721         goto done;
2722     memcpy(wined3d_map_desc.data, (char *)vertex_data + min_vertex_idx * vertex_stride, vtx_size);
2723     wined3d_resource_unmap(vb, 0);
2724     device->vertex_buffer_pos = vb_pos + vtx_size;
2725 
2726     hr = d3d9_device_prepare_index_buffer(device, idx_size);
2727     if (FAILED(hr))
2728         goto done;
2729 
2730     ib_pos = device->index_buffer_pos;
2731     align = ib_pos % idx_fmt_size;
2732     if (align) align = idx_fmt_size - align;
2733     if (ib_pos + idx_size + align > device->index_buffer_size)
2734         ib_pos = 0;
2735     else
2736         ib_pos += align;
2737 
2738     wined3d_box.left = ib_pos;
2739     wined3d_box.right = ib_pos + idx_size;
2740     ib = wined3d_buffer_get_resource(device->index_buffer);
2741     if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
2742             ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD)))
2743         goto done;
2744     memcpy(wined3d_map_desc.data, index_data, idx_size);
2745     wined3d_resource_unmap(ib, 0);
2746     device->index_buffer_pos = ib_pos + idx_size;
2747 
2748     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, vertex_stride);
2749     if (FAILED(hr))
2750         goto done;
2751 
2752     wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer,
2753             wined3dformat_from_d3dformat(index_format), 0);
2754     wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / vertex_stride - min_vertex_idx);
2755 
2756     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2757     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / idx_fmt_size, idx_count);
2758 
2759     wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
2760     wined3d_device_set_index_buffer(device->wined3d_device, NULL, WINED3DFMT_UNKNOWN, 0);
2761     wined3d_device_set_base_vertex_index(device->wined3d_device, 0);
2762 
2763 done:
2764     wined3d_mutex_unlock();
2765     return hr;
2766 }
2767 
2768 static HRESULT WINAPI d3d9_device_ProcessVertices(IDirect3DDevice9Ex *iface,
2769         UINT src_start_idx, UINT dst_idx, UINT vertex_count, IDirect3DVertexBuffer9 *dst_buffer,
2770         IDirect3DVertexDeclaration9 *declaration, DWORD flags)
2771 {
2772     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2773     struct d3d9_vertexbuffer *dst_impl = unsafe_impl_from_IDirect3DVertexBuffer9(dst_buffer);
2774     struct d3d9_vertex_declaration *decl_impl = unsafe_impl_from_IDirect3DVertexDeclaration9(declaration);
2775     HRESULT hr;
2776 
2777     TRACE("iface %p, src_start_idx %u, dst_idx %u, vertex_count %u, dst_buffer %p, declaration %p, flags %#x.\n",
2778             iface, src_start_idx, dst_idx, vertex_count, dst_buffer, declaration, flags);
2779 
2780     wined3d_mutex_lock();
2781     hr = wined3d_device_process_vertices(device->wined3d_device, src_start_idx, dst_idx, vertex_count,
2782             dst_impl->wined3d_buffer, decl_impl ? decl_impl->wined3d_declaration : NULL,
2783             flags, dst_impl->fvf);
2784     wined3d_mutex_unlock();
2785 
2786     return hr;
2787 }
2788 
2789 static HRESULT WINAPI d3d9_device_CreateVertexDeclaration(IDirect3DDevice9Ex *iface,
2790         const D3DVERTEXELEMENT9 *elements, IDirect3DVertexDeclaration9 **declaration)
2791 {
2792     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2793     struct d3d9_vertex_declaration *object;
2794     HRESULT hr;
2795 
2796     TRACE("iface %p, elements %p, declaration %p.\n", iface, elements, declaration);
2797 
2798     if (!declaration)
2799     {
2800         WARN("Caller passed a NULL declaration, returning D3DERR_INVALIDCALL.\n");
2801         return D3DERR_INVALIDCALL;
2802     }
2803 
2804     if (SUCCEEDED(hr = d3d9_vertex_declaration_create(device, elements, &object)))
2805         *declaration = &object->IDirect3DVertexDeclaration9_iface;
2806 
2807     return hr;
2808 }
2809 
2810 static HRESULT WINAPI d3d9_device_SetVertexDeclaration(IDirect3DDevice9Ex *iface,
2811         IDirect3DVertexDeclaration9 *declaration)
2812 {
2813     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2814     struct d3d9_vertex_declaration *decl_impl = unsafe_impl_from_IDirect3DVertexDeclaration9(declaration);
2815 
2816     TRACE("iface %p, declaration %p.\n", iface, declaration);
2817 
2818     wined3d_mutex_lock();
2819     wined3d_device_set_vertex_declaration(device->wined3d_device,
2820             decl_impl ? decl_impl->wined3d_declaration : NULL);
2821     device->has_vertex_declaration = !!decl_impl;
2822     wined3d_mutex_unlock();
2823 
2824     return D3D_OK;
2825 }
2826 
2827 static HRESULT WINAPI d3d9_device_GetVertexDeclaration(IDirect3DDevice9Ex *iface,
2828         IDirect3DVertexDeclaration9 **declaration)
2829 {
2830     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2831     struct wined3d_vertex_declaration *wined3d_declaration;
2832     struct d3d9_vertex_declaration *declaration_impl;
2833 
2834     TRACE("iface %p, declaration %p.\n", iface, declaration);
2835 
2836     if (!declaration) return D3DERR_INVALIDCALL;
2837 
2838     wined3d_mutex_lock();
2839     if ((wined3d_declaration = wined3d_device_get_vertex_declaration(device->wined3d_device)))
2840     {
2841         declaration_impl = wined3d_vertex_declaration_get_parent(wined3d_declaration);
2842         *declaration = &declaration_impl->IDirect3DVertexDeclaration9_iface;
2843         IDirect3DVertexDeclaration9_AddRef(*declaration);
2844     }
2845     else
2846     {
2847         *declaration = NULL;
2848     }
2849     wined3d_mutex_unlock();
2850 
2851     TRACE("Returning %p.\n", *declaration);
2852     return D3D_OK;
2853 }
2854 
2855 static struct wined3d_vertex_declaration *device_get_fvf_declaration(struct d3d9_device *device, DWORD fvf)
2856 {
2857     struct wined3d_vertex_declaration *wined3d_declaration;
2858     struct fvf_declaration *fvf_decls = device->fvf_decls;
2859     struct d3d9_vertex_declaration *d3d9_declaration;
2860     D3DVERTEXELEMENT9 *elements;
2861     int p, low, high; /* deliberately signed */
2862     HRESULT hr;
2863 
2864     TRACE("Searching for declaration for fvf %08x... ", fvf);
2865 
2866     low = 0;
2867     high = device->fvf_decl_count - 1;
2868     while (low <= high)
2869     {
2870         p = (low + high) >> 1;
2871         TRACE("%d ", p);
2872 
2873         if (fvf_decls[p].fvf == fvf)
2874         {
2875             TRACE("found %p.\n", fvf_decls[p].decl);
2876             return fvf_decls[p].decl;
2877         }
2878 
2879         if (fvf_decls[p].fvf < fvf)
2880             low = p + 1;
2881         else
2882             high = p - 1;
2883     }
2884     TRACE("not found. Creating and inserting at position %d.\n", low);
2885 
2886     if (FAILED(hr = vdecl_convert_fvf(fvf, &elements)))
2887         return NULL;
2888 
2889     hr = d3d9_vertex_declaration_create(device, elements, &d3d9_declaration);
2890     HeapFree(GetProcessHeap(), 0, elements);
2891     if (FAILED(hr))
2892         return NULL;
2893 
2894     if (device->fvf_decl_size == device->fvf_decl_count)
2895     {
2896         UINT grow = max(device->fvf_decl_size / 2, 8);
2897 
2898         fvf_decls = HeapReAlloc(GetProcessHeap(), 0, fvf_decls, sizeof(*fvf_decls) * (device->fvf_decl_size + grow));
2899         if (!fvf_decls)
2900         {
2901             IDirect3DVertexDeclaration9_Release(&d3d9_declaration->IDirect3DVertexDeclaration9_iface);
2902             return NULL;
2903         }
2904         device->fvf_decls = fvf_decls;
2905         device->fvf_decl_size += grow;
2906     }
2907 
2908     d3d9_declaration->fvf = fvf;
2909     wined3d_declaration = d3d9_declaration->wined3d_declaration;
2910     wined3d_vertex_declaration_incref(wined3d_declaration);
2911     IDirect3DVertexDeclaration9_Release(&d3d9_declaration->IDirect3DVertexDeclaration9_iface);
2912 
2913     memmove(fvf_decls + low + 1, fvf_decls + low, sizeof(*fvf_decls) * (device->fvf_decl_count - low));
2914     fvf_decls[low].decl = wined3d_declaration;
2915     fvf_decls[low].fvf = fvf;
2916     ++device->fvf_decl_count;
2917 
2918     TRACE("Returning %p. %u declarations in array.\n", wined3d_declaration, device->fvf_decl_count);
2919 
2920     return wined3d_declaration;
2921 }
2922 
2923 static HRESULT WINAPI d3d9_device_SetFVF(IDirect3DDevice9Ex *iface, DWORD fvf)
2924 {
2925     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2926     struct wined3d_vertex_declaration *decl;
2927 
2928     TRACE("iface %p, fvf %#x.\n", iface, fvf);
2929 
2930     if (!fvf)
2931     {
2932         WARN("%#x is not a valid FVF.\n", fvf);
2933         return D3D_OK;
2934     }
2935 
2936     wined3d_mutex_lock();
2937     if (!(decl = device_get_fvf_declaration(device, fvf)))
2938     {
2939         wined3d_mutex_unlock();
2940         ERR("Failed to create a vertex declaration for fvf %#x.\n", fvf);
2941         return D3DERR_DRIVERINTERNALERROR;
2942     }
2943 
2944     wined3d_device_set_vertex_declaration(device->wined3d_device, decl);
2945     device->has_vertex_declaration = TRUE;
2946     wined3d_mutex_unlock();
2947 
2948     return D3D_OK;
2949 }
2950 
2951 static HRESULT WINAPI d3d9_device_GetFVF(IDirect3DDevice9Ex *iface, DWORD *fvf)
2952 {
2953     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2954     struct wined3d_vertex_declaration *wined3d_declaration;
2955     struct d3d9_vertex_declaration *d3d9_declaration;
2956 
2957     TRACE("iface %p, fvf %p.\n", iface, fvf);
2958 
2959     wined3d_mutex_lock();
2960     if ((wined3d_declaration = wined3d_device_get_vertex_declaration(device->wined3d_device)))
2961     {
2962         d3d9_declaration = wined3d_vertex_declaration_get_parent(wined3d_declaration);
2963         *fvf = d3d9_declaration->fvf;
2964     }
2965     else
2966     {
2967         *fvf = 0;
2968     }
2969     wined3d_mutex_unlock();
2970 
2971     TRACE("Returning FVF %#x.\n", *fvf);
2972 
2973     return D3D_OK;
2974 }
2975 
2976 static HRESULT WINAPI d3d9_device_CreateVertexShader(IDirect3DDevice9Ex *iface,
2977         const DWORD *byte_code, IDirect3DVertexShader9 **shader)
2978 {
2979     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
2980     struct d3d9_vertexshader *object;
2981     HRESULT hr;
2982 
2983     TRACE("iface %p, byte_code %p, shader %p.\n", iface, byte_code, shader);
2984 
2985     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2986     if (!object)
2987         return E_OUTOFMEMORY;
2988 
2989     hr = vertexshader_init(object, device, byte_code);
2990     if (FAILED(hr))
2991     {
2992         WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
2993         HeapFree(GetProcessHeap(), 0, object);
2994         return hr;
2995     }
2996 
2997     TRACE("Created vertex shader %p.\n", object);
2998     *shader = &object->IDirect3DVertexShader9_iface;
2999 
3000     return D3D_OK;
3001 }
3002 
3003 static HRESULT WINAPI d3d9_device_SetVertexShader(IDirect3DDevice9Ex *iface, IDirect3DVertexShader9 *shader)
3004 {
3005     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3006     struct d3d9_vertexshader *shader_obj = unsafe_impl_from_IDirect3DVertexShader9(shader);
3007 
3008     TRACE("iface %p, shader %p.\n", iface, shader);
3009 
3010     wined3d_mutex_lock();
3011     wined3d_device_set_vertex_shader(device->wined3d_device,
3012             shader_obj ? shader_obj->wined3d_shader : NULL);
3013     wined3d_mutex_unlock();
3014 
3015     return D3D_OK;
3016 }
3017 
3018 static HRESULT WINAPI d3d9_device_GetVertexShader(IDirect3DDevice9Ex *iface, IDirect3DVertexShader9 **shader)
3019 {
3020     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3021     struct d3d9_vertexshader *shader_impl;
3022     struct wined3d_shader *wined3d_shader;
3023 
3024     TRACE("iface %p, shader %p.\n", iface, shader);
3025 
3026     wined3d_mutex_lock();
3027     if ((wined3d_shader = wined3d_device_get_vertex_shader(device->wined3d_device)))
3028     {
3029         shader_impl = wined3d_shader_get_parent(wined3d_shader);
3030         *shader = &shader_impl->IDirect3DVertexShader9_iface;
3031         IDirect3DVertexShader9_AddRef(*shader);
3032     }
3033     else
3034     {
3035         *shader = NULL;
3036     }
3037     wined3d_mutex_unlock();
3038 
3039     TRACE("Returning %p.\n", *shader);
3040 
3041     return D3D_OK;
3042 }
3043 
3044 static HRESULT WINAPI d3d9_device_SetVertexShaderConstantF(IDirect3DDevice9Ex *iface,
3045         UINT reg_idx, const float *data, UINT count)
3046 {
3047     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3048     HRESULT hr;
3049 
3050     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3051 
3052     if (reg_idx + count > D3D9_MAX_VERTEX_SHADER_CONSTANTF)
3053     {
3054         WARN("Trying to access %u constants, but d3d9 only supports %u\n",
3055              reg_idx + count, D3D9_MAX_VERTEX_SHADER_CONSTANTF);
3056         return D3DERR_INVALIDCALL;
3057     }
3058 
3059     wined3d_mutex_lock();
3060     hr = wined3d_device_set_vs_consts_f(device->wined3d_device,
3061             reg_idx, count, (const struct wined3d_vec4 *)data);
3062     wined3d_mutex_unlock();
3063 
3064     return hr;
3065 }
3066 
3067 static HRESULT WINAPI d3d9_device_GetVertexShaderConstantF(IDirect3DDevice9Ex *iface,
3068         UINT reg_idx, float *data, UINT count)
3069 {
3070     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3071     HRESULT hr;
3072 
3073     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3074 
3075     if (reg_idx + count > D3D9_MAX_VERTEX_SHADER_CONSTANTF)
3076     {
3077         WARN("Trying to access %u constants, but d3d9 only supports %u\n",
3078              reg_idx + count, D3D9_MAX_VERTEX_SHADER_CONSTANTF);
3079         return D3DERR_INVALIDCALL;
3080     }
3081 
3082     wined3d_mutex_lock();
3083     hr = wined3d_device_get_vs_consts_f(device->wined3d_device,
3084             reg_idx, count, (struct wined3d_vec4 *)data);
3085     wined3d_mutex_unlock();
3086 
3087     return hr;
3088 }
3089 
3090 static HRESULT WINAPI d3d9_device_SetVertexShaderConstantI(IDirect3DDevice9Ex *iface,
3091         UINT reg_idx, const int *data, UINT count)
3092 {
3093     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3094     HRESULT hr;
3095 
3096     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3097 
3098     wined3d_mutex_lock();
3099     hr = wined3d_device_set_vs_consts_i(device->wined3d_device,
3100             reg_idx, count, (const struct wined3d_ivec4 *)data);
3101     wined3d_mutex_unlock();
3102 
3103     return hr;
3104 }
3105 
3106 static HRESULT WINAPI d3d9_device_GetVertexShaderConstantI(IDirect3DDevice9Ex *iface,
3107         UINT reg_idx, int *data, UINT count)
3108 {
3109     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3110     HRESULT hr;
3111 
3112     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3113 
3114     wined3d_mutex_lock();
3115     hr = wined3d_device_get_vs_consts_i(device->wined3d_device,
3116             reg_idx, count, (struct wined3d_ivec4 *)data);
3117     wined3d_mutex_unlock();
3118 
3119     return hr;
3120 }
3121 
3122 static HRESULT WINAPI d3d9_device_SetVertexShaderConstantB(IDirect3DDevice9Ex *iface,
3123         UINT reg_idx, const BOOL *data, UINT count)
3124 {
3125     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3126     HRESULT hr;
3127 
3128     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3129 
3130     wined3d_mutex_lock();
3131     hr = wined3d_device_set_vs_consts_b(device->wined3d_device, reg_idx, count, data);
3132     wined3d_mutex_unlock();
3133 
3134     return hr;
3135 }
3136 
3137 static HRESULT WINAPI d3d9_device_GetVertexShaderConstantB(IDirect3DDevice9Ex *iface,
3138         UINT reg_idx, BOOL *data, UINT count)
3139 {
3140     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3141     HRESULT hr;
3142 
3143     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3144 
3145     wined3d_mutex_lock();
3146     hr = wined3d_device_get_vs_consts_b(device->wined3d_device, reg_idx, count, data);
3147     wined3d_mutex_unlock();
3148 
3149     return hr;
3150 }
3151 
3152 static HRESULT WINAPI d3d9_device_SetStreamSource(IDirect3DDevice9Ex *iface,
3153         UINT stream_idx, IDirect3DVertexBuffer9 *buffer, UINT offset, UINT stride)
3154 {
3155     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3156     struct d3d9_vertexbuffer *buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer9(buffer);
3157     HRESULT hr;
3158 
3159     TRACE("iface %p, stream_idx %u, buffer %p, offset %u, stride %u.\n",
3160             iface, stream_idx, buffer, offset, stride);
3161 
3162     wined3d_mutex_lock();
3163     hr = wined3d_device_set_stream_source(device->wined3d_device, stream_idx,
3164             buffer_impl ? buffer_impl->wined3d_buffer : NULL, offset, stride);
3165     wined3d_mutex_unlock();
3166 
3167     return hr;
3168 }
3169 
3170 static HRESULT WINAPI d3d9_device_GetStreamSource(IDirect3DDevice9Ex *iface,
3171         UINT stream_idx, IDirect3DVertexBuffer9 **buffer, UINT *offset, UINT *stride)
3172 {
3173     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3174     struct d3d9_vertexbuffer *buffer_impl;
3175     struct wined3d_buffer *wined3d_buffer;
3176     HRESULT hr;
3177 
3178     TRACE("iface %p, stream_idx %u, buffer %p, offset %p, stride %p.\n",
3179             iface, stream_idx, buffer, offset, stride);
3180 
3181     if (!buffer)
3182         return D3DERR_INVALIDCALL;
3183 
3184     wined3d_mutex_lock();
3185     hr = wined3d_device_get_stream_source(device->wined3d_device, stream_idx, &wined3d_buffer, offset, stride);
3186     if (SUCCEEDED(hr) && wined3d_buffer)
3187     {
3188         buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
3189         *buffer = &buffer_impl->IDirect3DVertexBuffer9_iface;
3190         IDirect3DVertexBuffer9_AddRef(*buffer);
3191     }
3192     else
3193     {
3194         if (FAILED(hr))
3195             FIXME("Call to GetStreamSource failed %p %p\n", offset, stride);
3196         *buffer = NULL;
3197     }
3198     wined3d_mutex_unlock();
3199 
3200     return hr;
3201 }
3202 
3203 static HRESULT WINAPI d3d9_device_SetStreamSourceFreq(IDirect3DDevice9Ex *iface, UINT stream_idx, UINT freq)
3204 {
3205     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3206     HRESULT hr;
3207 
3208     TRACE("iface %p, stream_idx %u, freq %u.\n", iface, stream_idx, freq);
3209 
3210     wined3d_mutex_lock();
3211     hr = wined3d_device_set_stream_source_freq(device->wined3d_device, stream_idx, freq);
3212     wined3d_mutex_unlock();
3213 
3214     return hr;
3215 }
3216 
3217 static HRESULT WINAPI d3d9_device_GetStreamSourceFreq(IDirect3DDevice9Ex *iface, UINT stream_idx, UINT *freq)
3218 {
3219     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3220     HRESULT hr;
3221 
3222     TRACE("iface %p, stream_idx %u, freq %p.\n", iface, stream_idx, freq);
3223 
3224     wined3d_mutex_lock();
3225     hr = wined3d_device_get_stream_source_freq(device->wined3d_device, stream_idx, freq);
3226     wined3d_mutex_unlock();
3227 
3228     return hr;
3229 }
3230 
3231 static HRESULT WINAPI d3d9_device_SetIndices(IDirect3DDevice9Ex *iface, IDirect3DIndexBuffer9 *buffer)
3232 {
3233     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3234     struct d3d9_indexbuffer *ib = unsafe_impl_from_IDirect3DIndexBuffer9(buffer);
3235 
3236     TRACE("iface %p, buffer %p.\n", iface, buffer);
3237 
3238     wined3d_mutex_lock();
3239     wined3d_device_set_index_buffer(device->wined3d_device,
3240             ib ? ib->wined3d_buffer : NULL, ib ? ib->format : WINED3DFMT_UNKNOWN, 0);
3241     wined3d_mutex_unlock();
3242 
3243     return D3D_OK;
3244 }
3245 
3246 static HRESULT WINAPI d3d9_device_GetIndices(IDirect3DDevice9Ex *iface, IDirect3DIndexBuffer9 **buffer)
3247 {
3248     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3249     enum wined3d_format_id wined3d_format;
3250     struct wined3d_buffer *wined3d_buffer;
3251     struct d3d9_indexbuffer *buffer_impl;
3252 
3253     TRACE("iface %p, buffer %p.\n", iface, buffer);
3254 
3255     if (!buffer)
3256         return D3DERR_INVALIDCALL;
3257 
3258     wined3d_mutex_lock();
3259     if ((wined3d_buffer = wined3d_device_get_index_buffer(device->wined3d_device, &wined3d_format, NULL)))
3260     {
3261         buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
3262         *buffer = &buffer_impl->IDirect3DIndexBuffer9_iface;
3263         IDirect3DIndexBuffer9_AddRef(*buffer);
3264     }
3265     else
3266     {
3267         *buffer = NULL;
3268     }
3269     wined3d_mutex_unlock();
3270 
3271     return D3D_OK;
3272 }
3273 
3274 static HRESULT WINAPI d3d9_device_CreatePixelShader(IDirect3DDevice9Ex *iface,
3275         const DWORD *byte_code, IDirect3DPixelShader9 **shader)
3276 {
3277     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3278     struct d3d9_pixelshader *object;
3279     HRESULT hr;
3280 
3281     TRACE("iface %p, byte_code %p, shader %p.\n", iface, byte_code, shader);
3282 
3283     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3284     if (!object)
3285     {
3286         FIXME("Failed to allocate pixel shader memory.\n");
3287         return E_OUTOFMEMORY;
3288     }
3289 
3290     hr = pixelshader_init(object, device, byte_code);
3291     if (FAILED(hr))
3292     {
3293         WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
3294         HeapFree(GetProcessHeap(), 0, object);
3295         return hr;
3296     }
3297 
3298     TRACE("Created pixel shader %p.\n", object);
3299     *shader = &object->IDirect3DPixelShader9_iface;
3300 
3301     return D3D_OK;
3302 }
3303 
3304 static HRESULT WINAPI d3d9_device_SetPixelShader(IDirect3DDevice9Ex *iface, IDirect3DPixelShader9 *shader)
3305 {
3306     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3307     struct d3d9_pixelshader *shader_obj = unsafe_impl_from_IDirect3DPixelShader9(shader);
3308 
3309     TRACE("iface %p, shader %p.\n", iface, shader);
3310 
3311     wined3d_mutex_lock();
3312     wined3d_device_set_pixel_shader(device->wined3d_device,
3313             shader_obj ? shader_obj->wined3d_shader : NULL);
3314     wined3d_mutex_unlock();
3315 
3316     return D3D_OK;
3317 }
3318 
3319 static HRESULT WINAPI d3d9_device_GetPixelShader(IDirect3DDevice9Ex *iface, IDirect3DPixelShader9 **shader)
3320 {
3321     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3322     struct d3d9_pixelshader *shader_impl;
3323     struct wined3d_shader *wined3d_shader;
3324 
3325     TRACE("iface %p, shader %p.\n", iface, shader);
3326 
3327     if (!shader) return D3DERR_INVALIDCALL;
3328 
3329     wined3d_mutex_lock();
3330     if ((wined3d_shader = wined3d_device_get_pixel_shader(device->wined3d_device)))
3331     {
3332         shader_impl = wined3d_shader_get_parent(wined3d_shader);
3333         *shader = &shader_impl->IDirect3DPixelShader9_iface;
3334         IDirect3DPixelShader9_AddRef(*shader);
3335     }
3336     else
3337     {
3338         *shader = NULL;
3339     }
3340     wined3d_mutex_unlock();
3341 
3342     TRACE("Returning %p.\n", *shader);
3343 
3344     return D3D_OK;
3345 }
3346 
3347 static HRESULT WINAPI d3d9_device_SetPixelShaderConstantF(IDirect3DDevice9Ex *iface,
3348         UINT reg_idx, const float *data, UINT count)
3349 {
3350     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3351     HRESULT hr;
3352 
3353     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3354 
3355     wined3d_mutex_lock();
3356     hr = wined3d_device_set_ps_consts_f(device->wined3d_device,
3357             reg_idx, count, (const struct wined3d_vec4 *)data);
3358     wined3d_mutex_unlock();
3359 
3360     return hr;
3361 }
3362 
3363 static HRESULT WINAPI d3d9_device_GetPixelShaderConstantF(IDirect3DDevice9Ex *iface,
3364         UINT reg_idx, float *data, UINT count)
3365 {
3366     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3367     HRESULT hr;
3368 
3369     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3370 
3371     wined3d_mutex_lock();
3372     hr = wined3d_device_get_ps_consts_f(device->wined3d_device,
3373             reg_idx, count, (struct wined3d_vec4 *)data);
3374     wined3d_mutex_unlock();
3375 
3376     return hr;
3377 }
3378 
3379 static HRESULT WINAPI d3d9_device_SetPixelShaderConstantI(IDirect3DDevice9Ex *iface,
3380         UINT reg_idx, const int *data, UINT count)
3381 {
3382     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3383     HRESULT hr;
3384 
3385     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3386 
3387     wined3d_mutex_lock();
3388     hr = wined3d_device_set_ps_consts_i(device->wined3d_device,
3389             reg_idx, count, (const struct wined3d_ivec4 *)data);
3390     wined3d_mutex_unlock();
3391 
3392     return hr;
3393 }
3394 
3395 static HRESULT WINAPI d3d9_device_GetPixelShaderConstantI(IDirect3DDevice9Ex *iface,
3396         UINT reg_idx, int *data, UINT count)
3397 {
3398     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3399     HRESULT hr;
3400 
3401     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3402 
3403     wined3d_mutex_lock();
3404     hr = wined3d_device_get_ps_consts_i(device->wined3d_device,
3405             reg_idx, count, (struct wined3d_ivec4 *)data);
3406     wined3d_mutex_unlock();
3407 
3408     return hr;
3409 }
3410 
3411 static HRESULT WINAPI d3d9_device_SetPixelShaderConstantB(IDirect3DDevice9Ex *iface,
3412         UINT reg_idx, const BOOL *data, UINT count)
3413 {
3414     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3415     HRESULT hr;
3416 
3417     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3418 
3419     wined3d_mutex_lock();
3420     hr = wined3d_device_set_ps_consts_b(device->wined3d_device, reg_idx, count, data);
3421     wined3d_mutex_unlock();
3422 
3423     return hr;
3424 }
3425 
3426 static HRESULT WINAPI d3d9_device_GetPixelShaderConstantB(IDirect3DDevice9Ex *iface,
3427         UINT reg_idx, BOOL *data, UINT count)
3428 {
3429     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3430     HRESULT hr;
3431 
3432     TRACE("iface %p, reg_idx %u, data %p, count %u.\n", iface, reg_idx, data, count);
3433 
3434     wined3d_mutex_lock();
3435     hr = wined3d_device_get_ps_consts_b(device->wined3d_device, reg_idx, count, data);
3436     wined3d_mutex_unlock();
3437 
3438     return hr;
3439 }
3440 
3441 static HRESULT WINAPI d3d9_device_DrawRectPatch(IDirect3DDevice9Ex *iface, UINT handle,
3442         const float *segment_count, const D3DRECTPATCH_INFO *patch_info)
3443 {
3444     FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
3445             iface, handle, segment_count, patch_info);
3446     return D3D_OK;
3447 }
3448 
3449 static HRESULT WINAPI d3d9_device_DrawTriPatch(IDirect3DDevice9Ex *iface, UINT handle,
3450         const float *segment_count, const D3DTRIPATCH_INFO *patch_info)
3451 {
3452     FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
3453             iface, handle, segment_count, patch_info);
3454     return D3D_OK;
3455 }
3456 
3457 static HRESULT WINAPI d3d9_device_DeletePatch(IDirect3DDevice9Ex *iface, UINT handle)
3458 {
3459     FIXME("iface %p, handle %#x unimplemented.\n", iface, handle);
3460     return D3DERR_INVALIDCALL;
3461 }
3462 
3463 static HRESULT WINAPI d3d9_device_CreateQuery(IDirect3DDevice9Ex *iface, D3DQUERYTYPE type, IDirect3DQuery9 **query)
3464 {
3465     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3466     struct d3d9_query *object;
3467     HRESULT hr;
3468 
3469     TRACE("iface %p, type %#x, query %p.\n", iface, type, query);
3470 
3471     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3472     if (!object)
3473         return E_OUTOFMEMORY;
3474 
3475     hr = query_init(object, device, type);
3476     if (FAILED(hr))
3477     {
3478         WARN("Failed to initialize query, hr %#x.\n", hr);
3479         HeapFree(GetProcessHeap(), 0, object);
3480         return hr;
3481     }
3482 
3483     TRACE("Created query %p.\n", object);
3484     if (query) *query = &object->IDirect3DQuery9_iface;
3485     else IDirect3DQuery9_Release(&object->IDirect3DQuery9_iface);
3486 
3487     return D3D_OK;
3488 }
3489 
3490 static HRESULT WINAPI d3d9_device_SetConvolutionMonoKernel(IDirect3DDevice9Ex *iface,
3491         UINT width, UINT height, float *rows, float *columns)
3492 {
3493     FIXME("iface %p, width %u, height %u, rows %p, columns %p stub!\n",
3494             iface, width, height, rows, columns);
3495 
3496     return E_NOTIMPL;
3497 }
3498 
3499 static HRESULT WINAPI d3d9_device_ComposeRects(IDirect3DDevice9Ex *iface,
3500         IDirect3DSurface9 *src_surface, IDirect3DSurface9 *dst_surface, IDirect3DVertexBuffer9 *src_descs,
3501         UINT rect_count, IDirect3DVertexBuffer9 *dst_descs, D3DCOMPOSERECTSOP operation, INT offset_x, INT offset_y)
3502 {
3503     FIXME("iface %p, src_surface %p, dst_surface %p, src_descs %p, rect_count %u, "
3504             "dst_descs %p, operation %#x, offset_x %u, offset_y %u stub!\n",
3505             iface, src_surface, dst_surface, src_descs, rect_count,
3506             dst_descs, operation, offset_x, offset_y);
3507 
3508     return E_NOTIMPL;
3509 }
3510 
3511 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_PresentEx(IDirect3DDevice9Ex *iface,
3512         const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override,
3513         const RGNDATA *dirty_region, DWORD flags)
3514 {
3515     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3516     UINT i;
3517     HRESULT hr;
3518 
3519     TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p, flags %#x.\n",
3520             iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect),
3521             dst_window_override, dirty_region, flags);
3522 
3523     if (device->device_state != D3D9_DEVICE_STATE_OK)
3524         return S_PRESENT_OCCLUDED;
3525 
3526     if (dirty_region)
3527         FIXME("Ignoring dirty_region %p.\n", dirty_region);
3528 
3529     wined3d_mutex_lock();
3530     for (i = 0; i < device->implicit_swapchain_count; ++i)
3531     {
3532         if (FAILED(hr = wined3d_swapchain_present(device->implicit_swapchains[i]->wined3d_swapchain,
3533                 src_rect, dst_rect, dst_window_override, flags)))
3534         {
3535             wined3d_mutex_unlock();
3536             return hr;
3537         }
3538     }
3539     wined3d_mutex_unlock();
3540 
3541     return D3D_OK;
3542 }
3543 
3544 static HRESULT WINAPI d3d9_device_GetGPUThreadPriority(IDirect3DDevice9Ex *iface, INT *priority)
3545 {
3546     FIXME("iface %p, priority %p stub!\n", iface, priority);
3547 
3548     return E_NOTIMPL;
3549 }
3550 
3551 static HRESULT WINAPI d3d9_device_SetGPUThreadPriority(IDirect3DDevice9Ex *iface, INT priority)
3552 {
3553     FIXME("iface %p, priority %d stub!\n", iface, priority);
3554 
3555     return E_NOTIMPL;
3556 }
3557 
3558 static HRESULT WINAPI d3d9_device_WaitForVBlank(IDirect3DDevice9Ex *iface, UINT swapchain_idx)
3559 {
3560     FIXME("iface %p, swapchain_idx %u stub!\n", iface, swapchain_idx);
3561 
3562     return E_NOTIMPL;
3563 }
3564 
3565 static HRESULT WINAPI d3d9_device_CheckResourceResidency(IDirect3DDevice9Ex *iface,
3566         IDirect3DResource9 **resources, UINT32 resource_count)
3567 {
3568     FIXME("iface %p, resources %p, resource_count %u stub!\n",
3569             iface, resources, resource_count);
3570 
3571     return E_NOTIMPL;
3572 }
3573 
3574 static HRESULT WINAPI d3d9_device_SetMaximumFrameLatency(IDirect3DDevice9Ex *iface, UINT max_latency)
3575 {
3576     TRACE("iface %p, max_latency %u.\n", iface, max_latency);
3577 
3578     if (max_latency)
3579         FIXME("Ignoring max_latency %u.\n", max_latency);
3580 
3581     return S_OK;
3582 }
3583 
3584 static HRESULT WINAPI d3d9_device_GetMaximumFrameLatency(IDirect3DDevice9Ex *iface, UINT *max_latency)
3585 {
3586     FIXME("iface %p, max_latency %p stub!\n", iface, max_latency);
3587 
3588     *max_latency = 2;
3589 
3590     return E_NOTIMPL;
3591 }
3592 
3593 static HRESULT WINAPI d3d9_device_CheckDeviceState(IDirect3DDevice9Ex *iface, HWND dst_window)
3594 {
3595     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3596     struct wined3d_swapchain_desc swapchain_desc;
3597 
3598     TRACE("iface %p, dst_window %p.\n", iface, dst_window);
3599 
3600     wined3d_mutex_lock();
3601     wined3d_swapchain_get_desc(device->implicit_swapchains[0]->wined3d_swapchain, &swapchain_desc);
3602     wined3d_mutex_unlock();
3603 
3604     if (swapchain_desc.windowed)
3605         return D3D_OK;
3606 
3607     /* FIXME: This is actually supposed to check if any other device is in
3608      * fullscreen mode. */
3609     if (dst_window != swapchain_desc.device_window)
3610         return device->device_state == D3D9_DEVICE_STATE_OK ? S_PRESENT_OCCLUDED : D3D_OK;
3611 
3612     return device->device_state == D3D9_DEVICE_STATE_OK ? D3D_OK : S_PRESENT_OCCLUDED;
3613 }
3614 
3615 static HRESULT WINAPI d3d9_device_CreateRenderTargetEx(IDirect3DDevice9Ex *iface,
3616         UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality,
3617         BOOL lockable, IDirect3DSurface9 **surface, HANDLE *shared_handle, DWORD usage)
3618 {
3619     FIXME("iface %p, width %u, height %u, format %#x, multisample_type %#x, multisample_quality %u, "
3620             "lockable %#x, surface %p, shared_handle %p, usage %#x stub!\n",
3621             iface, width, height, format, multisample_type, multisample_quality,
3622             lockable, surface, shared_handle, usage);
3623 
3624     *surface = NULL;
3625     if (shared_handle)
3626         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
3627 
3628     return E_NOTIMPL;
3629 }
3630 
3631 static HRESULT WINAPI d3d9_device_CreateOffscreenPlainSurfaceEx(IDirect3DDevice9Ex *iface,
3632         UINT width, UINT height, D3DFORMAT format, D3DPOOL pool, IDirect3DSurface9 **surface,
3633         HANDLE *shared_handle, DWORD usage)
3634 {
3635     FIXME("iface %p, width %u, height %u, format %#x, pool %#x, surface %p, shared_handle %p, usage %#x stub!\n",
3636             iface, width, height, format, pool, surface, shared_handle, usage);
3637 
3638     return E_NOTIMPL;
3639 }
3640 
3641 static HRESULT WINAPI d3d9_device_CreateDepthStencilSurfaceEx(IDirect3DDevice9Ex *iface,
3642         UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality,
3643         BOOL discard, IDirect3DSurface9 **surface, HANDLE *shared_handle, DWORD usage)
3644 {
3645     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3646     DWORD flags = WINED3D_TEXTURE_CREATE_MAPPABLE;
3647 
3648     TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, multisample_quality %u, "
3649             "discard %#x, surface %p, shared_handle %p, usage %#x.\n",
3650             iface, width, height, format, multisample_type, multisample_quality,
3651             discard, surface, shared_handle, usage);
3652 
3653     if (usage & D3DUSAGE_DEPTHSTENCIL)
3654     {
3655         WARN("Invalid usage %#x.\n", usage);
3656         return D3DERR_INVALIDCALL;
3657     }
3658 
3659     if (shared_handle)
3660         FIXME("Resource sharing not implemented, *shared_handle %p.\n", *shared_handle);
3661 
3662     if (discard)
3663         flags |= WINED3D_TEXTURE_CREATE_DISCARD;
3664 
3665     *surface = NULL;
3666     return d3d9_device_create_surface(device, width, height, format, flags, surface,
3667             D3DUSAGE_DEPTHSTENCIL | usage, D3DPOOL_DEFAULT, multisample_type, multisample_quality, NULL);
3668 }
3669 
3670 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_ResetEx(IDirect3DDevice9Ex *iface,
3671         D3DPRESENT_PARAMETERS *present_parameters, D3DDISPLAYMODEEX *mode)
3672 {
3673     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3674 
3675     TRACE("iface %p, present_parameters %p, mode %p.\n", iface, present_parameters, mode);
3676 
3677     if (!present_parameters->Windowed == !mode)
3678     {
3679         WARN("Mode can be passed if and only if Windowed is FALSE.\n");
3680         return D3DERR_INVALIDCALL;
3681     }
3682 
3683     if (mode && (mode->Width != present_parameters->BackBufferWidth
3684             || mode->Height != present_parameters->BackBufferHeight))
3685     {
3686         WARN("Mode and back buffer mismatch (mode %ux%u, backbuffer %ux%u).\n",
3687                 mode->Width, mode->Height,
3688                 present_parameters->BackBufferWidth, present_parameters->BackBufferHeight);
3689         return D3DERR_INVALIDCALL;
3690     }
3691 
3692     return d3d9_device_reset(device, present_parameters, mode);
3693 }
3694 
3695 static HRESULT WINAPI d3d9_device_GetDisplayModeEx(IDirect3DDevice9Ex *iface,
3696         UINT swapchain_idx, D3DDISPLAYMODEEX *mode, D3DDISPLAYROTATION *rotation)
3697 {
3698     struct d3d9_device *device = impl_from_IDirect3DDevice9Ex(iface);
3699     struct wined3d_display_mode wined3d_mode;
3700     HRESULT hr;
3701 
3702     TRACE("iface %p, swapchain_idx %u, mode %p, rotation %p.\n",
3703             iface, swapchain_idx, mode, rotation);
3704 
3705     if (mode->Size != sizeof(*mode))
3706         return D3DERR_INVALIDCALL;
3707 
3708     wined3d_mutex_lock();
3709     hr = wined3d_device_get_display_mode(device->wined3d_device, swapchain_idx, &wined3d_mode,
3710             (enum wined3d_display_rotation *)rotation);
3711     wined3d_mutex_unlock();
3712 
3713     if (SUCCEEDED(hr))
3714     {
3715         mode->Width = wined3d_mode.width;
3716         mode->Height = wined3d_mode.height;
3717         mode->RefreshRate = wined3d_mode.refresh_rate;
3718         mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
3719         mode->ScanLineOrdering = wined3d_mode.scanline_ordering;
3720     }
3721 
3722     return hr;
3723 }
3724 
3725 static const struct IDirect3DDevice9ExVtbl d3d9_device_vtbl =
3726 {
3727     /* IUnknown */
3728     d3d9_device_QueryInterface,
3729     d3d9_device_AddRef,
3730     d3d9_device_Release,
3731     /* IDirect3DDevice9 */
3732     d3d9_device_TestCooperativeLevel,
3733     d3d9_device_GetAvailableTextureMem,
3734     d3d9_device_EvictManagedResources,
3735     d3d9_device_GetDirect3D,
3736     d3d9_device_GetDeviceCaps,
3737     d3d9_device_GetDisplayMode,
3738     d3d9_device_GetCreationParameters,
3739     d3d9_device_SetCursorProperties,
3740     d3d9_device_SetCursorPosition,
3741     d3d9_device_ShowCursor,
3742     d3d9_device_CreateAdditionalSwapChain,
3743     d3d9_device_GetSwapChain,
3744     d3d9_device_GetNumberOfSwapChains,
3745     d3d9_device_Reset,
3746     d3d9_device_Present,
3747     d3d9_device_GetBackBuffer,
3748     d3d9_device_GetRasterStatus,
3749     d3d9_device_SetDialogBoxMode,
3750     d3d9_device_SetGammaRamp,
3751     d3d9_device_GetGammaRamp,
3752     d3d9_device_CreateTexture,
3753     d3d9_device_CreateVolumeTexture,
3754     d3d9_device_CreateCubeTexture,
3755     d3d9_device_CreateVertexBuffer,
3756     d3d9_device_CreateIndexBuffer,
3757     d3d9_device_CreateRenderTarget,
3758     d3d9_device_CreateDepthStencilSurface,
3759     d3d9_device_UpdateSurface,
3760     d3d9_device_UpdateTexture,
3761     d3d9_device_GetRenderTargetData,
3762     d3d9_device_GetFrontBufferData,
3763     d3d9_device_StretchRect,
3764     d3d9_device_ColorFill,
3765     d3d9_device_CreateOffscreenPlainSurface,
3766     d3d9_device_SetRenderTarget,
3767     d3d9_device_GetRenderTarget,
3768     d3d9_device_SetDepthStencilSurface,
3769     d3d9_device_GetDepthStencilSurface,
3770     d3d9_device_BeginScene,
3771     d3d9_device_EndScene,
3772     d3d9_device_Clear,
3773     d3d9_device_SetTransform,
3774     d3d9_device_GetTransform,
3775     d3d9_device_MultiplyTransform,
3776     d3d9_device_SetViewport,
3777     d3d9_device_GetViewport,
3778     d3d9_device_SetMaterial,
3779     d3d9_device_GetMaterial,
3780     d3d9_device_SetLight,
3781     d3d9_device_GetLight,
3782     d3d9_device_LightEnable,
3783     d3d9_device_GetLightEnable,
3784     d3d9_device_SetClipPlane,
3785     d3d9_device_GetClipPlane,
3786     d3d9_device_SetRenderState,
3787     d3d9_device_GetRenderState,
3788     d3d9_device_CreateStateBlock,
3789     d3d9_device_BeginStateBlock,
3790     d3d9_device_EndStateBlock,
3791     d3d9_device_SetClipStatus,
3792     d3d9_device_GetClipStatus,
3793     d3d9_device_GetTexture,
3794     d3d9_device_SetTexture,
3795     d3d9_device_GetTextureStageState,
3796     d3d9_device_SetTextureStageState,
3797     d3d9_device_GetSamplerState,
3798     d3d9_device_SetSamplerState,
3799     d3d9_device_ValidateDevice,
3800     d3d9_device_SetPaletteEntries,
3801     d3d9_device_GetPaletteEntries,
3802     d3d9_device_SetCurrentTexturePalette,
3803     d3d9_device_GetCurrentTexturePalette,
3804     d3d9_device_SetScissorRect,
3805     d3d9_device_GetScissorRect,
3806     d3d9_device_SetSoftwareVertexProcessing,
3807     d3d9_device_GetSoftwareVertexProcessing,
3808     d3d9_device_SetNPatchMode,
3809     d3d9_device_GetNPatchMode,
3810     d3d9_device_DrawPrimitive,
3811     d3d9_device_DrawIndexedPrimitive,
3812     d3d9_device_DrawPrimitiveUP,
3813     d3d9_device_DrawIndexedPrimitiveUP,
3814     d3d9_device_ProcessVertices,
3815     d3d9_device_CreateVertexDeclaration,
3816     d3d9_device_SetVertexDeclaration,
3817     d3d9_device_GetVertexDeclaration,
3818     d3d9_device_SetFVF,
3819     d3d9_device_GetFVF,
3820     d3d9_device_CreateVertexShader,
3821     d3d9_device_SetVertexShader,
3822     d3d9_device_GetVertexShader,
3823     d3d9_device_SetVertexShaderConstantF,
3824     d3d9_device_GetVertexShaderConstantF,
3825     d3d9_device_SetVertexShaderConstantI,
3826     d3d9_device_GetVertexShaderConstantI,
3827     d3d9_device_SetVertexShaderConstantB,
3828     d3d9_device_GetVertexShaderConstantB,
3829     d3d9_device_SetStreamSource,
3830     d3d9_device_GetStreamSource,
3831     d3d9_device_SetStreamSourceFreq,
3832     d3d9_device_GetStreamSourceFreq,
3833     d3d9_device_SetIndices,
3834     d3d9_device_GetIndices,
3835     d3d9_device_CreatePixelShader,
3836     d3d9_device_SetPixelShader,
3837     d3d9_device_GetPixelShader,
3838     d3d9_device_SetPixelShaderConstantF,
3839     d3d9_device_GetPixelShaderConstantF,
3840     d3d9_device_SetPixelShaderConstantI,
3841     d3d9_device_GetPixelShaderConstantI,
3842     d3d9_device_SetPixelShaderConstantB,
3843     d3d9_device_GetPixelShaderConstantB,
3844     d3d9_device_DrawRectPatch,
3845     d3d9_device_DrawTriPatch,
3846     d3d9_device_DeletePatch,
3847     d3d9_device_CreateQuery,
3848     /* IDirect3DDevice9Ex */
3849     d3d9_device_SetConvolutionMonoKernel,
3850     d3d9_device_ComposeRects,
3851     d3d9_device_PresentEx,
3852     d3d9_device_GetGPUThreadPriority,
3853     d3d9_device_SetGPUThreadPriority,
3854     d3d9_device_WaitForVBlank,
3855     d3d9_device_CheckResourceResidency,
3856     d3d9_device_SetMaximumFrameLatency,
3857     d3d9_device_GetMaximumFrameLatency,
3858     d3d9_device_CheckDeviceState,
3859     d3d9_device_CreateRenderTargetEx,
3860     d3d9_device_CreateOffscreenPlainSurfaceEx,
3861     d3d9_device_CreateDepthStencilSurfaceEx,
3862     d3d9_device_ResetEx,
3863     d3d9_device_GetDisplayModeEx,
3864 };
3865 
3866 static inline struct d3d9_device *device_from_device_parent(struct wined3d_device_parent *device_parent)
3867 {
3868     return CONTAINING_RECORD(device_parent, struct d3d9_device, device_parent);
3869 }
3870 
3871 static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
3872         struct wined3d_device *device)
3873 {
3874     TRACE("device_parent %p, device %p.\n", device_parent, device);
3875 }
3876 
3877 static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent)
3878 {
3879     TRACE("device_parent %p.\n", device_parent);
3880 }
3881 
3882 static void CDECL device_parent_activate(struct wined3d_device_parent *device_parent, BOOL activate)
3883 {
3884     struct d3d9_device *device = device_from_device_parent(device_parent);
3885 
3886     TRACE("device_parent %p, activate %#x.\n", device_parent, activate);
3887 
3888     if (!device->d3d_parent)
3889         return;
3890 
3891     if (!activate)
3892         InterlockedCompareExchange(&device->device_state, D3D9_DEVICE_STATE_LOST, D3D9_DEVICE_STATE_OK);
3893     else if (device->d3d_parent->extended)
3894         InterlockedCompareExchange(&device->device_state, D3D9_DEVICE_STATE_OK, D3D9_DEVICE_STATE_LOST);
3895     else
3896         InterlockedCompareExchange(&device->device_state, D3D9_DEVICE_STATE_NOT_RESET, D3D9_DEVICE_STATE_LOST);
3897 }
3898 
3899 static HRESULT CDECL device_parent_surface_created(struct wined3d_device_parent *device_parent,
3900         struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
3901         void **parent, const struct wined3d_parent_ops **parent_ops)
3902 {
3903     struct d3d9_surface *d3d_surface;
3904 
3905     TRACE("device_parent %p, wined3d_texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
3906             device_parent, wined3d_texture, sub_resource_idx, parent, parent_ops);
3907 
3908     if (!(d3d_surface = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d3d_surface))))
3909         return E_OUTOFMEMORY;
3910 
3911     surface_init(d3d_surface, wined3d_texture, sub_resource_idx, parent_ops);
3912     *parent = d3d_surface;
3913     TRACE("Created surface %p.\n", d3d_surface);
3914 
3915     return D3D_OK;
3916 }
3917 
3918 static HRESULT CDECL device_parent_volume_created(struct wined3d_device_parent *device_parent,
3919         struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
3920         void **parent, const struct wined3d_parent_ops **parent_ops)
3921 {
3922     struct d3d9_volume *d3d_volume;
3923 
3924     TRACE("device_parent %p, texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
3925             device_parent, wined3d_texture, sub_resource_idx, parent, parent_ops);
3926 
3927     if (!(d3d_volume = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*d3d_volume))))
3928         return E_OUTOFMEMORY;
3929 
3930     volume_init(d3d_volume, wined3d_texture, sub_resource_idx, parent_ops);
3931     *parent = d3d_volume;
3932     TRACE("Created volume %p.\n", d3d_volume);
3933 
3934     return D3D_OK;
3935 }
3936 
3937 static HRESULT CDECL device_parent_create_swapchain_texture(struct wined3d_device_parent *device_parent,
3938         void *container_parent, const struct wined3d_resource_desc *desc, DWORD texture_flags,
3939         struct wined3d_texture **texture)
3940 {
3941     struct d3d9_device *device = device_from_device_parent(device_parent);
3942     struct d3d9_surface *d3d_surface;
3943     HRESULT hr;
3944 
3945     TRACE("device_parent %p, container_parent %p, desc %p, texture flags %#x, texture %p.\n",
3946             device_parent, container_parent, desc, texture_flags, texture);
3947 
3948     if (container_parent == device_parent)
3949         container_parent = &device->IDirect3DDevice9Ex_iface;
3950 
3951     if (is_gdi_compat_wined3dformat(desc->format))
3952         texture_flags |= WINED3D_TEXTURE_CREATE_GET_DC;
3953 
3954     if (FAILED(hr = wined3d_texture_create(device->wined3d_device, desc, 1, 1,
3955             texture_flags | WINED3D_TEXTURE_CREATE_MAPPABLE, NULL, container_parent,
3956             &d3d9_null_wined3d_parent_ops, texture)))
3957     {
3958         WARN("Failed to create texture, hr %#x.\n", hr);
3959         return hr;
3960     }
3961 
3962     d3d_surface = wined3d_texture_get_sub_resource_parent(*texture, 0);
3963     d3d_surface->parent_device = &device->IDirect3DDevice9Ex_iface;
3964 
3965     return hr;
3966 }
3967 
3968 static HRESULT CDECL device_parent_create_swapchain(struct wined3d_device_parent *device_parent,
3969         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain **swapchain)
3970 {
3971     struct d3d9_device *device = device_from_device_parent(device_parent);
3972     struct d3d9_swapchain *d3d_swapchain;
3973     HRESULT hr;
3974 
3975     TRACE("device_parent %p, desc %p, swapchain %p\n", device_parent, desc, swapchain);
3976 
3977     hr = d3d9_swapchain_create(device, desc, &d3d_swapchain);
3978     if (FAILED(hr))
3979     {
3980         WARN("Failed to create swapchain, hr %#x.\n", hr);
3981         *swapchain = NULL;
3982         return hr;
3983     }
3984 
3985     *swapchain = d3d_swapchain->wined3d_swapchain;
3986     wined3d_swapchain_incref(*swapchain);
3987     IDirect3DSwapChain9Ex_Release(&d3d_swapchain->IDirect3DSwapChain9Ex_iface);
3988 
3989     return hr;
3990 }
3991 
3992 static const struct wined3d_device_parent_ops d3d9_wined3d_device_parent_ops =
3993 {
3994     device_parent_wined3d_device_created,
3995     device_parent_mode_changed,
3996     device_parent_activate,
3997     device_parent_surface_created,
3998     device_parent_volume_created,
3999     device_parent_create_swapchain_texture,
4000     device_parent_create_swapchain,
4001 };
4002 
4003 static void setup_fpu(void)
4004 {
4005 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
4006     WORD cw;
4007     __asm__ volatile ("fnstcw %0" : "=m" (cw));
4008     cw = (cw & ~0xf3f) | 0x3f;
4009     __asm__ volatile ("fldcw %0" : : "m" (cw));
4010 #elif defined(__i386__) && defined(_MSC_VER)
4011     WORD cw;
4012     __asm fnstcw cw;
4013     cw = (cw & ~0xf3f) | 0x3f;
4014     __asm fldcw cw;
4015 #else
4016     FIXME("FPU setup not implemented for this platform.\n");
4017 #endif
4018 }
4019 
4020 HRESULT device_init(struct d3d9_device *device, struct d3d9 *parent, struct wined3d *wined3d,
4021         UINT adapter, D3DDEVTYPE device_type, HWND focus_window, DWORD flags,
4022         D3DPRESENT_PARAMETERS *parameters, D3DDISPLAYMODEEX *mode)
4023 {
4024     struct wined3d_swapchain_desc *swapchain_desc;
4025     unsigned i, count = 1;
4026     WINED3DCAPS caps;
4027     HRESULT hr;
4028 
4029     if (mode)
4030         FIXME("Ignoring display mode.\n");
4031 
4032     device->IDirect3DDevice9Ex_iface.lpVtbl = &d3d9_device_vtbl;
4033     device->device_parent.ops = &d3d9_wined3d_device_parent_ops;
4034     device->refcount = 1;
4035 
4036     if (!(flags & D3DCREATE_FPU_PRESERVE)) setup_fpu();
4037 
4038     wined3d_mutex_lock();
4039     if (FAILED(hr = wined3d_device_create(wined3d, adapter, device_type, focus_window, flags, 4,
4040             &device->device_parent, &device->wined3d_device)))
4041     {
4042         WARN("Failed to create wined3d device, hr %#x.\n", hr);
4043         wined3d_mutex_unlock();
4044         return hr;
4045     }
4046 
4047     wined3d_get_device_caps(wined3d, adapter, device_type, &caps);
4048     device->max_user_clip_planes = caps.MaxUserClipPlanes;
4049     if (flags & D3DCREATE_ADAPTERGROUP_DEVICE)
4050         count = caps.NumberOfAdaptersInGroup;
4051 
4052     if (flags & D3DCREATE_MULTITHREADED)
4053         wined3d_device_set_multithreaded(device->wined3d_device);
4054 
4055     if (!parameters->Windowed)
4056     {
4057         if (!focus_window)
4058             focus_window = parameters->hDeviceWindow;
4059         if (FAILED(hr = wined3d_device_acquire_focus_window(device->wined3d_device, focus_window)))
4060         {
4061             ERR("Failed to acquire focus window, hr %#x.\n", hr);
4062             wined3d_device_decref(device->wined3d_device);
4063             wined3d_mutex_unlock();
4064             return hr;
4065         }
4066 
4067         for (i = 0; i < count; ++i)
4068         {
4069             HWND device_window = parameters[i].hDeviceWindow;
4070 
4071             if (!device_window) device_window = focus_window;
4072             wined3d_device_setup_fullscreen_window(device->wined3d_device, device_window,
4073                     parameters[i].BackBufferWidth,
4074                     parameters[i].BackBufferHeight);
4075         }
4076     }
4077 
4078     swapchain_desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain_desc) * count);
4079     if (!swapchain_desc)
4080     {
4081         ERR("Failed to allocate wined3d parameters.\n");
4082         wined3d_device_release_focus_window(device->wined3d_device);
4083         wined3d_device_decref(device->wined3d_device);
4084         wined3d_mutex_unlock();
4085         return E_OUTOFMEMORY;
4086     }
4087 
4088     for (i = 0; i < count; ++i)
4089     {
4090         if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc[i], &parameters[i],
4091                 parent->extended))
4092         {
4093             wined3d_device_release_focus_window(device->wined3d_device);
4094             wined3d_device_decref(device->wined3d_device);
4095             HeapFree(GetProcessHeap(), 0, swapchain_desc);
4096             wined3d_mutex_unlock();
4097             return D3DERR_INVALIDCALL;
4098         }
4099     }
4100 
4101     if (FAILED(hr = wined3d_device_init_3d(device->wined3d_device, swapchain_desc)))
4102     {
4103         WARN("Failed to initialize 3D, hr %#x.\n", hr);
4104         wined3d_device_release_focus_window(device->wined3d_device);
4105         HeapFree(GetProcessHeap(), 0, swapchain_desc);
4106         wined3d_device_decref(device->wined3d_device);
4107         wined3d_mutex_unlock();
4108         return hr;
4109     }
4110 
4111     wined3d_device_set_render_state(device->wined3d_device,
4112             WINED3D_RS_ZENABLE, !!swapchain_desc->enable_auto_depth_stencil);
4113 
4114     if (FAILED(hr = d3d9_device_get_swapchains(device)))
4115     {
4116         wined3d_device_uninit_3d(device->wined3d_device);
4117         wined3d_device_release_focus_window(device->wined3d_device);
4118         wined3d_device_decref(device->wined3d_device);
4119         wined3d_mutex_unlock();
4120         return E_OUTOFMEMORY;
4121     }
4122 
4123     for (i = 0; i < count; ++i)
4124     {
4125         present_parameters_from_wined3d_swapchain_desc(&parameters[i], &swapchain_desc[i]);
4126     }
4127 
4128     wined3d_mutex_unlock();
4129 
4130     HeapFree(GetProcessHeap(), 0, swapchain_desc);
4131 
4132     /* Initialize the converted declaration array. This creates a valid pointer
4133      * and when adding decls HeapReAlloc() can be used without further checking. */
4134     device->fvf_decls = HeapAlloc(GetProcessHeap(), 0, 0);
4135     if (!device->fvf_decls)
4136     {
4137         ERR("Failed to allocate FVF vertex declaration map memory.\n");
4138         wined3d_mutex_lock();
4139         HeapFree(GetProcessHeap(), 0, device->implicit_swapchains);
4140         wined3d_device_uninit_3d(device->wined3d_device);
4141         wined3d_device_release_focus_window(device->wined3d_device);
4142         wined3d_device_decref(device->wined3d_device);
4143         wined3d_mutex_unlock();
4144         return E_OUTOFMEMORY;
4145     }
4146 
4147     IDirect3D9Ex_AddRef(&parent->IDirect3D9Ex_iface);
4148     device->d3d_parent = parent;
4149 
4150     return D3D_OK;
4151 }
4152