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