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