xref: /reactos/dll/directx/wine/d3d8/device.c (revision 8786e12d)
1 /*
2  * IDirect3DDevice8 implementation
3  *
4  * Copyright 2002-2004 Jason Edmeades
5  * Copyright 2004 Christian Costa
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "config.h"
23 
24 #include <math.h>
25 #include <stdarg.h>
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "wingdi.h"
31 #include "wine/debug.h"
32 
33 #include "d3d8_private.h"
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d8);
36 
37 static void STDMETHODCALLTYPE d3d8_null_wined3d_object_destroyed(void *parent) {}
38 
39 static const struct wined3d_parent_ops d3d8_null_wined3d_parent_ops =
40 {
41     d3d8_null_wined3d_object_destroyed,
42 };
43 
44 D3DFORMAT d3dformat_from_wined3dformat(enum wined3d_format_id format)
45 {
46     BYTE *c = (BYTE *)&format;
47 
48     /* Don't translate FOURCC formats */
49     if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;
50 
51     switch(format)
52     {
53         case WINED3DFMT_UNKNOWN: return D3DFMT_UNKNOWN;
54         case WINED3DFMT_B8G8R8_UNORM: return D3DFMT_R8G8B8;
55         case WINED3DFMT_B8G8R8A8_UNORM: return D3DFMT_A8R8G8B8;
56         case WINED3DFMT_B8G8R8X8_UNORM: return D3DFMT_X8R8G8B8;
57         case WINED3DFMT_B5G6R5_UNORM: return D3DFMT_R5G6B5;
58         case WINED3DFMT_B5G5R5X1_UNORM: return D3DFMT_X1R5G5B5;
59         case WINED3DFMT_B5G5R5A1_UNORM: return D3DFMT_A1R5G5B5;
60         case WINED3DFMT_B4G4R4A4_UNORM: return D3DFMT_A4R4G4B4;
61         case WINED3DFMT_B2G3R3_UNORM: return D3DFMT_R3G3B2;
62         case WINED3DFMT_A8_UNORM: return D3DFMT_A8;
63         case WINED3DFMT_B2G3R3A8_UNORM: return D3DFMT_A8R3G3B2;
64         case WINED3DFMT_B4G4R4X4_UNORM: return D3DFMT_X4R4G4B4;
65         case WINED3DFMT_R10G10B10A2_UNORM: return D3DFMT_A2B10G10R10;
66         case WINED3DFMT_R16G16_UNORM: return D3DFMT_G16R16;
67         case WINED3DFMT_P8_UINT_A8_UNORM: return D3DFMT_A8P8;
68         case WINED3DFMT_P8_UINT: return D3DFMT_P8;
69         case WINED3DFMT_L8_UNORM: return D3DFMT_L8;
70         case WINED3DFMT_L8A8_UNORM: return D3DFMT_A8L8;
71         case WINED3DFMT_L4A4_UNORM: return D3DFMT_A4L4;
72         case WINED3DFMT_R8G8_SNORM: return D3DFMT_V8U8;
73         case WINED3DFMT_R5G5_SNORM_L6_UNORM: return D3DFMT_L6V5U5;
74         case WINED3DFMT_R8G8_SNORM_L8X8_UNORM: return D3DFMT_X8L8V8U8;
75         case WINED3DFMT_R8G8B8A8_SNORM: return D3DFMT_Q8W8V8U8;
76         case WINED3DFMT_R16G16_SNORM: return D3DFMT_V16U16;
77         case WINED3DFMT_R10G11B11_SNORM: return D3DFMT_W11V11U10;
78         case WINED3DFMT_R10G10B10_SNORM_A2_UNORM: return D3DFMT_A2W10V10U10;
79         case WINED3DFMT_D16_LOCKABLE: return D3DFMT_D16_LOCKABLE;
80         case WINED3DFMT_D32_UNORM: return D3DFMT_D32;
81         case WINED3DFMT_S1_UINT_D15_UNORM: return D3DFMT_D15S1;
82         case WINED3DFMT_D24_UNORM_S8_UINT: return D3DFMT_D24S8;
83         case WINED3DFMT_X8D24_UNORM: return D3DFMT_D24X8;
84         case WINED3DFMT_S4X4_UINT_D24_UNORM: return D3DFMT_D24X4S4;
85         case WINED3DFMT_D16_UNORM: return D3DFMT_D16;
86         case WINED3DFMT_R16_UINT: return D3DFMT_INDEX16;
87         case WINED3DFMT_R32_UINT: return D3DFMT_INDEX32;
88         default:
89             FIXME("Unhandled wined3d format %#x.\n", format);
90             return D3DFMT_UNKNOWN;
91     }
92 }
93 
94 enum wined3d_format_id wined3dformat_from_d3dformat(D3DFORMAT format)
95 {
96     BYTE *c = (BYTE *)&format;
97 
98     /* Don't translate FOURCC formats */
99     if (isprint(c[0]) && isprint(c[1]) && isprint(c[2]) && isprint(c[3])) return format;
100 
101     switch(format)
102     {
103         case D3DFMT_UNKNOWN: return WINED3DFMT_UNKNOWN;
104         case D3DFMT_R8G8B8: return WINED3DFMT_B8G8R8_UNORM;
105         case D3DFMT_A8R8G8B8: return WINED3DFMT_B8G8R8A8_UNORM;
106         case D3DFMT_X8R8G8B8: return WINED3DFMT_B8G8R8X8_UNORM;
107         case D3DFMT_R5G6B5: return WINED3DFMT_B5G6R5_UNORM;
108         case D3DFMT_X1R5G5B5: return WINED3DFMT_B5G5R5X1_UNORM;
109         case D3DFMT_A1R5G5B5: return WINED3DFMT_B5G5R5A1_UNORM;
110         case D3DFMT_A4R4G4B4: return WINED3DFMT_B4G4R4A4_UNORM;
111         case D3DFMT_R3G3B2: return WINED3DFMT_B2G3R3_UNORM;
112         case D3DFMT_A8: return WINED3DFMT_A8_UNORM;
113         case D3DFMT_A8R3G3B2: return WINED3DFMT_B2G3R3A8_UNORM;
114         case D3DFMT_X4R4G4B4: return WINED3DFMT_B4G4R4X4_UNORM;
115         case D3DFMT_A2B10G10R10: return WINED3DFMT_R10G10B10A2_UNORM;
116         case D3DFMT_G16R16: return WINED3DFMT_R16G16_UNORM;
117         case D3DFMT_A8P8: return WINED3DFMT_P8_UINT_A8_UNORM;
118         case D3DFMT_P8: return WINED3DFMT_P8_UINT;
119         case D3DFMT_L8: return WINED3DFMT_L8_UNORM;
120         case D3DFMT_A8L8: return WINED3DFMT_L8A8_UNORM;
121         case D3DFMT_A4L4: return WINED3DFMT_L4A4_UNORM;
122         case D3DFMT_V8U8: return WINED3DFMT_R8G8_SNORM;
123         case D3DFMT_L6V5U5: return WINED3DFMT_R5G5_SNORM_L6_UNORM;
124         case D3DFMT_X8L8V8U8: return WINED3DFMT_R8G8_SNORM_L8X8_UNORM;
125         case D3DFMT_Q8W8V8U8: return WINED3DFMT_R8G8B8A8_SNORM;
126         case D3DFMT_V16U16: return WINED3DFMT_R16G16_SNORM;
127         case D3DFMT_W11V11U10: return WINED3DFMT_R10G11B11_SNORM;
128         case D3DFMT_A2W10V10U10: return WINED3DFMT_R10G10B10_SNORM_A2_UNORM;
129         case D3DFMT_D16_LOCKABLE: return WINED3DFMT_D16_LOCKABLE;
130         case D3DFMT_D32: return WINED3DFMT_D32_UNORM;
131         case D3DFMT_D15S1: return WINED3DFMT_S1_UINT_D15_UNORM;
132         case D3DFMT_D24S8: return WINED3DFMT_D24_UNORM_S8_UINT;
133         case D3DFMT_D24X8: return WINED3DFMT_X8D24_UNORM;
134         case D3DFMT_D24X4S4: return WINED3DFMT_S4X4_UINT_D24_UNORM;
135         case D3DFMT_D16: return WINED3DFMT_D16_UNORM;
136         case D3DFMT_INDEX16: return WINED3DFMT_R16_UINT;
137         case D3DFMT_INDEX32: return WINED3DFMT_R32_UINT;
138         default:
139             FIXME("Unhandled D3DFORMAT %#x.\n", format);
140             return WINED3DFMT_UNKNOWN;
141     }
142 }
143 
144 unsigned int wined3dmapflags_from_d3dmapflags(unsigned int flags)
145 {
146     static const unsigned int handled = D3DLOCK_NOSYSLOCK
147             | D3DLOCK_NOOVERWRITE
148             | D3DLOCK_DISCARD
149             | D3DLOCK_NO_DIRTY_UPDATE;
150     unsigned int wined3d_flags;
151 
152     wined3d_flags = flags & handled;
153     if (!(flags & (D3DLOCK_NOOVERWRITE | D3DLOCK_DISCARD)))
154         wined3d_flags |= WINED3D_MAP_READ;
155     if (!(flags & D3DLOCK_READONLY))
156         wined3d_flags |= WINED3D_MAP_WRITE;
157     if (!(wined3d_flags & (WINED3D_MAP_READ | WINED3D_MAP_WRITE)))
158         wined3d_flags |= WINED3D_MAP_READ | WINED3D_MAP_WRITE;
159     flags &= ~(handled | D3DLOCK_READONLY);
160 
161     if (flags)
162         FIXME("Unhandled flags %#x.\n", flags);
163 
164     return wined3d_flags;
165 }
166 
167 static UINT vertex_count_from_primitive_count(D3DPRIMITIVETYPE primitive_type, UINT primitive_count)
168 {
169     switch (primitive_type)
170     {
171         case D3DPT_POINTLIST:
172             return primitive_count;
173 
174         case D3DPT_LINELIST:
175             return primitive_count * 2;
176 
177         case D3DPT_LINESTRIP:
178             return primitive_count + 1;
179 
180         case D3DPT_TRIANGLELIST:
181             return primitive_count * 3;
182 
183         case D3DPT_TRIANGLESTRIP:
184         case D3DPT_TRIANGLEFAN:
185             return primitive_count + 2;
186 
187         default:
188             FIXME("Unhandled primitive type %#x.\n", primitive_type);
189             return 0;
190     }
191 }
192 
193 static D3DSWAPEFFECT d3dswapeffect_from_wined3dswapeffect(enum wined3d_swap_effect effect)
194 {
195     switch (effect)
196     {
197         case WINED3D_SWAP_EFFECT_DISCARD:
198             return D3DSWAPEFFECT_DISCARD;
199         case WINED3D_SWAP_EFFECT_SEQUENTIAL:
200             return D3DSWAPEFFECT_FLIP;
201         case WINED3D_SWAP_EFFECT_COPY:
202             return D3DSWAPEFFECT_COPY;
203         case WINED3D_SWAP_EFFECT_COPY_VSYNC:
204             return D3DSWAPEFFECT_COPY_VSYNC;
205         default:
206             FIXME("Unhandled swap effect %#x.\n", effect);
207             return D3DSWAPEFFECT_FLIP;
208     }
209 }
210 
211 static void present_parameters_from_wined3d_swapchain_desc(D3DPRESENT_PARAMETERS *present_parameters,
212         const struct wined3d_swapchain_desc *swapchain_desc, DWORD presentation_interval)
213 {
214     present_parameters->BackBufferWidth = swapchain_desc->backbuffer_width;
215     present_parameters->BackBufferHeight = swapchain_desc->backbuffer_height;
216     present_parameters->BackBufferFormat = d3dformat_from_wined3dformat(swapchain_desc->backbuffer_format);
217     present_parameters->BackBufferCount = swapchain_desc->backbuffer_count;
218     present_parameters->MultiSampleType = swapchain_desc->multisample_type;
219     present_parameters->SwapEffect = d3dswapeffect_from_wined3dswapeffect(swapchain_desc->swap_effect);
220     present_parameters->hDeviceWindow = swapchain_desc->device_window;
221     present_parameters->Windowed = swapchain_desc->windowed;
222     present_parameters->EnableAutoDepthStencil = swapchain_desc->enable_auto_depth_stencil;
223     present_parameters->AutoDepthStencilFormat
224             = d3dformat_from_wined3dformat(swapchain_desc->auto_depth_stencil_format);
225     present_parameters->Flags = swapchain_desc->flags & D3DPRESENTFLAGS_MASK;
226     present_parameters->FullScreen_RefreshRateInHz = swapchain_desc->refresh_rate;
227     present_parameters->FullScreen_PresentationInterval = presentation_interval;
228 }
229 
230 static enum wined3d_swap_effect wined3dswapeffect_from_d3dswapeffect(D3DSWAPEFFECT effect)
231 {
232     switch (effect)
233     {
234         case D3DSWAPEFFECT_DISCARD:
235             return WINED3D_SWAP_EFFECT_DISCARD;
236         case D3DSWAPEFFECT_FLIP:
237             return WINED3D_SWAP_EFFECT_SEQUENTIAL;
238         case D3DSWAPEFFECT_COPY:
239             return WINED3D_SWAP_EFFECT_COPY;
240         case D3DSWAPEFFECT_COPY_VSYNC:
241             return WINED3D_SWAP_EFFECT_COPY_VSYNC;
242         default:
243             FIXME("Unhandled swap effect %#x.\n", effect);
244             return WINED3D_SWAP_EFFECT_SEQUENTIAL;
245     }
246 }
247 
248 static enum wined3d_swap_interval wined3dswapinterval_from_d3d(DWORD interval)
249 {
250     switch (interval)
251     {
252         case D3DPRESENT_INTERVAL_IMMEDIATE:
253             return WINED3D_SWAP_INTERVAL_IMMEDIATE;
254         case D3DPRESENT_INTERVAL_ONE:
255             return WINED3D_SWAP_INTERVAL_ONE;
256         case D3DPRESENT_INTERVAL_TWO:
257             return WINED3D_SWAP_INTERVAL_TWO;
258         case D3DPRESENT_INTERVAL_THREE:
259             return WINED3D_SWAP_INTERVAL_THREE;
260         case D3DPRESENT_INTERVAL_FOUR:
261             return WINED3D_SWAP_INTERVAL_FOUR;
262         default:
263             FIXME("Unhandled presentation interval %#x.\n", interval);
264         case D3DPRESENT_INTERVAL_DEFAULT:
265             return WINED3D_SWAP_INTERVAL_DEFAULT;
266     }
267 }
268 
269 static BOOL wined3d_swapchain_desc_from_present_parameters(struct wined3d_swapchain_desc *swapchain_desc,
270         const D3DPRESENT_PARAMETERS *present_parameters)
271 {
272     if (!present_parameters->SwapEffect || present_parameters->SwapEffect > D3DSWAPEFFECT_COPY_VSYNC)
273     {
274         WARN("Invalid swap effect %u passed.\n", present_parameters->SwapEffect);
275         return FALSE;
276     }
277     if (present_parameters->BackBufferCount > 3
278             || ((present_parameters->SwapEffect == D3DSWAPEFFECT_COPY
279             || present_parameters->SwapEffect == D3DSWAPEFFECT_COPY_VSYNC)
280             && present_parameters->BackBufferCount > 1))
281     {
282         WARN("Invalid backbuffer count %u.\n", present_parameters->BackBufferCount);
283         return FALSE;
284     }
285     switch (present_parameters->FullScreen_PresentationInterval)
286     {
287         case D3DPRESENT_INTERVAL_DEFAULT:
288         case D3DPRESENT_INTERVAL_ONE:
289         case D3DPRESENT_INTERVAL_TWO:
290         case D3DPRESENT_INTERVAL_THREE:
291         case D3DPRESENT_INTERVAL_FOUR:
292         case D3DPRESENT_INTERVAL_IMMEDIATE:
293             break;
294         default:
295             WARN("Invalid presentation interval %#x.\n",
296                     present_parameters->FullScreen_PresentationInterval);
297             return FALSE;
298     }
299 
300     swapchain_desc->backbuffer_width = present_parameters->BackBufferWidth;
301     swapchain_desc->backbuffer_height = present_parameters->BackBufferHeight;
302     swapchain_desc->backbuffer_format = wined3dformat_from_d3dformat(present_parameters->BackBufferFormat);
303     swapchain_desc->backbuffer_count = max(1, present_parameters->BackBufferCount);
304     swapchain_desc->backbuffer_usage = WINED3DUSAGE_RENDERTARGET;
305     swapchain_desc->multisample_type = present_parameters->MultiSampleType;
306     swapchain_desc->multisample_quality = 0; /* d3d9 only */
307     swapchain_desc->swap_effect = wined3dswapeffect_from_d3dswapeffect(present_parameters->SwapEffect);
308     swapchain_desc->device_window = present_parameters->hDeviceWindow;
309     swapchain_desc->windowed = present_parameters->Windowed;
310     swapchain_desc->enable_auto_depth_stencil = present_parameters->EnableAutoDepthStencil;
311     swapchain_desc->auto_depth_stencil_format
312             = wined3dformat_from_d3dformat(present_parameters->AutoDepthStencilFormat);
313     swapchain_desc->flags
314             = (present_parameters->Flags & D3DPRESENTFLAGS_MASK) | WINED3D_SWAPCHAIN_ALLOW_MODE_SWITCH;
315     swapchain_desc->refresh_rate = present_parameters->FullScreen_RefreshRateInHz;
316     swapchain_desc->auto_restore_display_mode = TRUE;
317 
318     if (present_parameters->Flags & ~D3DPRESENTFLAGS_MASK)
319         FIXME("Unhandled flags %#x.\n", present_parameters->Flags & ~D3DPRESENTFLAGS_MASK);
320 
321     return TRUE;
322 }
323 
324 void d3dcaps_from_wined3dcaps(D3DCAPS8 *caps, const WINED3DCAPS *wined3d_caps)
325 {
326     caps->DeviceType                = (D3DDEVTYPE)wined3d_caps->DeviceType;
327     caps->AdapterOrdinal            = wined3d_caps->AdapterOrdinal;
328     caps->Caps                      = wined3d_caps->Caps;
329     caps->Caps2                     = wined3d_caps->Caps2;
330     caps->Caps3                     = wined3d_caps->Caps3;
331     caps->PresentationIntervals     = D3DPRESENT_INTERVAL_IMMEDIATE | D3DPRESENT_INTERVAL_ONE;
332     caps->CursorCaps                = wined3d_caps->CursorCaps;
333     caps->DevCaps                   = wined3d_caps->DevCaps;
334     caps->PrimitiveMiscCaps         = wined3d_caps->PrimitiveMiscCaps;
335     caps->RasterCaps                = wined3d_caps->RasterCaps;
336     caps->ZCmpCaps                  = wined3d_caps->ZCmpCaps;
337     caps->SrcBlendCaps              = wined3d_caps->SrcBlendCaps;
338     caps->DestBlendCaps             = wined3d_caps->DestBlendCaps;
339     caps->AlphaCmpCaps              = wined3d_caps->AlphaCmpCaps;
340     caps->ShadeCaps                 = wined3d_caps->ShadeCaps;
341     caps->TextureCaps               = wined3d_caps->TextureCaps;
342     caps->TextureFilterCaps         = wined3d_caps->TextureFilterCaps;
343     caps->CubeTextureFilterCaps     = wined3d_caps->CubeTextureFilterCaps;
344     caps->VolumeTextureFilterCaps   = wined3d_caps->VolumeTextureFilterCaps;
345     caps->TextureAddressCaps        = wined3d_caps->TextureAddressCaps;
346     caps->VolumeTextureAddressCaps  = wined3d_caps->VolumeTextureAddressCaps;
347     caps->LineCaps                  = wined3d_caps->LineCaps;
348     caps->MaxTextureWidth           = wined3d_caps->MaxTextureWidth;
349     caps->MaxTextureHeight          = wined3d_caps->MaxTextureHeight;
350     caps->MaxVolumeExtent           = wined3d_caps->MaxVolumeExtent;
351     caps->MaxTextureRepeat          = wined3d_caps->MaxTextureRepeat;
352     caps->MaxTextureAspectRatio     = wined3d_caps->MaxTextureAspectRatio;
353     caps->MaxAnisotropy             = wined3d_caps->MaxAnisotropy;
354     caps->MaxVertexW                = wined3d_caps->MaxVertexW;
355     caps->GuardBandLeft             = wined3d_caps->GuardBandLeft;
356     caps->GuardBandTop              = wined3d_caps->GuardBandTop;
357     caps->GuardBandRight            = wined3d_caps->GuardBandRight;
358     caps->GuardBandBottom           = wined3d_caps->GuardBandBottom;
359     caps->ExtentsAdjust             = wined3d_caps->ExtentsAdjust;
360     caps->StencilCaps               = wined3d_caps->StencilCaps;
361     caps->FVFCaps                   = wined3d_caps->FVFCaps;
362     caps->TextureOpCaps             = wined3d_caps->TextureOpCaps;
363     caps->MaxTextureBlendStages     = wined3d_caps->MaxTextureBlendStages;
364     caps->MaxSimultaneousTextures   = wined3d_caps->MaxSimultaneousTextures;
365     caps->VertexProcessingCaps      = wined3d_caps->VertexProcessingCaps;
366     caps->MaxActiveLights           = wined3d_caps->MaxActiveLights;
367     caps->MaxUserClipPlanes         = wined3d_caps->MaxUserClipPlanes;
368     caps->MaxVertexBlendMatrices    = wined3d_caps->MaxVertexBlendMatrices;
369     caps->MaxVertexBlendMatrixIndex = wined3d_caps->MaxVertexBlendMatrixIndex;
370     caps->MaxPointSize              = wined3d_caps->MaxPointSize;
371     caps->MaxPrimitiveCount         = wined3d_caps->MaxPrimitiveCount;
372     caps->MaxVertexIndex            = wined3d_caps->MaxVertexIndex;
373     caps->MaxStreams                = wined3d_caps->MaxStreams;
374     caps->MaxStreamStride           = wined3d_caps->MaxStreamStride;
375     caps->VertexShaderVersion       = wined3d_caps->VertexShaderVersion;
376     caps->MaxVertexShaderConst      = wined3d_caps->MaxVertexShaderConst;
377     caps->PixelShaderVersion        = wined3d_caps->PixelShaderVersion;
378     caps->MaxPixelShaderValue       = wined3d_caps->PixelShader1xMaxValue;
379 
380     caps->Caps2 &= D3DCAPS2_CANCALIBRATEGAMMA | D3DCAPS2_CANRENDERWINDOWED
381             | D3DCAPS2_CANMANAGERESOURCE | D3DCAPS2_DYNAMICTEXTURES | D3DCAPS2_FULLSCREENGAMMA
382             | D3DCAPS2_NO2DDURING3DSCENE | D3DCAPS2_RESERVED;
383     caps->Caps3 &= D3DCAPS3_ALPHA_FULLSCREEN_FLIP_OR_DISCARD | D3DCAPS3_RESERVED;
384     caps->PrimitiveMiscCaps &= D3DPMISCCAPS_MASKZ | D3DPMISCCAPS_LINEPATTERNREP
385             | D3DPMISCCAPS_CULLNONE | D3DPMISCCAPS_CULLCW | D3DPMISCCAPS_CULLCCW
386             | D3DPMISCCAPS_COLORWRITEENABLE | D3DPMISCCAPS_CLIPPLANESCALEDPOINTS
387             | D3DPMISCCAPS_CLIPTLVERTS | D3DPMISCCAPS_TSSARGTEMP | D3DPMISCCAPS_BLENDOP
388             | D3DPMISCCAPS_NULLREFERENCE;
389     caps->RasterCaps &= D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_PAT | D3DPRASTERCAPS_ZTEST
390             | D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_FOGTABLE | D3DPRASTERCAPS_ANTIALIASEDGES
391             | D3DPRASTERCAPS_MIPMAPLODBIAS | D3DPRASTERCAPS_ZBIAS | D3DPRASTERCAPS_ZBUFFERLESSHSR
392             | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_ANISOTROPY | D3DPRASTERCAPS_WBUFFER
393             | D3DPRASTERCAPS_WFOG | D3DPRASTERCAPS_ZFOG | D3DPRASTERCAPS_COLORPERSPECTIVE
394             | D3DPRASTERCAPS_STRETCHBLTMULTISAMPLE;
395     caps->SrcBlendCaps &= D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR
396             | D3DPBLENDCAPS_INVSRCCOLOR | D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA
397             | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_DESTCOLOR
398             | D3DPBLENDCAPS_INVDESTCOLOR | D3DPBLENDCAPS_SRCALPHASAT | D3DPBLENDCAPS_BOTHSRCALPHA
399             | D3DPBLENDCAPS_BOTHINVSRCALPHA;
400     caps->DestBlendCaps &= D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR
401             | D3DPBLENDCAPS_INVSRCCOLOR | D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA
402             | D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_DESTCOLOR
403             | D3DPBLENDCAPS_INVDESTCOLOR | D3DPBLENDCAPS_SRCALPHASAT | D3DPBLENDCAPS_BOTHSRCALPHA
404             | D3DPBLENDCAPS_BOTHINVSRCALPHA;
405     caps->TextureCaps &= D3DPTEXTURECAPS_PERSPECTIVE | D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_ALPHA
406             | D3DPTEXTURECAPS_SQUAREONLY | D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE
407             | D3DPTEXTURECAPS_ALPHAPALETTE | D3DPTEXTURECAPS_NONPOW2CONDITIONAL
408             | D3DPTEXTURECAPS_PROJECTED | D3DPTEXTURECAPS_CUBEMAP | D3DPTEXTURECAPS_VOLUMEMAP
409             | D3DPTEXTURECAPS_MIPMAP | D3DPTEXTURECAPS_MIPVOLUMEMAP | D3DPTEXTURECAPS_MIPCUBEMAP
410             | D3DPTEXTURECAPS_CUBEMAP_POW2 | D3DPTEXTURECAPS_VOLUMEMAP_POW2;
411     caps->TextureFilterCaps &= D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MINFLINEAR
412             | D3DPTFILTERCAPS_MINFANISOTROPIC | D3DPTFILTERCAPS_MIPFPOINT
413             | D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MAGFLINEAR
414             | D3DPTFILTERCAPS_MAGFANISOTROPIC | D3DPTFILTERCAPS_MAGFAFLATCUBIC
415             | D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;
416     caps->CubeTextureFilterCaps &= D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MINFLINEAR
417             | D3DPTFILTERCAPS_MINFANISOTROPIC | D3DPTFILTERCAPS_MIPFPOINT
418             | D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MAGFLINEAR
419             | D3DPTFILTERCAPS_MAGFANISOTROPIC | D3DPTFILTERCAPS_MAGFAFLATCUBIC
420             | D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;
421     caps->VolumeTextureFilterCaps &= D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MINFLINEAR
422             | D3DPTFILTERCAPS_MINFANISOTROPIC | D3DPTFILTERCAPS_MIPFPOINT
423             | D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MAGFPOINT | D3DPTFILTERCAPS_MAGFLINEAR
424             | D3DPTFILTERCAPS_MAGFANISOTROPIC | D3DPTFILTERCAPS_MAGFAFLATCUBIC
425             | D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;
426     caps->StencilCaps &= ~WINED3DSTENCILCAPS_TWOSIDED;
427     caps->VertexProcessingCaps &= D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7
428             | D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER
429             | D3DVTXPCAPS_TWEENING | D3DVTXPCAPS_NO_VSDT_UBYTE4;
430 
431     /* D3D8 doesn't support SM 2.0 or higher, so clamp to 1.x */
432     if (caps->PixelShaderVersion)
433         caps->PixelShaderVersion = D3DPS_VERSION(1, 4);
434     else
435         caps->PixelShaderVersion = D3DPS_VERSION(0, 0);
436     if (caps->VertexShaderVersion)
437         caps->VertexShaderVersion = D3DVS_VERSION(1, 1);
438     else
439         caps->VertexShaderVersion = D3DVS_VERSION(0, 0);
440     caps->MaxVertexShaderConst = min(D3D8_MAX_VERTEX_SHADER_CONSTANTF, caps->MaxVertexShaderConst);
441 }
442 
443 /* Handle table functions */
444 static DWORD d3d8_allocate_handle(struct d3d8_handle_table *t, void *object, enum d3d8_handle_type type)
445 {
446     struct d3d8_handle_entry *entry;
447 
448     if (t->free_entries)
449     {
450         DWORD index = t->free_entries - t->entries;
451         /* Use a free handle */
452         entry = t->free_entries;
453         if (entry->type != D3D8_HANDLE_FREE)
454         {
455             ERR("Handle %u(%p) is in the free list, but has type %#x.\n", index, entry, entry->type);
456             return D3D8_INVALID_HANDLE;
457         }
458         t->free_entries = entry->object;
459         entry->object = object;
460         entry->type = type;
461 
462         return index;
463     }
464 
465     if (!(t->entry_count < t->table_size))
466     {
467         /* Grow the table */
468         UINT new_size = t->table_size + (t->table_size >> 1);
469         struct d3d8_handle_entry *new_entries;
470 
471         if (!(new_entries = heap_realloc(t->entries, new_size * sizeof(*t->entries))))
472         {
473             ERR("Failed to grow the handle table.\n");
474             return D3D8_INVALID_HANDLE;
475         }
476         t->entries = new_entries;
477         t->table_size = new_size;
478     }
479 
480     entry = &t->entries[t->entry_count];
481     entry->object = object;
482     entry->type = type;
483 
484     return t->entry_count++;
485 }
486 
487 static void *d3d8_free_handle(struct d3d8_handle_table *t, DWORD handle, enum d3d8_handle_type type)
488 {
489     struct d3d8_handle_entry *entry;
490     void *object;
491 
492     if (handle == D3D8_INVALID_HANDLE || handle >= t->entry_count)
493     {
494         WARN("Invalid handle %u passed.\n", handle);
495         return NULL;
496     }
497 
498     entry = &t->entries[handle];
499     if (entry->type != type)
500     {
501         WARN("Handle %u(%p) is not of type %#x.\n", handle, entry, type);
502         return NULL;
503     }
504 
505     object = entry->object;
506     entry->object = t->free_entries;
507     entry->type = D3D8_HANDLE_FREE;
508     t->free_entries = entry;
509 
510     return object;
511 }
512 
513 static void *d3d8_get_object(struct d3d8_handle_table *t, DWORD handle, enum d3d8_handle_type type)
514 {
515     struct d3d8_handle_entry *entry;
516 
517     if (handle == D3D8_INVALID_HANDLE || handle >= t->entry_count)
518     {
519         WARN("Invalid handle %u passed.\n", handle);
520         return NULL;
521     }
522 
523     entry = &t->entries[handle];
524     if (entry->type != type)
525     {
526         WARN("Handle %u(%p) is not of type %#x.\n", handle, entry, type);
527         return NULL;
528     }
529 
530     return entry->object;
531 }
532 
533 static HRESULT WINAPI d3d8_device_QueryInterface(IDirect3DDevice8 *iface, REFIID riid, void **out)
534 {
535     TRACE("iface %p, riid %s, out %p.\n",
536             iface, debugstr_guid(riid), out);
537 
538     if (IsEqualGUID(riid, &IID_IDirect3DDevice8)
539             || IsEqualGUID(riid, &IID_IUnknown))
540     {
541         IDirect3DDevice8_AddRef(iface);
542         *out = iface;
543         return S_OK;
544     }
545 
546     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
547 
548     *out = NULL;
549     return E_NOINTERFACE;
550 }
551 
552 static ULONG WINAPI d3d8_device_AddRef(IDirect3DDevice8 *iface)
553 {
554     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
555     ULONG ref = InterlockedIncrement(&device->ref);
556 
557     TRACE("%p increasing refcount to %u.\n", iface, ref);
558 
559     return ref;
560 }
561 
562 static ULONG WINAPI d3d8_device_Release(IDirect3DDevice8 *iface)
563 {
564     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
565     ULONG ref;
566 
567     if (device->inDestruction)
568         return 0;
569 
570     ref = InterlockedDecrement(&device->ref);
571 
572     TRACE("%p decreasing refcount to %u.\n", iface, ref);
573 
574     if (!ref)
575     {
576         IDirect3D8 *parent = device->d3d_parent;
577         unsigned i;
578 
579         TRACE("Releasing wined3d device %p.\n", device->wined3d_device);
580 
581         wined3d_mutex_lock();
582 
583         device->inDestruction = TRUE;
584 
585         for (i = 0; i < device->numConvertedDecls; ++i)
586         {
587             d3d8_vertex_declaration_destroy(device->decls[i].declaration);
588         }
589         heap_free(device->decls);
590 
591         if (device->vertex_buffer)
592             wined3d_buffer_decref(device->vertex_buffer);
593         if (device->index_buffer)
594             wined3d_buffer_decref(device->index_buffer);
595 
596         wined3d_device_uninit_3d(device->wined3d_device);
597         wined3d_device_release_focus_window(device->wined3d_device);
598         wined3d_device_decref(device->wined3d_device);
599         heap_free(device->handle_table.entries);
600         heap_free(device);
601 
602         wined3d_mutex_unlock();
603 
604         IDirect3D8_Release(parent);
605     }
606     return ref;
607 }
608 
609 static HRESULT WINAPI d3d8_device_TestCooperativeLevel(IDirect3DDevice8 *iface)
610 {
611     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
612 
613     TRACE("iface %p.\n", iface);
614 
615     TRACE("device state: %#x.\n", device->device_state);
616 
617     switch (device->device_state)
618     {
619         default:
620         case D3D8_DEVICE_STATE_OK:
621             return D3D_OK;
622         case D3D8_DEVICE_STATE_LOST:
623             return D3DERR_DEVICELOST;
624         case D3D8_DEVICE_STATE_NOT_RESET:
625             return D3DERR_DEVICENOTRESET;
626     }
627 }
628 
629 static UINT WINAPI d3d8_device_GetAvailableTextureMem(IDirect3DDevice8 *iface)
630 {
631     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
632     UINT ret;
633 
634     TRACE("iface %p.\n", iface);
635 
636     wined3d_mutex_lock();
637     ret = wined3d_device_get_available_texture_mem(device->wined3d_device);
638     wined3d_mutex_unlock();
639 
640     return ret;
641 }
642 
643 static HRESULT WINAPI d3d8_device_ResourceManagerDiscardBytes(IDirect3DDevice8 *iface, DWORD byte_count)
644 {
645     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
646 
647     TRACE("iface %p, byte_count %u.\n", iface, byte_count);
648 
649     if (byte_count)
650         FIXME("Byte count ignored.\n");
651 
652     wined3d_mutex_lock();
653     wined3d_device_evict_managed_resources(device->wined3d_device);
654     wined3d_mutex_unlock();
655 
656     return D3D_OK;
657 }
658 
659 static HRESULT WINAPI d3d8_device_GetDirect3D(IDirect3DDevice8 *iface, IDirect3D8 **d3d8)
660 {
661     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
662 
663     TRACE("iface %p, d3d8 %p.\n", iface, d3d8);
664 
665     if (!d3d8)
666         return D3DERR_INVALIDCALL;
667 
668     return IDirect3D8_QueryInterface(device->d3d_parent, &IID_IDirect3D8, (void **)d3d8);
669 }
670 
671 static HRESULT WINAPI d3d8_device_GetDeviceCaps(IDirect3DDevice8 *iface, D3DCAPS8 *caps)
672 {
673     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
674     WINED3DCAPS wined3d_caps;
675     HRESULT hr;
676 
677     TRACE("iface %p, caps %p.\n", iface, caps);
678 
679     if (!caps)
680         return D3DERR_INVALIDCALL;
681 
682     wined3d_mutex_lock();
683     hr = wined3d_device_get_device_caps(device->wined3d_device, &wined3d_caps);
684     wined3d_mutex_unlock();
685 
686     d3dcaps_from_wined3dcaps(caps, &wined3d_caps);
687 
688     return hr;
689 }
690 
691 static HRESULT WINAPI d3d8_device_GetDisplayMode(IDirect3DDevice8 *iface, D3DDISPLAYMODE *mode)
692 {
693     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
694     struct wined3d_display_mode wined3d_mode;
695     HRESULT hr;
696 
697     TRACE("iface %p, mode %p.\n", iface, mode);
698 
699     wined3d_mutex_lock();
700     hr = wined3d_device_get_display_mode(device->wined3d_device, 0, &wined3d_mode, NULL);
701     wined3d_mutex_unlock();
702 
703     if (SUCCEEDED(hr))
704     {
705         mode->Width = wined3d_mode.width;
706         mode->Height = wined3d_mode.height;
707         mode->RefreshRate = wined3d_mode.refresh_rate;
708         mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
709     }
710 
711     return hr;
712 }
713 
714 static HRESULT WINAPI d3d8_device_GetCreationParameters(IDirect3DDevice8 *iface,
715         D3DDEVICE_CREATION_PARAMETERS *parameters)
716 {
717     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
718 
719     TRACE("iface %p, parameters %p.\n", iface, parameters);
720 
721     wined3d_mutex_lock();
722     wined3d_device_get_creation_parameters(device->wined3d_device,
723             (struct wined3d_device_creation_parameters *)parameters);
724     wined3d_mutex_unlock();
725 
726     return D3D_OK;
727 }
728 
729 static HRESULT WINAPI d3d8_device_SetCursorProperties(IDirect3DDevice8 *iface,
730         UINT hotspot_x, UINT hotspot_y, IDirect3DSurface8 *bitmap)
731 {
732     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
733     struct d3d8_surface *bitmap_impl = unsafe_impl_from_IDirect3DSurface8(bitmap);
734     HRESULT hr;
735 
736     TRACE("iface %p, hotspot_x %u, hotspot_y %u, bitmap %p.\n",
737             iface, hotspot_x, hotspot_y, bitmap);
738 
739     if (!bitmap)
740     {
741         WARN("No cursor bitmap, returning D3DERR_INVALIDCALL.\n");
742         return D3DERR_INVALIDCALL;
743     }
744 
745     wined3d_mutex_lock();
746     hr = wined3d_device_set_cursor_properties(device->wined3d_device,
747             hotspot_x, hotspot_y, bitmap_impl->wined3d_texture, bitmap_impl->sub_resource_idx);
748     wined3d_mutex_unlock();
749 
750     return hr;
751 }
752 
753 static void WINAPI d3d8_device_SetCursorPosition(IDirect3DDevice8 *iface, UINT x, UINT y, DWORD flags)
754 {
755     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
756 
757     TRACE("iface %p, x %u, y %u, flags %#x.\n", iface, x, y, flags);
758 
759     wined3d_mutex_lock();
760     wined3d_device_set_cursor_position(device->wined3d_device, x, y, flags);
761     wined3d_mutex_unlock();
762 }
763 
764 static BOOL WINAPI d3d8_device_ShowCursor(IDirect3DDevice8 *iface, BOOL show)
765 {
766     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
767     BOOL ret;
768 
769     TRACE("iface %p, show %#x.\n", iface, show);
770 
771     wined3d_mutex_lock();
772     ret = wined3d_device_show_cursor(device->wined3d_device, show);
773     wined3d_mutex_unlock();
774 
775     return ret;
776 }
777 
778 static HRESULT WINAPI d3d8_device_CreateAdditionalSwapChain(IDirect3DDevice8 *iface,
779         D3DPRESENT_PARAMETERS *present_parameters, IDirect3DSwapChain8 **swapchain)
780 {
781     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
782     struct wined3d_swapchain_desc desc;
783     struct d3d8_swapchain *object;
784     unsigned int swap_interval;
785     unsigned int i, count;
786     HRESULT hr;
787 
788     TRACE("iface %p, present_parameters %p, swapchain %p.\n",
789             iface, present_parameters, swapchain);
790 
791     if (!present_parameters->Windowed)
792     {
793         WARN("Trying to create an additional fullscreen swapchain, returning D3DERR_INVALIDCALL.\n");
794         return D3DERR_INVALIDCALL;
795     }
796 
797     wined3d_mutex_lock();
798     count = wined3d_device_get_swapchain_count(device->wined3d_device);
799     for (i = 0; i < count; ++i)
800     {
801         struct wined3d_swapchain *wined3d_swapchain;
802 
803         wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, i);
804         wined3d_swapchain_get_desc(wined3d_swapchain, &desc);
805 
806         if (!desc.windowed)
807         {
808             wined3d_mutex_unlock();
809             WARN("Trying to create an additional swapchain in fullscreen mode, returning D3DERR_INVALIDCALL.\n");
810             return D3DERR_INVALIDCALL;
811         }
812     }
813     wined3d_mutex_unlock();
814 
815     if (!wined3d_swapchain_desc_from_present_parameters(&desc, present_parameters))
816         return D3DERR_INVALIDCALL;
817     swap_interval = wined3dswapinterval_from_d3d(present_parameters->FullScreen_PresentationInterval);
818     if (SUCCEEDED(hr = d3d8_swapchain_create(device, &desc, swap_interval, &object)))
819         *swapchain = &object->IDirect3DSwapChain8_iface;
820     present_parameters_from_wined3d_swapchain_desc(present_parameters,
821             &desc, present_parameters->FullScreen_PresentationInterval);
822 
823     return hr;
824 }
825 
826 static HRESULT CDECL reset_enum_callback(struct wined3d_resource *resource)
827 {
828     struct wined3d_resource_desc desc;
829     IDirect3DBaseTexture8 *texture;
830     struct d3d8_surface *surface;
831     IUnknown *parent;
832 
833     wined3d_resource_get_desc(resource, &desc);
834     if (desc.access & WINED3D_RESOURCE_ACCESS_CPU)
835         return D3D_OK;
836 
837     if (desc.resource_type != WINED3D_RTYPE_TEXTURE_2D)
838     {
839         WARN("Resource %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", resource);
840         return D3DERR_DEVICELOST;
841     }
842 
843     parent = wined3d_resource_get_parent(resource);
844     if (parent && SUCCEEDED(IUnknown_QueryInterface(parent, &IID_IDirect3DBaseTexture8, (void **)&texture)))
845     {
846         IDirect3DBaseTexture8_Release(texture);
847         WARN("Texture %p (resource %p) in pool D3DPOOL_DEFAULT blocks the Reset call.\n", texture, resource);
848         return D3DERR_DEVICELOST;
849     }
850 
851     surface = wined3d_texture_get_sub_resource_parent(wined3d_texture_from_resource(resource), 0);
852     if (!surface->resource.refcount)
853         return D3D_OK;
854 
855     WARN("Surface %p in pool D3DPOOL_DEFAULT blocks the Reset call.\n", surface);
856     return D3DERR_DEVICELOST;
857 }
858 
859 static HRESULT WINAPI d3d8_device_Reset(IDirect3DDevice8 *iface,
860         D3DPRESENT_PARAMETERS *present_parameters)
861 {
862     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
863     struct wined3d_swapchain_desc swapchain_desc;
864     HRESULT hr;
865 
866     TRACE("iface %p, present_parameters %p.\n", iface, present_parameters);
867 
868     if (device->device_state == D3D8_DEVICE_STATE_LOST)
869     {
870         WARN("App not active, returning D3DERR_DEVICELOST.\n");
871         return D3DERR_DEVICELOST;
872     }
873     if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, present_parameters))
874         return D3DERR_INVALIDCALL;
875 
876     wined3d_mutex_lock();
877 
878     if (device->vertex_buffer)
879     {
880         wined3d_buffer_decref(device->vertex_buffer);
881         device->vertex_buffer = NULL;
882         device->vertex_buffer_size = 0;
883     }
884     if (device->index_buffer)
885     {
886         wined3d_buffer_decref(device->index_buffer);
887         device->index_buffer = NULL;
888         device->index_buffer_size = 0;
889     }
890 
891     if (SUCCEEDED(hr = wined3d_device_reset(device->wined3d_device, &swapchain_desc,
892             NULL, reset_enum_callback, TRUE)))
893     {
894         present_parameters->BackBufferCount = swapchain_desc.backbuffer_count;
895         device->implicit_swapchain->swap_interval
896                 = wined3dswapinterval_from_d3d(present_parameters->FullScreen_PresentationInterval);
897         wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_POINTSIZE_MIN, 0);
898         wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_ZENABLE,
899                 !!swapchain_desc.enable_auto_depth_stencil);
900         device->device_state = D3D8_DEVICE_STATE_OK;
901     }
902     else
903     {
904         device->device_state = D3D8_DEVICE_STATE_NOT_RESET;
905     }
906     wined3d_mutex_unlock();
907 
908     return hr;
909 }
910 
911 static HRESULT WINAPI d3d8_device_Present(IDirect3DDevice8 *iface, const RECT *src_rect,
912         const RECT *dst_rect, HWND dst_window_override, const RGNDATA *dirty_region)
913 {
914     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
915 
916     TRACE("iface %p, src_rect %s, dst_rect %s, dst_window_override %p, dirty_region %p.\n",
917             iface, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect), dst_window_override, dirty_region);
918 
919     /* Fraps does not hook IDirect3DDevice8::Present regardless of the hotpatch
920      * attribute. It only hooks IDirect3DSwapChain8::Present. Yet it properly
921      * shows a framerate on Windows in applications that only call the device
922      * method, like e.g. the dx8 sdk samples. The conclusion is that native
923      * calls the swapchain's public method from the device. */
924     return IDirect3DSwapChain8_Present(&device->implicit_swapchain->IDirect3DSwapChain8_iface,
925             src_rect, dst_rect, dst_window_override, dirty_region);
926 }
927 
928 static HRESULT WINAPI d3d8_device_GetBackBuffer(IDirect3DDevice8 *iface,
929         UINT backbuffer_idx, D3DBACKBUFFER_TYPE backbuffer_type, IDirect3DSurface8 **backbuffer)
930 {
931     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
932     struct wined3d_swapchain *wined3d_swapchain;
933     struct wined3d_texture *wined3d_texture;
934     struct d3d8_surface *surface_impl;
935 
936     TRACE("iface %p, backbuffer_idx %u, backbuffer_type %#x, backbuffer %p.\n",
937             iface, backbuffer_idx, backbuffer_type, backbuffer);
938 
939     /* backbuffer_type is ignored by native. */
940 
941     /* No need to check for backbuffer == NULL, Windows crashes in that case. */
942     wined3d_mutex_lock();
943 
944     wined3d_swapchain = device->implicit_swapchain->wined3d_swapchain;
945     if (!(wined3d_texture = wined3d_swapchain_get_back_buffer(wined3d_swapchain, backbuffer_idx)))
946     {
947         wined3d_mutex_unlock();
948         *backbuffer = NULL;
949         return D3DERR_INVALIDCALL;
950     }
951 
952     surface_impl = wined3d_texture_get_sub_resource_parent(wined3d_texture, 0);
953     *backbuffer = &surface_impl->IDirect3DSurface8_iface;
954     IDirect3DSurface8_AddRef(*backbuffer);
955 
956     wined3d_mutex_unlock();
957     return D3D_OK;
958 }
959 
960 static HRESULT WINAPI d3d8_device_GetRasterStatus(IDirect3DDevice8 *iface, D3DRASTER_STATUS *raster_status)
961 {
962     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
963     HRESULT hr;
964 
965     TRACE("iface %p, raster_status %p.\n", iface, raster_status);
966 
967     wined3d_mutex_lock();
968     hr = wined3d_device_get_raster_status(device->wined3d_device, 0, (struct wined3d_raster_status *)raster_status);
969     wined3d_mutex_unlock();
970 
971     return hr;
972 }
973 
974 static void WINAPI d3d8_device_SetGammaRamp(IDirect3DDevice8 *iface, DWORD flags, const D3DGAMMARAMP *ramp)
975 {
976     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
977 
978     TRACE("iface %p, flags %#x, ramp %p.\n", iface, flags, ramp);
979 
980     /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
981     wined3d_mutex_lock();
982     wined3d_device_set_gamma_ramp(device->wined3d_device, 0, flags, (const struct wined3d_gamma_ramp *)ramp);
983     wined3d_mutex_unlock();
984 }
985 
986 static void WINAPI d3d8_device_GetGammaRamp(IDirect3DDevice8 *iface, D3DGAMMARAMP *ramp)
987 {
988     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
989 
990     TRACE("iface %p, ramp %p.\n", iface, ramp);
991 
992     /* Note: D3DGAMMARAMP is compatible with struct wined3d_gamma_ramp. */
993     wined3d_mutex_lock();
994     wined3d_device_get_gamma_ramp(device->wined3d_device, 0, (struct wined3d_gamma_ramp *)ramp);
995     wined3d_mutex_unlock();
996 }
997 
998 static HRESULT WINAPI d3d8_device_CreateTexture(IDirect3DDevice8 *iface,
999         UINT width, UINT height, UINT levels, DWORD usage, D3DFORMAT format,
1000         D3DPOOL pool, IDirect3DTexture8 **texture)
1001 {
1002     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1003     struct d3d8_texture *object;
1004     HRESULT hr;
1005 
1006     TRACE("iface %p, width %u, height %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
1007             iface, width, height, levels, usage, format, pool, texture);
1008 
1009     if (!format)
1010         return D3DERR_INVALIDCALL;
1011 
1012     *texture = NULL;
1013     if (!(object = heap_alloc_zero(sizeof(*object))))
1014         return D3DERR_OUTOFVIDEOMEMORY;
1015 
1016     hr = texture_init(object, device, width, height, levels, usage, format, pool);
1017     if (FAILED(hr))
1018     {
1019         WARN("Failed to initialize texture, hr %#x.\n", hr);
1020         heap_free(object);
1021         return hr;
1022     }
1023 
1024     TRACE("Created texture %p.\n", object);
1025     *texture = (IDirect3DTexture8 *)&object->IDirect3DBaseTexture8_iface;
1026 
1027     return D3D_OK;
1028 }
1029 
1030 static HRESULT WINAPI d3d8_device_CreateVolumeTexture(IDirect3DDevice8 *iface,
1031         UINT width, UINT height, UINT depth, UINT levels, DWORD usage, D3DFORMAT format,
1032         D3DPOOL pool, IDirect3DVolumeTexture8 **texture)
1033 {
1034     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1035     struct d3d8_texture *object;
1036     HRESULT hr;
1037 
1038     TRACE("iface %p, width %u, height %u, depth %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
1039             iface, width, height, depth, levels, usage, format, pool, texture);
1040 
1041     if (!format)
1042         return D3DERR_INVALIDCALL;
1043 
1044     *texture = NULL;
1045     if (!(object = heap_alloc_zero(sizeof(*object))))
1046         return D3DERR_OUTOFVIDEOMEMORY;
1047 
1048     hr = volumetexture_init(object, device, width, height, depth, levels, usage, format, pool);
1049     if (FAILED(hr))
1050     {
1051         WARN("Failed to initialize volume texture, hr %#x.\n", hr);
1052         heap_free(object);
1053         return hr;
1054     }
1055 
1056     TRACE("Created volume texture %p.\n", object);
1057     *texture = (IDirect3DVolumeTexture8 *)&object->IDirect3DBaseTexture8_iface;
1058 
1059     return D3D_OK;
1060 }
1061 
1062 static HRESULT WINAPI d3d8_device_CreateCubeTexture(IDirect3DDevice8 *iface, UINT edge_length,
1063         UINT levels, DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DCubeTexture8 **texture)
1064 {
1065     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1066     struct d3d8_texture *object;
1067     HRESULT hr;
1068 
1069     TRACE("iface %p, edge_length %u, levels %u, usage %#x, format %#x, pool %#x, texture %p.\n",
1070             iface, edge_length, levels, usage, format, pool, texture);
1071 
1072     if (!format)
1073         return D3DERR_INVALIDCALL;
1074 
1075     *texture = NULL;
1076     if (!(object = heap_alloc_zero(sizeof(*object))))
1077         return D3DERR_OUTOFVIDEOMEMORY;
1078 
1079     hr = cubetexture_init(object, device, edge_length, levels, usage, format, pool);
1080     if (FAILED(hr))
1081     {
1082         WARN("Failed to initialize cube texture, hr %#x.\n", hr);
1083         heap_free(object);
1084         return hr;
1085     }
1086 
1087     TRACE("Created cube texture %p.\n", object);
1088     *texture = (IDirect3DCubeTexture8 *)&object->IDirect3DBaseTexture8_iface;
1089 
1090     return hr;
1091 }
1092 
1093 static HRESULT WINAPI d3d8_device_CreateVertexBuffer(IDirect3DDevice8 *iface, UINT size,
1094         DWORD usage, DWORD fvf, D3DPOOL pool, IDirect3DVertexBuffer8 **buffer)
1095 {
1096     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1097     struct d3d8_vertexbuffer *object;
1098     HRESULT hr;
1099 
1100     TRACE("iface %p, size %u, usage %#x, fvf %#x, pool %#x, buffer %p.\n",
1101             iface, size, usage, fvf, pool, buffer);
1102 
1103     if (!(object = heap_alloc_zero(sizeof(*object))))
1104         return D3DERR_OUTOFVIDEOMEMORY;
1105 
1106     hr = vertexbuffer_init(object, device, size, usage, fvf, pool);
1107     if (FAILED(hr))
1108     {
1109         WARN("Failed to initialize vertex buffer, hr %#x.\n", hr);
1110         heap_free(object);
1111         return hr;
1112     }
1113 
1114     TRACE("Created vertex buffer %p.\n", object);
1115     *buffer = &object->IDirect3DVertexBuffer8_iface;
1116 
1117     return D3D_OK;
1118 }
1119 
1120 static HRESULT WINAPI d3d8_device_CreateIndexBuffer(IDirect3DDevice8 *iface, UINT size,
1121         DWORD usage, D3DFORMAT format, D3DPOOL pool, IDirect3DIndexBuffer8 **buffer)
1122 {
1123     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1124     struct d3d8_indexbuffer *object;
1125     HRESULT hr;
1126 
1127     TRACE("iface %p, size %u, usage %#x, format %#x, pool %#x, buffer %p.\n",
1128             iface, size, usage, format, pool, buffer);
1129 
1130     if (!(object = heap_alloc_zero(sizeof(*object))))
1131         return D3DERR_OUTOFVIDEOMEMORY;
1132 
1133     hr = indexbuffer_init(object, device, size, usage, format, pool);
1134     if (FAILED(hr))
1135     {
1136         WARN("Failed to initialize index buffer, hr %#x.\n", hr);
1137         heap_free(object);
1138         return hr;
1139     }
1140 
1141     TRACE("Created index buffer %p.\n", object);
1142     *buffer = &object->IDirect3DIndexBuffer8_iface;
1143 
1144     return D3D_OK;
1145 }
1146 
1147 static HRESULT d3d8_device_create_surface(struct d3d8_device *device, UINT width, UINT height,
1148         D3DFORMAT format, DWORD flags, IDirect3DSurface8 **surface, UINT usage, D3DPOOL pool,
1149         D3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality)
1150 {
1151     struct wined3d_resource_desc desc;
1152     struct d3d8_surface *surface_impl;
1153     struct wined3d_texture *texture;
1154     HRESULT hr;
1155 
1156     TRACE("device %p, width %u, height %u, format %#x, flags %#x, surface %p, "
1157             "usage %#x, pool %#x, multisample_type %#x, multisample_quality %u.\n",
1158             device, width, height, format, flags, surface,
1159             usage, pool, multisample_type, multisample_quality);
1160 
1161     desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
1162     desc.format = wined3dformat_from_d3dformat(format);
1163     desc.multisample_type = multisample_type;
1164     desc.multisample_quality = multisample_quality;
1165     desc.usage = usage & WINED3DUSAGE_MASK;
1166     if (pool == D3DPOOL_SCRATCH)
1167         desc.usage |= WINED3DUSAGE_SCRATCH;
1168     desc.access = wined3daccess_from_d3dpool(pool, usage)
1169             | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
1170     desc.width = width;
1171     desc.height = height;
1172     desc.depth = 1;
1173     desc.size = 0;
1174 
1175     wined3d_mutex_lock();
1176 
1177     if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &desc,
1178             1, 1, flags, NULL, NULL, &d3d8_null_wined3d_parent_ops, &texture)))
1179     {
1180         wined3d_mutex_unlock();
1181         WARN("Failed to create texture, hr %#x.\n", hr);
1182         return hr;
1183     }
1184 
1185     surface_impl = wined3d_texture_get_sub_resource_parent(texture, 0);
1186     surface_impl->parent_device = &device->IDirect3DDevice8_iface;
1187     *surface = &surface_impl->IDirect3DSurface8_iface;
1188     IDirect3DSurface8_AddRef(*surface);
1189     wined3d_texture_decref(texture);
1190 
1191     wined3d_mutex_unlock();
1192 
1193     return D3D_OK;
1194 }
1195 
1196 static HRESULT WINAPI d3d8_device_CreateRenderTarget(IDirect3DDevice8 *iface, UINT width,
1197         UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, BOOL lockable,
1198         IDirect3DSurface8 **surface)
1199 {
1200     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1201     DWORD flags = 0;
1202 
1203     TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, lockable %#x, surface %p.\n",
1204             iface, width, height, format, multisample_type, lockable, surface);
1205 
1206     if (!format)
1207         return D3DERR_INVALIDCALL;
1208 
1209     *surface = NULL;
1210     if (lockable)
1211         flags |= WINED3D_TEXTURE_CREATE_MAPPABLE;
1212 
1213     return d3d8_device_create_surface(device, width, height, format, flags, surface,
1214             D3DUSAGE_RENDERTARGET, D3DPOOL_DEFAULT, multisample_type, 0);
1215 }
1216 
1217 static HRESULT WINAPI d3d8_device_CreateDepthStencilSurface(IDirect3DDevice8 *iface,
1218         UINT width, UINT height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type,
1219         IDirect3DSurface8 **surface)
1220 {
1221     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1222 
1223     TRACE("iface %p, width %u, height %u, format %#x, multisample_type %#x, surface %p.\n",
1224             iface, width, height, format, multisample_type, surface);
1225 
1226     if (!format)
1227         return D3DERR_INVALIDCALL;
1228 
1229     *surface = NULL;
1230 
1231     /* TODO: Verify that Discard is false */
1232     return d3d8_device_create_surface(device, width, height, format, WINED3D_TEXTURE_CREATE_MAPPABLE,
1233             surface, D3DUSAGE_DEPTHSTENCIL, D3DPOOL_DEFAULT, multisample_type, 0);
1234 }
1235 
1236 /*  IDirect3DDevice8Impl::CreateImageSurface returns surface with pool type SYSTEMMEM */
1237 static HRESULT WINAPI d3d8_device_CreateImageSurface(IDirect3DDevice8 *iface, UINT width,
1238         UINT height, D3DFORMAT format, IDirect3DSurface8 **surface)
1239 {
1240     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1241 
1242     TRACE("iface %p, width %u, height %u, format %#x, surface %p.\n",
1243             iface, width, height, format, surface);
1244 
1245     *surface = NULL;
1246 
1247     return d3d8_device_create_surface(device, width, height, format, WINED3D_TEXTURE_CREATE_MAPPABLE,
1248             surface, 0, D3DPOOL_SYSTEMMEM, D3DMULTISAMPLE_NONE, 0);
1249 }
1250 
1251 static HRESULT WINAPI d3d8_device_CopyRects(IDirect3DDevice8 *iface,
1252         IDirect3DSurface8 *src_surface, const RECT *src_rects, UINT rect_count,
1253         IDirect3DSurface8 *dst_surface, const POINT *dst_points)
1254 {
1255     struct d3d8_surface *src = unsafe_impl_from_IDirect3DSurface8(src_surface);
1256     struct d3d8_surface *dst = unsafe_impl_from_IDirect3DSurface8(dst_surface);
1257     enum wined3d_format_id src_format, dst_format;
1258     struct wined3d_sub_resource_desc wined3d_desc;
1259     UINT src_w, src_h;
1260 
1261     TRACE("iface %p, src_surface %p, src_rects %p, rect_count %u, dst_surface %p, dst_points %p.\n",
1262             iface, src_surface, src_rects, rect_count, dst_surface, dst_points);
1263 
1264     /* Check that the source texture is in WINED3D_POOL_SYSTEM_MEM and the
1265      * destination texture is in WINED3D_POOL_DEFAULT. */
1266 
1267     wined3d_mutex_lock();
1268     wined3d_texture_get_sub_resource_desc(src->wined3d_texture, src->sub_resource_idx, &wined3d_desc);
1269     if (wined3d_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
1270     {
1271         WARN("Source %p is a depth stencil surface, returning D3DERR_INVALIDCALL.\n", src_surface);
1272         wined3d_mutex_unlock();
1273         return D3DERR_INVALIDCALL;
1274     }
1275     src_format = wined3d_desc.format;
1276     src_w = wined3d_desc.width;
1277     src_h = wined3d_desc.height;
1278 
1279     wined3d_texture_get_sub_resource_desc(dst->wined3d_texture, dst->sub_resource_idx, &wined3d_desc);
1280     if (wined3d_desc.usage & WINED3DUSAGE_DEPTHSTENCIL)
1281     {
1282         WARN("Destination %p is a depth stencil surface, returning D3DERR_INVALIDCALL.\n", dst_surface);
1283         wined3d_mutex_unlock();
1284         return D3DERR_INVALIDCALL;
1285     }
1286     dst_format = wined3d_desc.format;
1287 
1288     /* Check that the source and destination formats match */
1289     if (src_format != dst_format)
1290     {
1291         WARN("Source %p format must match the destination %p format, returning D3DERR_INVALIDCALL.\n",
1292                 src_surface, dst_surface);
1293         wined3d_mutex_unlock();
1294         return D3DERR_INVALIDCALL;
1295     }
1296 
1297     /* Quick if complete copy ... */
1298     if (!rect_count && !src_rects && !dst_points)
1299     {
1300         RECT rect = {0, 0, src_w, src_h};
1301         wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &rect,
1302                 src->wined3d_texture, src->sub_resource_idx, &rect, 0, NULL, WINED3D_TEXF_POINT);
1303     }
1304     else
1305     {
1306         unsigned int i;
1307         /* Copy rect by rect */
1308         if (src_rects && dst_points)
1309         {
1310             for (i = 0; i < rect_count; ++i)
1311             {
1312                 UINT w = src_rects[i].right - src_rects[i].left;
1313                 UINT h = src_rects[i].bottom - src_rects[i].top;
1314                 RECT dst_rect = {dst_points[i].x, dst_points[i].y,
1315                         dst_points[i].x + w, dst_points[i].y + h};
1316 
1317                 wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &dst_rect,
1318                         src->wined3d_texture, src->sub_resource_idx, &src_rects[i], 0, NULL, WINED3D_TEXF_POINT);
1319             }
1320         }
1321         else
1322         {
1323             for (i = 0; i < rect_count; ++i)
1324             {
1325                 UINT w = src_rects[i].right - src_rects[i].left;
1326                 UINT h = src_rects[i].bottom - src_rects[i].top;
1327                 RECT dst_rect = {0, 0, w, h};
1328 
1329                 wined3d_texture_blt(dst->wined3d_texture, dst->sub_resource_idx, &dst_rect,
1330                         src->wined3d_texture, src->sub_resource_idx, &src_rects[i], 0, NULL, WINED3D_TEXF_POINT);
1331             }
1332         }
1333     }
1334     wined3d_mutex_unlock();
1335 
1336     return WINED3D_OK;
1337 }
1338 
1339 static HRESULT WINAPI d3d8_device_UpdateTexture(IDirect3DDevice8 *iface,
1340         IDirect3DBaseTexture8 *src_texture, IDirect3DBaseTexture8 *dst_texture)
1341 {
1342     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1343     struct d3d8_texture *src_impl, *dst_impl;
1344     HRESULT hr;
1345 
1346     TRACE("iface %p, src_texture %p, dst_texture %p.\n", iface, src_texture, dst_texture);
1347 
1348     src_impl = unsafe_impl_from_IDirect3DBaseTexture8(src_texture);
1349     dst_impl = unsafe_impl_from_IDirect3DBaseTexture8(dst_texture);
1350 
1351     wined3d_mutex_lock();
1352     hr = wined3d_device_update_texture(device->wined3d_device,
1353             src_impl->wined3d_texture, dst_impl->wined3d_texture);
1354     wined3d_mutex_unlock();
1355 
1356     return hr;
1357 }
1358 
1359 static HRESULT WINAPI d3d8_device_GetFrontBuffer(IDirect3DDevice8 *iface, IDirect3DSurface8 *dst_surface)
1360 {
1361     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1362     struct d3d8_surface *dst_impl = unsafe_impl_from_IDirect3DSurface8(dst_surface);
1363     HRESULT hr;
1364 
1365     TRACE("iface %p, dst_surface %p.\n", iface, dst_surface);
1366 
1367     if (!dst_surface)
1368     {
1369         WARN("Invalid destination surface passed.\n");
1370         return D3DERR_INVALIDCALL;
1371     }
1372 
1373     wined3d_mutex_lock();
1374     hr = wined3d_swapchain_get_front_buffer_data(device->implicit_swapchain->wined3d_swapchain,
1375             dst_impl->wined3d_texture, dst_impl->sub_resource_idx);
1376     wined3d_mutex_unlock();
1377 
1378     return hr;
1379 }
1380 
1381 static HRESULT WINAPI d3d8_device_SetRenderTarget(IDirect3DDevice8 *iface,
1382         IDirect3DSurface8 *render_target, IDirect3DSurface8 *depth_stencil)
1383 {
1384     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1385     struct d3d8_surface *rt_impl = unsafe_impl_from_IDirect3DSurface8(render_target);
1386     struct d3d8_surface *ds_impl = unsafe_impl_from_IDirect3DSurface8(depth_stencil);
1387     struct wined3d_rendertarget_view *original_dsv, *rtv;
1388     HRESULT hr = D3D_OK;
1389 
1390     TRACE("iface %p, render_target %p, depth_stencil %p.\n", iface, render_target, depth_stencil);
1391 
1392     if (rt_impl && d3d8_surface_get_device(rt_impl) != device)
1393     {
1394         WARN("Render target surface does not match device.\n");
1395         return D3DERR_INVALIDCALL;
1396     }
1397 
1398     wined3d_mutex_lock();
1399 
1400     if (ds_impl)
1401     {
1402         struct wined3d_sub_resource_desc ds_desc, rt_desc;
1403         struct wined3d_rendertarget_view *original_rtv;
1404         struct d3d8_surface *original_surface;
1405 
1406         /* If no render target is passed in check the size against the current RT */
1407         if (!render_target)
1408         {
1409             if (!(original_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
1410             {
1411                 wined3d_mutex_unlock();
1412                 return D3DERR_NOTFOUND;
1413             }
1414             original_surface = wined3d_rendertarget_view_get_sub_resource_parent(original_rtv);
1415             wined3d_texture_get_sub_resource_desc(original_surface->wined3d_texture,
1416                     original_surface->sub_resource_idx, &rt_desc);
1417         }
1418         else
1419             wined3d_texture_get_sub_resource_desc(rt_impl->wined3d_texture,
1420                     rt_impl->sub_resource_idx, &rt_desc);
1421 
1422         wined3d_texture_get_sub_resource_desc(ds_impl->wined3d_texture, ds_impl->sub_resource_idx, &ds_desc);
1423 
1424         if (ds_desc.width < rt_desc.width || ds_desc.height < rt_desc.height)
1425         {
1426             WARN("Depth stencil is smaller than the render target, returning D3DERR_INVALIDCALL\n");
1427             wined3d_mutex_unlock();
1428             return D3DERR_INVALIDCALL;
1429         }
1430         if (ds_desc.multisample_type != rt_desc.multisample_type
1431                 || ds_desc.multisample_quality != rt_desc.multisample_quality)
1432         {
1433             WARN("Multisample settings do not match, returning D3DERR_INVALIDCALL\n");
1434             wined3d_mutex_unlock();
1435             return D3DERR_INVALIDCALL;
1436         }
1437     }
1438 
1439     original_dsv = wined3d_device_get_depth_stencil_view(device->wined3d_device);
1440     rtv = ds_impl ? d3d8_surface_acquire_rendertarget_view(ds_impl) : NULL;
1441     wined3d_device_set_depth_stencil_view(device->wined3d_device, rtv);
1442     d3d8_surface_release_rendertarget_view(ds_impl, rtv);
1443     rtv = render_target ? d3d8_surface_acquire_rendertarget_view(rt_impl) : NULL;
1444     if (render_target && FAILED(hr = wined3d_device_set_rendertarget_view(device->wined3d_device, 0, rtv, TRUE)))
1445         wined3d_device_set_depth_stencil_view(device->wined3d_device, original_dsv);
1446     d3d8_surface_release_rendertarget_view(rt_impl, rtv);
1447 
1448     wined3d_mutex_unlock();
1449 
1450     return hr;
1451 }
1452 
1453 static HRESULT WINAPI d3d8_device_GetRenderTarget(IDirect3DDevice8 *iface, IDirect3DSurface8 **render_target)
1454 {
1455     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1456     struct wined3d_rendertarget_view *wined3d_rtv;
1457     struct d3d8_surface *surface_impl;
1458     HRESULT hr;
1459 
1460     TRACE("iface %p, render_target %p.\n", iface, render_target);
1461 
1462     if (!render_target)
1463         return D3DERR_INVALIDCALL;
1464 
1465     wined3d_mutex_lock();
1466     if ((wined3d_rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
1467     {
1468         /* We want the sub resource parent here, since the view itself may be
1469          * internal to wined3d and may not have a parent. */
1470         surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_rtv);
1471         *render_target = &surface_impl->IDirect3DSurface8_iface;
1472         IDirect3DSurface8_AddRef(*render_target);
1473         hr = D3D_OK;
1474     }
1475     else
1476     {
1477         ERR("Failed to get wined3d render target.\n");
1478         *render_target = NULL;
1479         hr = D3DERR_NOTFOUND;
1480     }
1481     wined3d_mutex_unlock();
1482 
1483     return hr;
1484 }
1485 
1486 static HRESULT WINAPI d3d8_device_GetDepthStencilSurface(IDirect3DDevice8 *iface, IDirect3DSurface8 **depth_stencil)
1487 {
1488     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1489     struct wined3d_rendertarget_view *wined3d_dsv;
1490     struct d3d8_surface *surface_impl;
1491     HRESULT hr = D3D_OK;
1492 
1493     TRACE("iface %p, depth_stencil %p.\n", iface, depth_stencil);
1494 
1495     if (!depth_stencil)
1496         return D3DERR_INVALIDCALL;
1497 
1498     wined3d_mutex_lock();
1499     if ((wined3d_dsv = wined3d_device_get_depth_stencil_view(device->wined3d_device)))
1500     {
1501         /* We want the sub resource parent here, since the view itself may be
1502          * internal to wined3d and may not have a parent. */
1503         surface_impl = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_dsv);
1504         *depth_stencil = &surface_impl->IDirect3DSurface8_iface;
1505         IDirect3DSurface8_AddRef(*depth_stencil);
1506     }
1507     else
1508     {
1509         hr = D3DERR_NOTFOUND;
1510         *depth_stencil = NULL;
1511     }
1512     wined3d_mutex_unlock();
1513 
1514     return hr;
1515 }
1516 
1517 static HRESULT WINAPI d3d8_device_BeginScene(IDirect3DDevice8 *iface)
1518 {
1519     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1520     HRESULT hr;
1521 
1522     TRACE("iface %p.\n", iface);
1523 
1524     wined3d_mutex_lock();
1525     hr = wined3d_device_begin_scene(device->wined3d_device);
1526     wined3d_mutex_unlock();
1527 
1528     return hr;
1529 }
1530 
1531 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d8_device_EndScene(IDirect3DDevice8 *iface)
1532 {
1533     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1534     HRESULT hr;
1535 
1536     TRACE("iface %p.\n", iface);
1537 
1538     wined3d_mutex_lock();
1539     hr = wined3d_device_end_scene(device->wined3d_device);
1540     wined3d_mutex_unlock();
1541 
1542     return hr;
1543 }
1544 
1545 static HRESULT WINAPI d3d8_device_Clear(IDirect3DDevice8 *iface, DWORD rect_count,
1546         const D3DRECT *rects, DWORD flags, D3DCOLOR color, float z, DWORD stencil)
1547 {
1548     const struct wined3d_color c =
1549     {
1550         ((color >> 16) & 0xff) / 255.0f,
1551         ((color >>  8) & 0xff) / 255.0f,
1552         (color & 0xff) / 255.0f,
1553         ((color >> 24) & 0xff) / 255.0f,
1554     };
1555     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1556     HRESULT hr;
1557 
1558     TRACE("iface %p, rect_count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %u.\n",
1559             iface, rect_count, rects, flags, color, z, stencil);
1560 
1561     if (rect_count && !rects)
1562     {
1563         WARN("count %u with NULL rects.\n", rect_count);
1564         rect_count = 0;
1565     }
1566 
1567     wined3d_mutex_lock();
1568     hr = wined3d_device_clear(device->wined3d_device, rect_count, (const RECT *)rects, flags, &c, z, stencil);
1569     wined3d_mutex_unlock();
1570 
1571     return hr;
1572 }
1573 
1574 static HRESULT WINAPI d3d8_device_SetTransform(IDirect3DDevice8 *iface,
1575         D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1576 {
1577     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1578 
1579     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1580 
1581     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1582     wined3d_mutex_lock();
1583     wined3d_device_set_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1584     wined3d_mutex_unlock();
1585 
1586     return D3D_OK;
1587 }
1588 
1589 static HRESULT WINAPI d3d8_device_GetTransform(IDirect3DDevice8 *iface,
1590         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
1591 {
1592     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1593 
1594     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1595 
1596     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1597     wined3d_mutex_lock();
1598     wined3d_device_get_transform(device->wined3d_device, state, (struct wined3d_matrix *)matrix);
1599     wined3d_mutex_unlock();
1600 
1601     return D3D_OK;
1602 }
1603 
1604 static HRESULT WINAPI d3d8_device_MultiplyTransform(IDirect3DDevice8 *iface,
1605         D3DTRANSFORMSTATETYPE state, const D3DMATRIX *matrix)
1606 {
1607     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1608 
1609     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
1610 
1611     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
1612     wined3d_mutex_lock();
1613     wined3d_device_multiply_transform(device->wined3d_device, state, (const struct wined3d_matrix *)matrix);
1614     wined3d_mutex_unlock();
1615 
1616     return D3D_OK;
1617 }
1618 
1619 static HRESULT WINAPI d3d8_device_SetViewport(IDirect3DDevice8 *iface, const D3DVIEWPORT8 *viewport)
1620 {
1621     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1622     struct wined3d_sub_resource_desc rt_desc;
1623     struct wined3d_rendertarget_view *rtv;
1624     struct d3d8_surface *surface;
1625     struct wined3d_viewport vp;
1626 
1627     TRACE("iface %p, viewport %p.\n", iface, viewport);
1628 
1629     wined3d_mutex_lock();
1630     if (!(rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
1631     {
1632         wined3d_mutex_unlock();
1633         return D3DERR_NOTFOUND;
1634     }
1635     surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv);
1636     wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc);
1637 
1638     if (viewport->X > rt_desc.width || viewport->Width > rt_desc.width - viewport->X
1639             || viewport->Y > rt_desc.height || viewport->Height > rt_desc.height - viewport->Y)
1640     {
1641         WARN("Invalid viewport, returning D3DERR_INVALIDCALL.\n");
1642         wined3d_mutex_unlock();
1643         return D3DERR_INVALIDCALL;
1644     }
1645 
1646     vp.x = viewport->X;
1647     vp.y = viewport->Y;
1648     vp.width = viewport->Width;
1649     vp.height = viewport->Height;
1650     vp.min_z = viewport->MinZ;
1651     vp.max_z = viewport->MaxZ;
1652 
1653     wined3d_device_set_viewports(device->wined3d_device, 1, &vp);
1654     wined3d_mutex_unlock();
1655 
1656     return D3D_OK;
1657 }
1658 
1659 static HRESULT WINAPI d3d8_device_GetViewport(IDirect3DDevice8 *iface, D3DVIEWPORT8 *viewport)
1660 {
1661     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1662     struct wined3d_viewport wined3d_viewport;
1663 
1664     TRACE("iface %p, viewport %p.\n", iface, viewport);
1665 
1666     wined3d_mutex_lock();
1667     wined3d_device_get_viewports(device->wined3d_device, NULL, &wined3d_viewport);
1668     wined3d_mutex_unlock();
1669 
1670     viewport->X = wined3d_viewport.x;
1671     viewport->Y = wined3d_viewport.y;
1672     viewport->Width = wined3d_viewport.width;
1673     viewport->Height = wined3d_viewport.height;
1674     viewport->MinZ = wined3d_viewport.min_z;
1675     viewport->MaxZ = wined3d_viewport.max_z;
1676 
1677     return D3D_OK;
1678 }
1679 
1680 static HRESULT WINAPI d3d8_device_SetMaterial(IDirect3DDevice8 *iface, const D3DMATERIAL8 *material)
1681 {
1682     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1683 
1684     TRACE("iface %p, material %p.\n", iface, material);
1685 
1686     /* Note: D3DMATERIAL8 is compatible with struct wined3d_material. */
1687     wined3d_mutex_lock();
1688     wined3d_device_set_material(device->wined3d_device, (const struct wined3d_material *)material);
1689     wined3d_mutex_unlock();
1690 
1691     return D3D_OK;
1692 }
1693 
1694 static HRESULT WINAPI d3d8_device_GetMaterial(IDirect3DDevice8 *iface, D3DMATERIAL8 *material)
1695 {
1696     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1697 
1698     TRACE("iface %p, material %p.\n", iface, material);
1699 
1700     /* Note: D3DMATERIAL8 is compatible with struct wined3d_material. */
1701     wined3d_mutex_lock();
1702     wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
1703     wined3d_mutex_unlock();
1704 
1705     return D3D_OK;
1706 }
1707 
1708 static HRESULT WINAPI d3d8_device_SetLight(IDirect3DDevice8 *iface, DWORD index, const D3DLIGHT8 *light)
1709 {
1710     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1711     HRESULT hr;
1712 
1713     TRACE("iface %p, index %u, light %p.\n", iface, index, light);
1714 
1715     /* Note: D3DLIGHT8 is compatible with struct wined3d_light. */
1716     wined3d_mutex_lock();
1717     hr = wined3d_device_set_light(device->wined3d_device, index, (const struct wined3d_light *)light);
1718     wined3d_mutex_unlock();
1719 
1720     return hr;
1721 }
1722 
1723 static HRESULT WINAPI d3d8_device_GetLight(IDirect3DDevice8 *iface, DWORD index, D3DLIGHT8 *light)
1724 {
1725     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1726     HRESULT hr;
1727 
1728     TRACE("iface %p, index %u, light %p.\n", iface, index, light);
1729 
1730     /* Note: D3DLIGHT8 is compatible with struct wined3d_light. */
1731     wined3d_mutex_lock();
1732     hr = wined3d_device_get_light(device->wined3d_device, index, (struct wined3d_light *)light);
1733     wined3d_mutex_unlock();
1734 
1735     return hr;
1736 }
1737 
1738 static HRESULT WINAPI d3d8_device_LightEnable(IDirect3DDevice8 *iface, DWORD index, BOOL enable)
1739 {
1740     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1741     HRESULT hr;
1742 
1743     TRACE("iface %p, index %u, enable %#x.\n", iface, index, enable);
1744 
1745     wined3d_mutex_lock();
1746     hr = wined3d_device_set_light_enable(device->wined3d_device, index, enable);
1747     wined3d_mutex_unlock();
1748 
1749     return hr;
1750 }
1751 
1752 static HRESULT WINAPI d3d8_device_GetLightEnable(IDirect3DDevice8 *iface, DWORD index, BOOL *enable)
1753 {
1754     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1755     HRESULT hr;
1756 
1757     TRACE("iface %p, index %u, enable %p.\n", iface, index, enable);
1758 
1759     wined3d_mutex_lock();
1760     hr = wined3d_device_get_light_enable(device->wined3d_device, index, enable);
1761     wined3d_mutex_unlock();
1762 
1763     return hr;
1764 }
1765 
1766 static HRESULT WINAPI d3d8_device_SetClipPlane(IDirect3DDevice8 *iface, DWORD index, const float *plane)
1767 {
1768     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1769     HRESULT hr;
1770 
1771     TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
1772 
1773     wined3d_mutex_lock();
1774     hr = wined3d_device_set_clip_plane(device->wined3d_device, index, (const struct wined3d_vec4 *)plane);
1775     wined3d_mutex_unlock();
1776 
1777     return hr;
1778 }
1779 
1780 static HRESULT WINAPI d3d8_device_GetClipPlane(IDirect3DDevice8 *iface, DWORD index, float *plane)
1781 {
1782     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1783     HRESULT hr;
1784 
1785     TRACE("iface %p, index %u, plane %p.\n", iface, index, plane);
1786 
1787     wined3d_mutex_lock();
1788     hr = wined3d_device_get_clip_plane(device->wined3d_device, index, (struct wined3d_vec4 *)plane);
1789     wined3d_mutex_unlock();
1790 
1791     return hr;
1792 }
1793 
1794 static HRESULT WINAPI d3d8_device_SetRenderState(IDirect3DDevice8 *iface,
1795         D3DRENDERSTATETYPE state, DWORD value)
1796 {
1797     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1798 
1799     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
1800 
1801     wined3d_mutex_lock();
1802     switch (state)
1803     {
1804         case D3DRS_ZBIAS:
1805             wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
1806             break;
1807 
1808         default:
1809             wined3d_device_set_render_state(device->wined3d_device, state, value);
1810     }
1811     wined3d_mutex_unlock();
1812 
1813     return D3D_OK;
1814 }
1815 
1816 static HRESULT WINAPI d3d8_device_GetRenderState(IDirect3DDevice8 *iface,
1817         D3DRENDERSTATETYPE state, DWORD *value)
1818 {
1819     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1820 
1821     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
1822 
1823     wined3d_mutex_lock();
1824     switch (state)
1825     {
1826         case D3DRS_ZBIAS:
1827             *value = wined3d_device_get_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS);
1828             break;
1829 
1830         default:
1831             *value = wined3d_device_get_render_state(device->wined3d_device, state);
1832     }
1833     wined3d_mutex_unlock();
1834 
1835     return D3D_OK;
1836 }
1837 
1838 static HRESULT WINAPI d3d8_device_BeginStateBlock(IDirect3DDevice8 *iface)
1839 {
1840     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1841     HRESULT hr;
1842 
1843     TRACE("iface %p.\n", iface);
1844 
1845     wined3d_mutex_lock();
1846     hr = wined3d_device_begin_stateblock(device->wined3d_device);
1847     wined3d_mutex_unlock();
1848 
1849     return hr;
1850 }
1851 
1852 static HRESULT WINAPI d3d8_device_EndStateBlock(IDirect3DDevice8 *iface, DWORD *token)
1853 {
1854     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1855     struct wined3d_stateblock *stateblock;
1856     HRESULT hr;
1857 
1858     TRACE("iface %p, token %p.\n", iface, token);
1859 
1860     /* Tell wineD3D to endstateblock before anything else (in case we run out
1861      * of memory later and cause locking problems)
1862      */
1863     wined3d_mutex_lock();
1864     hr = wined3d_device_end_stateblock(device->wined3d_device, &stateblock);
1865     if (FAILED(hr))
1866     {
1867         WARN("Failed to end the state block, %#x.\n", hr);
1868         wined3d_mutex_unlock();
1869         return hr;
1870     }
1871 
1872     *token = d3d8_allocate_handle(&device->handle_table, stateblock, D3D8_HANDLE_SB);
1873     wined3d_mutex_unlock();
1874 
1875     if (*token == D3D8_INVALID_HANDLE)
1876     {
1877         ERR("Failed to create a handle\n");
1878         wined3d_mutex_lock();
1879         wined3d_stateblock_decref(stateblock);
1880         wined3d_mutex_unlock();
1881         return E_FAIL;
1882     }
1883     ++*token;
1884 
1885     TRACE("Returning %#x (%p).\n", *token, stateblock);
1886 
1887     return hr;
1888 }
1889 
1890 static HRESULT WINAPI d3d8_device_ApplyStateBlock(IDirect3DDevice8 *iface, DWORD token)
1891 {
1892     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1893     struct wined3d_stateblock *stateblock;
1894 
1895     TRACE("iface %p, token %#x.\n", iface, token);
1896 
1897     if (!token)
1898         return D3D_OK;
1899 
1900     wined3d_mutex_lock();
1901     stateblock = d3d8_get_object(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1902     if (!stateblock)
1903     {
1904         WARN("Invalid handle (%#x) passed.\n", token);
1905         wined3d_mutex_unlock();
1906         return D3DERR_INVALIDCALL;
1907     }
1908     wined3d_stateblock_apply(stateblock);
1909     wined3d_mutex_unlock();
1910 
1911     return D3D_OK;
1912 }
1913 
1914 static HRESULT WINAPI d3d8_device_CaptureStateBlock(IDirect3DDevice8 *iface, DWORD token)
1915 {
1916     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1917     struct wined3d_stateblock *stateblock;
1918 
1919     TRACE("iface %p, token %#x.\n", iface, token);
1920 
1921     wined3d_mutex_lock();
1922     stateblock = d3d8_get_object(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1923     if (!stateblock)
1924     {
1925         WARN("Invalid handle (%#x) passed.\n", token);
1926         wined3d_mutex_unlock();
1927         return D3DERR_INVALIDCALL;
1928     }
1929     wined3d_stateblock_capture(stateblock);
1930     wined3d_mutex_unlock();
1931 
1932     return D3D_OK;
1933 }
1934 
1935 static HRESULT WINAPI d3d8_device_DeleteStateBlock(IDirect3DDevice8 *iface, DWORD token)
1936 {
1937     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1938     struct wined3d_stateblock *stateblock;
1939 
1940     TRACE("iface %p, token %#x.\n", iface, token);
1941 
1942     wined3d_mutex_lock();
1943     stateblock = d3d8_free_handle(&device->handle_table, token - 1, D3D8_HANDLE_SB);
1944 
1945     if (!stateblock)
1946     {
1947         WARN("Invalid handle (%#x) passed.\n", token);
1948         wined3d_mutex_unlock();
1949         return D3DERR_INVALIDCALL;
1950     }
1951 
1952     if (wined3d_stateblock_decref(stateblock))
1953     {
1954         ERR("Stateblock %p has references left, this shouldn't happen.\n", stateblock);
1955     }
1956     wined3d_mutex_unlock();
1957 
1958     return D3D_OK;
1959 }
1960 
1961 static HRESULT WINAPI d3d8_device_CreateStateBlock(IDirect3DDevice8 *iface,
1962         D3DSTATEBLOCKTYPE type, DWORD *handle)
1963 {
1964     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
1965     struct wined3d_stateblock *stateblock;
1966     HRESULT hr;
1967 
1968     TRACE("iface %p, type %#x, handle %p.\n", iface, type, handle);
1969 
1970     if (type != D3DSBT_ALL
1971             && type != D3DSBT_PIXELSTATE
1972             && type != D3DSBT_VERTEXSTATE)
1973     {
1974         WARN("Unexpected stateblock type, returning D3DERR_INVALIDCALL\n");
1975         return D3DERR_INVALIDCALL;
1976     }
1977 
1978     wined3d_mutex_lock();
1979     hr = wined3d_stateblock_create(device->wined3d_device, (enum wined3d_stateblock_type)type, &stateblock);
1980     if (FAILED(hr))
1981     {
1982         wined3d_mutex_unlock();
1983         ERR("Failed to create the state block, hr %#x\n", hr);
1984         return hr;
1985     }
1986 
1987     *handle = d3d8_allocate_handle(&device->handle_table, stateblock, D3D8_HANDLE_SB);
1988     wined3d_mutex_unlock();
1989 
1990     if (*handle == D3D8_INVALID_HANDLE)
1991     {
1992         ERR("Failed to allocate a handle.\n");
1993         wined3d_mutex_lock();
1994         wined3d_stateblock_decref(stateblock);
1995         wined3d_mutex_unlock();
1996         return E_FAIL;
1997     }
1998     ++*handle;
1999 
2000     TRACE("Returning %#x (%p).\n", *handle, stateblock);
2001 
2002     return hr;
2003 }
2004 
2005 static HRESULT WINAPI d3d8_device_SetClipStatus(IDirect3DDevice8 *iface, const D3DCLIPSTATUS8 *clip_status)
2006 {
2007     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2008     HRESULT hr;
2009 
2010     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
2011     /* FIXME: Verify that D3DCLIPSTATUS8 ~= struct wined3d_clip_status. */
2012 
2013     wined3d_mutex_lock();
2014     hr = wined3d_device_set_clip_status(device->wined3d_device, (const struct wined3d_clip_status *)clip_status);
2015     wined3d_mutex_unlock();
2016 
2017     return hr;
2018 }
2019 
2020 static HRESULT WINAPI d3d8_device_GetClipStatus(IDirect3DDevice8 *iface, D3DCLIPSTATUS8 *clip_status)
2021 {
2022     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2023     HRESULT hr;
2024 
2025     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
2026 
2027     wined3d_mutex_lock();
2028     hr = wined3d_device_get_clip_status(device->wined3d_device, (struct wined3d_clip_status *)clip_status);
2029     wined3d_mutex_unlock();
2030 
2031     return hr;
2032 }
2033 
2034 static HRESULT WINAPI d3d8_device_GetTexture(IDirect3DDevice8 *iface, DWORD stage, IDirect3DBaseTexture8 **texture)
2035 {
2036     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2037     struct wined3d_texture *wined3d_texture;
2038     struct d3d8_texture *texture_impl;
2039 
2040     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
2041 
2042     if (!texture)
2043         return D3DERR_INVALIDCALL;
2044 
2045     wined3d_mutex_lock();
2046     if ((wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
2047     {
2048         texture_impl = wined3d_texture_get_parent(wined3d_texture);
2049         *texture = &texture_impl->IDirect3DBaseTexture8_iface;
2050         IDirect3DBaseTexture8_AddRef(*texture);
2051     }
2052     else
2053     {
2054         *texture = NULL;
2055     }
2056     wined3d_mutex_unlock();
2057 
2058     return D3D_OK;
2059 }
2060 
2061 static HRESULT WINAPI d3d8_device_SetTexture(IDirect3DDevice8 *iface, DWORD stage, IDirect3DBaseTexture8 *texture)
2062 {
2063     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2064     struct d3d8_texture *texture_impl;
2065     HRESULT hr;
2066 
2067     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
2068 
2069     texture_impl = unsafe_impl_from_IDirect3DBaseTexture8(texture);
2070 
2071     wined3d_mutex_lock();
2072     hr = wined3d_device_set_texture(device->wined3d_device, stage,
2073             texture_impl ? texture_impl->wined3d_texture : NULL);
2074     wined3d_mutex_unlock();
2075 
2076     return hr;
2077 }
2078 
2079 static const struct tss_lookup
2080 {
2081     BOOL sampler_state;
2082     union
2083     {
2084         enum wined3d_texture_stage_state texture_state;
2085         enum wined3d_sampler_state sampler_state;
2086     } u;
2087 }
2088 tss_lookup[] =
2089 {
2090     {FALSE, {WINED3D_TSS_INVALID}},                   /*  0, unused */
2091     {FALSE, {WINED3D_TSS_COLOR_OP}},                  /*  1, D3DTSS_COLOROP */
2092     {FALSE, {WINED3D_TSS_COLOR_ARG1}},                /*  2, D3DTSS_COLORARG1 */
2093     {FALSE, {WINED3D_TSS_COLOR_ARG2}},                /*  3, D3DTSS_COLORARG2 */
2094     {FALSE, {WINED3D_TSS_ALPHA_OP}},                  /*  4, D3DTSS_ALPHAOP */
2095     {FALSE, {WINED3D_TSS_ALPHA_ARG1}},                /*  5, D3DTSS_ALPHAARG1 */
2096     {FALSE, {WINED3D_TSS_ALPHA_ARG2}},                /*  6, D3DTSS_ALPHAARG2 */
2097     {FALSE, {WINED3D_TSS_BUMPENV_MAT00}},             /*  7, D3DTSS_BUMPENVMAT00 */
2098     {FALSE, {WINED3D_TSS_BUMPENV_MAT01}},             /*  8, D3DTSS_BUMPENVMAT01 */
2099     {FALSE, {WINED3D_TSS_BUMPENV_MAT10}},             /*  9, D3DTSS_BUMPENVMAT10 */
2100     {FALSE, {WINED3D_TSS_BUMPENV_MAT11}},             /* 10, D3DTSS_BUMPENVMAT11 */
2101     {FALSE, {WINED3D_TSS_TEXCOORD_INDEX}},            /* 11, D3DTSS_TEXCOORDINDEX */
2102     {FALSE, {WINED3D_TSS_INVALID}},                   /* 12, unused */
2103     {TRUE,  {WINED3D_SAMP_ADDRESS_U}},                /* 13, D3DTSS_ADDRESSU */
2104     {TRUE,  {WINED3D_SAMP_ADDRESS_V}},                /* 14, D3DTSS_ADDRESSV */
2105     {TRUE,  {WINED3D_SAMP_BORDER_COLOR}},             /* 15, D3DTSS_BORDERCOLOR */
2106     {TRUE,  {WINED3D_SAMP_MAG_FILTER}},               /* 16, D3DTSS_MAGFILTER */
2107     {TRUE,  {WINED3D_SAMP_MIN_FILTER}},               /* 17, D3DTSS_MINFILTER */
2108     {TRUE,  {WINED3D_SAMP_MIP_FILTER}},               /* 18, D3DTSS_MIPFILTER */
2109     {TRUE,  {WINED3D_SAMP_MIPMAP_LOD_BIAS}},          /* 19, D3DTSS_MIPMAPLODBIAS */
2110     {TRUE,  {WINED3D_SAMP_MAX_MIP_LEVEL}},            /* 20, D3DTSS_MAXMIPLEVEL */
2111     {TRUE,  {WINED3D_SAMP_MAX_ANISOTROPY}},           /* 21, D3DTSS_MAXANISOTROPY */
2112     {FALSE, {WINED3D_TSS_BUMPENV_LSCALE}},            /* 22, D3DTSS_BUMPENVLSCALE */
2113     {FALSE, {WINED3D_TSS_BUMPENV_LOFFSET}},           /* 23, D3DTSS_BUMPENVLOFFSET */
2114     {FALSE, {WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS}},   /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
2115     {TRUE,  {WINED3D_SAMP_ADDRESS_W}},                /* 25, D3DTSS_ADDRESSW */
2116     {FALSE, {WINED3D_TSS_COLOR_ARG0}},                /* 26, D3DTSS_COLORARG0 */
2117     {FALSE, {WINED3D_TSS_ALPHA_ARG0}},                /* 27, D3DTSS_ALPHAARG0 */
2118     {FALSE, {WINED3D_TSS_RESULT_ARG}},                /* 28, D3DTSS_RESULTARG */
2119 };
2120 
2121 static HRESULT WINAPI d3d8_device_GetTextureStageState(IDirect3DDevice8 *iface,
2122         DWORD stage, D3DTEXTURESTAGESTATETYPE Type, DWORD *value)
2123 {
2124     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2125     const struct tss_lookup *l;
2126 
2127     TRACE("iface %p, stage %u, state %#x, value %p.\n", iface, stage, Type, value);
2128 
2129     if (Type >= sizeof(tss_lookup) / sizeof(*tss_lookup))
2130     {
2131         WARN("Invalid Type %#x passed.\n", Type);
2132         return D3D_OK;
2133     }
2134 
2135     l = &tss_lookup[Type];
2136 
2137     wined3d_mutex_lock();
2138     if (l->sampler_state)
2139         *value = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->u.sampler_state);
2140     else
2141         *value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->u.texture_state);
2142     wined3d_mutex_unlock();
2143 
2144     return D3D_OK;
2145 }
2146 
2147 static HRESULT WINAPI d3d8_device_SetTextureStageState(IDirect3DDevice8 *iface,
2148         DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
2149 {
2150     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2151     const struct tss_lookup *l;
2152 
2153     TRACE("iface %p, stage %u, state %#x, value %#x.\n", iface, stage, type, value);
2154 
2155     if (type >= sizeof(tss_lookup) / sizeof(*tss_lookup))
2156     {
2157         WARN("Invalid type %#x passed.\n", type);
2158         return D3D_OK;
2159     }
2160 
2161     l = &tss_lookup[type];
2162 
2163     wined3d_mutex_lock();
2164     if (l->sampler_state)
2165         wined3d_device_set_sampler_state(device->wined3d_device, stage, l->u.sampler_state, value);
2166     else
2167         wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->u.texture_state, value);
2168     wined3d_mutex_unlock();
2169 
2170     return D3D_OK;
2171 }
2172 
2173 static HRESULT WINAPI d3d8_device_ValidateDevice(IDirect3DDevice8 *iface, DWORD *pass_count)
2174 {
2175     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2176     HRESULT hr;
2177 
2178     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
2179 
2180     wined3d_mutex_lock();
2181     hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
2182     wined3d_mutex_unlock();
2183 
2184     return hr;
2185 }
2186 
2187 static HRESULT WINAPI d3d8_device_GetInfo(IDirect3DDevice8 *iface,
2188         DWORD info_id, void *info, DWORD info_size)
2189 {
2190     TRACE("iface %p, info_id %#x, info %p, info_size %u.\n", iface, info_id, info, info_size);
2191 
2192     if (info_id < 4)
2193         return E_FAIL;
2194     return S_FALSE;
2195 }
2196 
2197 static HRESULT WINAPI d3d8_device_SetPaletteEntries(IDirect3DDevice8 *iface,
2198         UINT palette_idx, const PALETTEENTRY *entries)
2199 {
2200     WARN("iface %p, palette_idx %u, entries %p unimplemented\n", iface, palette_idx, entries);
2201 
2202     /* GPUs stopped supporting palettized textures with the Shader Model 1 generation. Wined3d
2203      * does not have a d3d8/9-style palette API */
2204 
2205     return D3D_OK;
2206 }
2207 
2208 static HRESULT WINAPI d3d8_device_GetPaletteEntries(IDirect3DDevice8 *iface,
2209         UINT palette_idx, PALETTEENTRY *entries)
2210 {
2211     FIXME("iface %p, palette_idx %u, entries %p unimplemented.\n", iface, palette_idx, entries);
2212 
2213     return D3DERR_INVALIDCALL;
2214 }
2215 
2216 static HRESULT WINAPI d3d8_device_SetCurrentTexturePalette(IDirect3DDevice8 *iface, UINT palette_idx)
2217 {
2218     WARN("iface %p, palette_idx %u unimplemented.\n", iface, palette_idx);
2219 
2220     return D3D_OK;
2221 }
2222 
2223 static HRESULT WINAPI d3d8_device_GetCurrentTexturePalette(IDirect3DDevice8 *iface, UINT *palette_idx)
2224 {
2225     FIXME("iface %p, palette_idx %p unimplemented.\n", iface, palette_idx);
2226 
2227     return D3DERR_INVALIDCALL;
2228 }
2229 
2230 static HRESULT WINAPI d3d8_device_DrawPrimitive(IDirect3DDevice8 *iface,
2231         D3DPRIMITIVETYPE primitive_type, UINT start_vertex, UINT primitive_count)
2232 {
2233     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2234     HRESULT hr;
2235 
2236     TRACE("iface %p, primitive_type %#x, start_vertex %u, primitive_count %u.\n",
2237             iface, primitive_type, start_vertex, primitive_count);
2238 
2239     wined3d_mutex_lock();
2240     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2241     hr = wined3d_device_draw_primitive(device->wined3d_device, start_vertex,
2242             vertex_count_from_primitive_count(primitive_type, primitive_count));
2243     wined3d_mutex_unlock();
2244 
2245     return hr;
2246 }
2247 
2248 static HRESULT WINAPI d3d8_device_DrawIndexedPrimitive(IDirect3DDevice8 *iface,
2249         D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
2250         UINT start_idx, UINT primitive_count)
2251 {
2252     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2253     HRESULT hr;
2254 
2255     TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, start_idx %u, primitive_count %u.\n",
2256             iface, primitive_type, min_vertex_idx, vertex_count, start_idx, primitive_count);
2257 
2258     wined3d_mutex_lock();
2259     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2260     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, start_idx,
2261             vertex_count_from_primitive_count(primitive_type, primitive_count));
2262     wined3d_mutex_unlock();
2263 
2264     return hr;
2265 }
2266 
2267 /* The caller is responsible for wined3d locking */
2268 static HRESULT d3d8_device_prepare_vertex_buffer(struct d3d8_device *device, UINT min_size)
2269 {
2270     HRESULT hr;
2271 
2272     if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
2273     {
2274         UINT size = max(device->vertex_buffer_size * 2, min_size);
2275         struct wined3d_buffer_desc desc;
2276         struct wined3d_buffer *buffer;
2277 
2278         TRACE("Growing vertex buffer to %u bytes\n", size);
2279 
2280         desc.byte_width = size;
2281         desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY;
2282         desc.bind_flags = WINED3D_BIND_VERTEX_BUFFER;
2283         desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
2284         desc.misc_flags = 0;
2285         desc.structure_byte_stride = 0;
2286 
2287         if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
2288                 NULL, NULL, &d3d8_null_wined3d_parent_ops, &buffer)))
2289         {
2290             ERR("Failed to create vertex buffer, hr %#x.\n", hr);
2291             return hr;
2292         }
2293 
2294         if (device->vertex_buffer)
2295             wined3d_buffer_decref(device->vertex_buffer);
2296 
2297         device->vertex_buffer = buffer;
2298         device->vertex_buffer_size = size;
2299         device->vertex_buffer_pos = 0;
2300     }
2301     return D3D_OK;
2302 }
2303 
2304 static HRESULT WINAPI d3d8_device_DrawPrimitiveUP(IDirect3DDevice8 *iface,
2305         D3DPRIMITIVETYPE primitive_type, UINT primitive_count, const void *data,
2306         UINT stride)
2307 {
2308     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2309     HRESULT hr;
2310     UINT vtx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
2311     struct wined3d_map_desc wined3d_map_desc;
2312     struct wined3d_box wined3d_box = {0};
2313     UINT size = vtx_count * stride;
2314     struct wined3d_resource *vb;
2315     UINT vb_pos, align;
2316 
2317     TRACE("iface %p, primitive_type %#x, primitive_count %u, data %p, stride %u.\n",
2318             iface, primitive_type, primitive_count, data, stride);
2319 
2320     if (!primitive_count)
2321     {
2322         WARN("primitive_count is 0, returning D3D_OK\n");
2323         return D3D_OK;
2324     }
2325 
2326     wined3d_mutex_lock();
2327     hr = d3d8_device_prepare_vertex_buffer(device, size);
2328     if (FAILED(hr))
2329         goto done;
2330 
2331     vb_pos = device->vertex_buffer_pos;
2332     align = vb_pos % stride;
2333     if (align) align = stride - align;
2334     if (vb_pos + size + align > device->vertex_buffer_size)
2335         vb_pos = 0;
2336     else
2337         vb_pos += align;
2338 
2339     wined3d_box.left = vb_pos;
2340     wined3d_box.right = vb_pos + size;
2341     vb = wined3d_buffer_get_resource(device->vertex_buffer);
2342     if (FAILED(wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
2343             WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
2344         goto done;
2345     memcpy(wined3d_map_desc.data, data, size);
2346     wined3d_resource_unmap(vb, 0);
2347     device->vertex_buffer_pos = vb_pos + size;
2348 
2349     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
2350     if (FAILED(hr))
2351         goto done;
2352 
2353     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2354     hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vtx_count);
2355     wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
2356 
2357 done:
2358     wined3d_mutex_unlock();
2359     return hr;
2360 }
2361 
2362 /* The caller is responsible for wined3d locking */
2363 static HRESULT d3d8_device_prepare_index_buffer(struct d3d8_device *device, UINT min_size)
2364 {
2365     HRESULT hr;
2366 
2367     if (device->index_buffer_size < min_size || !device->index_buffer)
2368     {
2369         UINT size = max(device->index_buffer_size * 2, min_size);
2370         struct wined3d_buffer_desc desc;
2371         struct wined3d_buffer *buffer;
2372 
2373         TRACE("Growing index buffer to %u bytes\n", size);
2374 
2375         desc.byte_width = size;
2376         desc.usage = WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_STATICDECL;
2377         desc.bind_flags = WINED3D_BIND_INDEX_BUFFER;
2378         desc.access = WINED3D_RESOURCE_ACCESS_GPU | WINED3D_RESOURCE_ACCESS_MAP_R | WINED3D_RESOURCE_ACCESS_MAP_W;
2379         desc.misc_flags = 0;
2380         desc.structure_byte_stride = 0;
2381 
2382         if (FAILED(hr = wined3d_buffer_create(device->wined3d_device, &desc,
2383                 NULL, NULL, &d3d8_null_wined3d_parent_ops, &buffer)))
2384         {
2385             ERR("Failed to create index buffer, hr %#x.\n", hr);
2386             return hr;
2387         }
2388 
2389         if (device->index_buffer)
2390             wined3d_buffer_decref(device->index_buffer);
2391 
2392         device->index_buffer = buffer;
2393         device->index_buffer_size = size;
2394         device->index_buffer_pos = 0;
2395     }
2396     return D3D_OK;
2397 }
2398 
2399 static HRESULT WINAPI d3d8_device_DrawIndexedPrimitiveUP(IDirect3DDevice8 *iface,
2400         D3DPRIMITIVETYPE primitive_type, UINT min_vertex_idx, UINT vertex_count,
2401         UINT primitive_count, const void *index_data, D3DFORMAT index_format,
2402         const void *vertex_data, UINT vertex_stride)
2403 {
2404     UINT idx_count = vertex_count_from_primitive_count(primitive_type, primitive_count);
2405     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2406     UINT idx_fmt_size = index_format == D3DFMT_INDEX16 ? 2 : 4;
2407     UINT vtx_size = vertex_count * vertex_stride;
2408     UINT idx_size = idx_count * idx_fmt_size;
2409     struct wined3d_map_desc wined3d_map_desc;
2410     struct wined3d_box wined3d_box = {0};
2411     struct wined3d_resource *ib, *vb;
2412     UINT vb_pos, ib_pos, align;
2413     HRESULT hr;
2414 
2415     TRACE("iface %p, primitive_type %#x, min_vertex_idx %u, vertex_count %u, primitive_count %u, "
2416             "index_data %p, index_format %#x, vertex_data %p, vertex_stride %u.\n",
2417             iface, primitive_type, min_vertex_idx, vertex_count, primitive_count,
2418             index_data, index_format, vertex_data, vertex_stride);
2419 
2420     if (!primitive_count)
2421     {
2422         WARN("primitive_count is 0, returning D3D_OK\n");
2423         return D3D_OK;
2424     }
2425 
2426     wined3d_mutex_lock();
2427 
2428     hr = d3d8_device_prepare_vertex_buffer(device, vtx_size);
2429     if (FAILED(hr))
2430         goto done;
2431 
2432     vb_pos = device->vertex_buffer_pos;
2433     align = vb_pos % vertex_stride;
2434     if (align) align = vertex_stride - align;
2435     if (vb_pos + vtx_size + align > device->vertex_buffer_size)
2436         vb_pos = 0;
2437     else
2438         vb_pos += align;
2439 
2440     wined3d_box.left = vb_pos;
2441     wined3d_box.right = vb_pos + vtx_size;
2442     vb = wined3d_buffer_get_resource(device->vertex_buffer);
2443     if (FAILED(hr = wined3d_resource_map(vb, 0, &wined3d_map_desc, &wined3d_box,
2444             WINED3D_MAP_WRITE | (vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
2445         goto done;
2446     memcpy(wined3d_map_desc.data, (char *)vertex_data + min_vertex_idx * vertex_stride, vtx_size);
2447     wined3d_resource_unmap(vb, 0);
2448     device->vertex_buffer_pos = vb_pos + vtx_size;
2449 
2450     hr = d3d8_device_prepare_index_buffer(device, idx_size);
2451     if (FAILED(hr))
2452         goto done;
2453 
2454     ib_pos = device->index_buffer_pos;
2455     align = ib_pos % idx_fmt_size;
2456     if (align) align = idx_fmt_size - align;
2457     if (ib_pos + idx_size + align > device->index_buffer_size)
2458         ib_pos = 0;
2459     else
2460         ib_pos += align;
2461 
2462     wined3d_box.left = ib_pos;
2463     wined3d_box.right = ib_pos + idx_size;
2464     ib = wined3d_buffer_get_resource(device->index_buffer);
2465     if (FAILED(hr = wined3d_resource_map(ib, 0, &wined3d_map_desc, &wined3d_box,
2466             WINED3D_MAP_WRITE | (ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD))))
2467         goto done;
2468     memcpy(wined3d_map_desc.data, index_data, idx_size);
2469     wined3d_resource_unmap(ib, 0);
2470     device->index_buffer_pos = ib_pos + idx_size;
2471 
2472     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, vertex_stride);
2473     if (FAILED(hr))
2474         goto done;
2475 
2476     wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer,
2477             wined3dformat_from_d3dformat(index_format), 0);
2478     wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / vertex_stride - min_vertex_idx);
2479 
2480     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type, 0);
2481     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / idx_fmt_size, idx_count);
2482 
2483     wined3d_device_set_stream_source(device->wined3d_device, 0, NULL, 0, 0);
2484     wined3d_device_set_index_buffer(device->wined3d_device, NULL, WINED3DFMT_UNKNOWN, 0);
2485     wined3d_device_set_base_vertex_index(device->wined3d_device, 0);
2486 
2487 done:
2488     wined3d_mutex_unlock();
2489     return hr;
2490 }
2491 
2492 static HRESULT WINAPI d3d8_device_ProcessVertices(IDirect3DDevice8 *iface, UINT src_start_idx,
2493         UINT dst_idx, UINT vertex_count, IDirect3DVertexBuffer8 *dst_buffer, DWORD flags)
2494 {
2495     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2496     struct d3d8_vertexbuffer *dst = unsafe_impl_from_IDirect3DVertexBuffer8(dst_buffer);
2497     HRESULT hr;
2498 
2499     TRACE("iface %p, src_start_idx %u, dst_idx %u, vertex_count %u, dst_buffer %p, flags %#x.\n",
2500             iface, src_start_idx, dst_idx, vertex_count, dst_buffer, flags);
2501 
2502     wined3d_mutex_lock();
2503     hr = wined3d_device_process_vertices(device->wined3d_device, src_start_idx, dst_idx,
2504             vertex_count, dst->wined3d_buffer, NULL, flags, dst->fvf);
2505     wined3d_mutex_unlock();
2506 
2507     return hr;
2508 }
2509 
2510 static HRESULT WINAPI d3d8_device_CreateVertexShader(IDirect3DDevice8 *iface,
2511         const DWORD *declaration, const DWORD *byte_code, DWORD *shader, DWORD usage)
2512 {
2513     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2514     struct d3d8_vertex_shader *object;
2515     DWORD shader_handle;
2516     DWORD handle;
2517     HRESULT hr;
2518 
2519     TRACE("iface %p, declaration %p, byte_code %p, shader %p, usage %#x.\n",
2520             iface, declaration, byte_code, shader, usage);
2521 
2522     if (!(object = heap_alloc_zero(sizeof(*object))))
2523     {
2524         *shader = 0;
2525         return E_OUTOFMEMORY;
2526     }
2527 
2528     wined3d_mutex_lock();
2529     handle = d3d8_allocate_handle(&device->handle_table, object, D3D8_HANDLE_VS);
2530     wined3d_mutex_unlock();
2531     if (handle == D3D8_INVALID_HANDLE)
2532     {
2533         ERR("Failed to allocate vertex shader handle.\n");
2534         heap_free(object);
2535         *shader = 0;
2536         return E_OUTOFMEMORY;
2537     }
2538 
2539     shader_handle = handle + VS_HIGHESTFIXEDFXF + 1;
2540 
2541     hr = d3d8_vertex_shader_init(object, device, declaration, byte_code, shader_handle, usage);
2542     if (FAILED(hr))
2543     {
2544         WARN("Failed to initialize vertex shader, hr %#x.\n", hr);
2545         wined3d_mutex_lock();
2546         d3d8_free_handle(&device->handle_table, handle, D3D8_HANDLE_VS);
2547         wined3d_mutex_unlock();
2548         heap_free(object);
2549         *shader = 0;
2550         return hr;
2551     }
2552 
2553     TRACE("Created vertex shader %p (handle %#x).\n", object, shader_handle);
2554     *shader = shader_handle;
2555 
2556     return D3D_OK;
2557 }
2558 
2559 static struct d3d8_vertex_declaration *d3d8_device_get_fvf_declaration(struct d3d8_device *device, DWORD fvf)
2560 {
2561     struct d3d8_vertex_declaration *d3d8_declaration;
2562     struct FvfToDecl *convertedDecls = device->decls;
2563     int p, low, high; /* deliberately signed */
2564     HRESULT hr;
2565 
2566     TRACE("Searching for declaration for fvf %08x... ", fvf);
2567 
2568     low = 0;
2569     high = device->numConvertedDecls - 1;
2570     while (low <= high)
2571     {
2572         p = (low + high) >> 1;
2573         TRACE("%d ", p);
2574 
2575         if (convertedDecls[p].fvf == fvf)
2576         {
2577             TRACE("found %p\n", convertedDecls[p].declaration);
2578             return convertedDecls[p].declaration;
2579         }
2580 
2581         if (convertedDecls[p].fvf < fvf)
2582             low = p + 1;
2583         else
2584             high = p - 1;
2585     }
2586     TRACE("not found. Creating and inserting at position %d.\n", low);
2587 
2588     if (!(d3d8_declaration = heap_alloc(sizeof(*d3d8_declaration))))
2589         return NULL;
2590 
2591     if (FAILED(hr = d3d8_vertex_declaration_init_fvf(d3d8_declaration, device, fvf)))
2592     {
2593         WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
2594         heap_free(d3d8_declaration);
2595         return NULL;
2596     }
2597 
2598     if (device->declArraySize == device->numConvertedDecls)
2599     {
2600         UINT grow = device->declArraySize / 2;
2601 
2602         if (!(convertedDecls = heap_realloc(convertedDecls,
2603                 sizeof(*convertedDecls) * (device->numConvertedDecls + grow))))
2604         {
2605             d3d8_vertex_declaration_destroy(d3d8_declaration);
2606             return NULL;
2607         }
2608         device->decls = convertedDecls;
2609         device->declArraySize += grow;
2610     }
2611 
2612     memmove(convertedDecls + low + 1, convertedDecls + low,
2613             sizeof(*convertedDecls) * (device->numConvertedDecls - low));
2614     convertedDecls[low].declaration = d3d8_declaration;
2615     convertedDecls[low].fvf = fvf;
2616     ++device->numConvertedDecls;
2617 
2618     TRACE("Returning %p. %u decls in array.\n", d3d8_declaration, device->numConvertedDecls);
2619 
2620     return d3d8_declaration;
2621 }
2622 
2623 static HRESULT WINAPI d3d8_device_SetVertexShader(IDirect3DDevice8 *iface, DWORD shader)
2624 {
2625     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2626     struct d3d8_vertex_shader *shader_impl;
2627 
2628     TRACE("iface %p, shader %#x.\n", iface, shader);
2629 
2630     if (VS_HIGHESTFIXEDFXF >= shader)
2631     {
2632         TRACE("Setting FVF, %#x\n", shader);
2633 
2634         wined3d_mutex_lock();
2635         wined3d_device_set_vertex_declaration(device->wined3d_device,
2636                 d3d8_device_get_fvf_declaration(device, shader)->wined3d_vertex_declaration);
2637         wined3d_device_set_vertex_shader(device->wined3d_device, NULL);
2638         wined3d_mutex_unlock();
2639 
2640         return D3D_OK;
2641     }
2642 
2643     TRACE("Setting shader\n");
2644 
2645     wined3d_mutex_lock();
2646     if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2647     {
2648         WARN("Invalid handle (%#x) passed.\n", shader);
2649         wined3d_mutex_unlock();
2650 
2651         return D3DERR_INVALIDCALL;
2652     }
2653 
2654     wined3d_device_set_vertex_declaration(device->wined3d_device,
2655             shader_impl->vertex_declaration->wined3d_vertex_declaration);
2656     wined3d_device_set_vertex_shader(device->wined3d_device, shader_impl->wined3d_shader);
2657     wined3d_mutex_unlock();
2658 
2659     return D3D_OK;
2660 }
2661 
2662 static HRESULT WINAPI d3d8_device_GetVertexShader(IDirect3DDevice8 *iface, DWORD *shader)
2663 {
2664     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2665     struct wined3d_vertex_declaration *wined3d_declaration;
2666     struct d3d8_vertex_declaration *d3d8_declaration;
2667 
2668     TRACE("iface %p, shader %p.\n", iface, shader);
2669 
2670     wined3d_mutex_lock();
2671     if ((wined3d_declaration = wined3d_device_get_vertex_declaration(device->wined3d_device)))
2672     {
2673         d3d8_declaration = wined3d_vertex_declaration_get_parent(wined3d_declaration);
2674         *shader = d3d8_declaration->shader_handle;
2675     }
2676     else
2677     {
2678         *shader = 0;
2679     }
2680     wined3d_mutex_unlock();
2681 
2682     TRACE("Returning %#x.\n", *shader);
2683 
2684     return D3D_OK;
2685 }
2686 
2687 static HRESULT WINAPI d3d8_device_DeleteVertexShader(IDirect3DDevice8 *iface, DWORD shader)
2688 {
2689     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2690     struct d3d8_vertex_shader *shader_impl;
2691 
2692     TRACE("iface %p, shader %#x.\n", iface, shader);
2693 
2694     wined3d_mutex_lock();
2695     if (!(shader_impl = d3d8_free_handle(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2696     {
2697         WARN("Invalid handle (%#x) passed.\n", shader);
2698         wined3d_mutex_unlock();
2699 
2700         return D3DERR_INVALIDCALL;
2701     }
2702 
2703     if (shader_impl->wined3d_shader
2704             && wined3d_device_get_vertex_shader(device->wined3d_device) == shader_impl->wined3d_shader)
2705         IDirect3DDevice8_SetVertexShader(iface, 0);
2706 
2707     wined3d_mutex_unlock();
2708 
2709     d3d8_vertex_shader_destroy(shader_impl);
2710 
2711     return D3D_OK;
2712 }
2713 
2714 static HRESULT WINAPI d3d8_device_SetVertexShaderConstant(IDirect3DDevice8 *iface,
2715         DWORD start_register, const void *data, DWORD count)
2716 {
2717     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2718     HRESULT hr;
2719 
2720     TRACE("iface %p, start_register %u, data %p, count %u.\n",
2721             iface, start_register, data, count);
2722 
2723     if (start_register + count > D3D8_MAX_VERTEX_SHADER_CONSTANTF)
2724     {
2725         WARN("Trying to access %u constants, but d3d8 only supports %u\n",
2726              start_register + count, D3D8_MAX_VERTEX_SHADER_CONSTANTF);
2727         return D3DERR_INVALIDCALL;
2728     }
2729 
2730     wined3d_mutex_lock();
2731     hr = wined3d_device_set_vs_consts_f(device->wined3d_device, start_register, count, data);
2732     wined3d_mutex_unlock();
2733 
2734     return hr;
2735 }
2736 
2737 static HRESULT WINAPI d3d8_device_GetVertexShaderConstant(IDirect3DDevice8 *iface,
2738         DWORD start_register, void *data, DWORD count)
2739 {
2740     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2741     HRESULT hr;
2742 
2743     TRACE("iface %p, start_register %u, data %p, count %u.\n",
2744             iface, start_register, data, count);
2745 
2746     if (start_register + count > D3D8_MAX_VERTEX_SHADER_CONSTANTF)
2747     {
2748         WARN("Trying to access %u constants, but d3d8 only supports %u\n",
2749              start_register + count, D3D8_MAX_VERTEX_SHADER_CONSTANTF);
2750         return D3DERR_INVALIDCALL;
2751     }
2752 
2753     wined3d_mutex_lock();
2754     hr = wined3d_device_get_vs_consts_f(device->wined3d_device, start_register, count, data);
2755     wined3d_mutex_unlock();
2756 
2757     return hr;
2758 }
2759 
2760 static HRESULT WINAPI d3d8_device_GetVertexShaderDeclaration(IDirect3DDevice8 *iface,
2761         DWORD shader, void *data, DWORD *data_size)
2762 {
2763     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2764     struct d3d8_vertex_declaration *declaration;
2765     struct d3d8_vertex_shader *shader_impl;
2766 
2767     TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
2768             iface, shader, data, data_size);
2769 
2770     wined3d_mutex_lock();
2771     shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS);
2772     wined3d_mutex_unlock();
2773 
2774     if (!shader_impl)
2775     {
2776         WARN("Invalid handle (%#x) passed.\n", shader);
2777         return D3DERR_INVALIDCALL;
2778     }
2779     declaration = shader_impl->vertex_declaration;
2780 
2781     if (!data)
2782     {
2783         *data_size = declaration->elements_size;
2784         return D3D_OK;
2785     }
2786 
2787     /* MSDN claims that if *data_size is smaller than the required size
2788      * we should write the required size and return D3DERR_MOREDATA.
2789      * That's not actually true. */
2790     if (*data_size < declaration->elements_size)
2791         return D3DERR_INVALIDCALL;
2792 
2793     memcpy(data, declaration->elements, declaration->elements_size);
2794 
2795     return D3D_OK;
2796 }
2797 
2798 static HRESULT WINAPI d3d8_device_GetVertexShaderFunction(IDirect3DDevice8 *iface,
2799         DWORD shader, void *data, DWORD *data_size)
2800 {
2801     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2802     struct d3d8_vertex_shader *shader_impl = NULL;
2803     HRESULT hr;
2804 
2805     TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
2806             iface, shader, data, data_size);
2807 
2808     wined3d_mutex_lock();
2809     if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_VS)))
2810     {
2811         WARN("Invalid handle (%#x) passed.\n", shader);
2812         wined3d_mutex_unlock();
2813 
2814         return D3DERR_INVALIDCALL;
2815     }
2816 
2817     if (!shader_impl->wined3d_shader)
2818     {
2819         wined3d_mutex_unlock();
2820         *data_size = 0;
2821         return D3D_OK;
2822     }
2823 
2824     hr = wined3d_shader_get_byte_code(shader_impl->wined3d_shader, data, data_size);
2825     wined3d_mutex_unlock();
2826 
2827     return hr;
2828 }
2829 
2830 static HRESULT WINAPI d3d8_device_SetIndices(IDirect3DDevice8 *iface,
2831         IDirect3DIndexBuffer8 *buffer, UINT base_vertex_idx)
2832 {
2833     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2834     struct d3d8_indexbuffer *ib = unsafe_impl_from_IDirect3DIndexBuffer8(buffer);
2835 
2836     TRACE("iface %p, buffer %p, base_vertex_idx %u.\n", iface, buffer, base_vertex_idx);
2837 
2838     /* WineD3D takes an INT(due to d3d9), but d3d8 uses UINTs. Do I have to add a check here that
2839      * the UINT doesn't cause an overflow in the INT? It seems rather unlikely because such large
2840      * vertex buffers can't be created to address them with an index that requires the 32nd bit
2841      * (4 Byte minimum vertex size * 2^31-1 -> 8 gb buffer. The index sign would be the least
2842      * problem)
2843      */
2844     wined3d_mutex_lock();
2845     wined3d_device_set_base_vertex_index(device->wined3d_device, base_vertex_idx);
2846     wined3d_device_set_index_buffer(device->wined3d_device,
2847             ib ? ib->wined3d_buffer : NULL, ib ? ib->format : WINED3DFMT_UNKNOWN, 0);
2848     wined3d_mutex_unlock();
2849 
2850     return D3D_OK;
2851 }
2852 
2853 static HRESULT WINAPI d3d8_device_GetIndices(IDirect3DDevice8 *iface,
2854         IDirect3DIndexBuffer8 **buffer, UINT *base_vertex_index)
2855 {
2856     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2857     enum wined3d_format_id wined3d_format;
2858     struct wined3d_buffer *wined3d_buffer;
2859     struct d3d8_indexbuffer *buffer_impl;
2860 
2861     TRACE("iface %p, buffer %p, base_vertex_index %p.\n", iface, buffer, base_vertex_index);
2862 
2863     if (!buffer)
2864         return D3DERR_INVALIDCALL;
2865 
2866     /* The case from UINT to INT is safe because d3d8 will never set negative values */
2867     wined3d_mutex_lock();
2868     *base_vertex_index = wined3d_device_get_base_vertex_index(device->wined3d_device);
2869     if ((wined3d_buffer = wined3d_device_get_index_buffer(device->wined3d_device, &wined3d_format, NULL)))
2870     {
2871         buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
2872         *buffer = &buffer_impl->IDirect3DIndexBuffer8_iface;
2873         IDirect3DIndexBuffer8_AddRef(*buffer);
2874     }
2875     else
2876     {
2877         *buffer = NULL;
2878     }
2879     wined3d_mutex_unlock();
2880 
2881     return D3D_OK;
2882 }
2883 
2884 static HRESULT WINAPI d3d8_device_CreatePixelShader(IDirect3DDevice8 *iface,
2885         const DWORD *byte_code, DWORD *shader)
2886 {
2887     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2888     struct d3d8_pixel_shader *object;
2889     DWORD shader_handle;
2890     DWORD handle;
2891     HRESULT hr;
2892 
2893     TRACE("iface %p, byte_code %p, shader %p.\n", iface, byte_code, shader);
2894 
2895     if (!shader)
2896         return D3DERR_INVALIDCALL;
2897 
2898     if (!(object = heap_alloc_zero(sizeof(*object))))
2899         return E_OUTOFMEMORY;
2900 
2901     wined3d_mutex_lock();
2902     handle = d3d8_allocate_handle(&device->handle_table, object, D3D8_HANDLE_PS);
2903     wined3d_mutex_unlock();
2904     if (handle == D3D8_INVALID_HANDLE)
2905     {
2906         ERR("Failed to allocate pixel shader handle.\n");
2907         heap_free(object);
2908         return E_OUTOFMEMORY;
2909     }
2910 
2911     shader_handle = handle + VS_HIGHESTFIXEDFXF + 1;
2912 
2913     hr = d3d8_pixel_shader_init(object, device, byte_code, shader_handle);
2914     if (FAILED(hr))
2915     {
2916         WARN("Failed to initialize pixel shader, hr %#x.\n", hr);
2917         wined3d_mutex_lock();
2918         d3d8_free_handle(&device->handle_table, handle, D3D8_HANDLE_PS);
2919         wined3d_mutex_unlock();
2920         heap_free(object);
2921         *shader = 0;
2922         return hr;
2923     }
2924 
2925     TRACE("Created pixel shader %p (handle %#x).\n", object, shader_handle);
2926     *shader = shader_handle;
2927 
2928     return D3D_OK;
2929 }
2930 
2931 static HRESULT WINAPI d3d8_device_SetPixelShader(IDirect3DDevice8 *iface, DWORD shader)
2932 {
2933     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2934     struct d3d8_pixel_shader *shader_impl;
2935 
2936     TRACE("iface %p, shader %#x.\n", iface, shader);
2937 
2938     wined3d_mutex_lock();
2939 
2940     if (!shader)
2941     {
2942         wined3d_device_set_pixel_shader(device->wined3d_device, NULL);
2943         wined3d_mutex_unlock();
2944         return D3D_OK;
2945     }
2946 
2947     if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
2948     {
2949         WARN("Invalid handle (%#x) passed.\n", shader);
2950         wined3d_mutex_unlock();
2951         return D3DERR_INVALIDCALL;
2952     }
2953 
2954     TRACE("Setting shader %p.\n", shader_impl);
2955     wined3d_device_set_pixel_shader(device->wined3d_device, shader_impl->wined3d_shader);
2956     wined3d_mutex_unlock();
2957 
2958     return D3D_OK;
2959 }
2960 
2961 static HRESULT WINAPI d3d8_device_GetPixelShader(IDirect3DDevice8 *iface, DWORD *shader)
2962 {
2963     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2964     struct wined3d_shader *object;
2965 
2966     TRACE("iface %p, shader %p.\n", iface, shader);
2967 
2968     if (!shader)
2969         return D3DERR_INVALIDCALL;
2970 
2971     wined3d_mutex_lock();
2972     if ((object = wined3d_device_get_pixel_shader(device->wined3d_device)))
2973     {
2974         struct d3d8_pixel_shader *d3d8_shader;
2975         d3d8_shader = wined3d_shader_get_parent(object);
2976         *shader = d3d8_shader->handle;
2977     }
2978     else
2979     {
2980         *shader = 0;
2981     }
2982     wined3d_mutex_unlock();
2983 
2984     TRACE("Returning %#x.\n", *shader);
2985 
2986     return D3D_OK;
2987 }
2988 
2989 static HRESULT WINAPI d3d8_device_DeletePixelShader(IDirect3DDevice8 *iface, DWORD shader)
2990 {
2991     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
2992     struct d3d8_pixel_shader *shader_impl;
2993 
2994     TRACE("iface %p, shader %#x.\n", iface, shader);
2995 
2996     wined3d_mutex_lock();
2997 
2998     if (!(shader_impl = d3d8_free_handle(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
2999     {
3000         WARN("Invalid handle (%#x) passed.\n", shader);
3001         wined3d_mutex_unlock();
3002         return D3DERR_INVALIDCALL;
3003     }
3004 
3005     if (wined3d_device_get_pixel_shader(device->wined3d_device) == shader_impl->wined3d_shader)
3006         IDirect3DDevice8_SetPixelShader(iface, 0);
3007 
3008     wined3d_mutex_unlock();
3009 
3010     d3d8_pixel_shader_destroy(shader_impl);
3011 
3012     return D3D_OK;
3013 }
3014 
3015 static HRESULT WINAPI d3d8_device_SetPixelShaderConstant(IDirect3DDevice8 *iface,
3016         DWORD start_register, const void *data, DWORD count)
3017 {
3018     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
3019     HRESULT hr;
3020 
3021     TRACE("iface %p, start_register %u, data %p, count %u.\n",
3022             iface, start_register, data, count);
3023 
3024     wined3d_mutex_lock();
3025     hr = wined3d_device_set_ps_consts_f(device->wined3d_device, start_register, count, data);
3026     wined3d_mutex_unlock();
3027 
3028     return hr;
3029 }
3030 
3031 static HRESULT WINAPI d3d8_device_GetPixelShaderConstant(IDirect3DDevice8 *iface,
3032         DWORD start_register, void *data, DWORD count)
3033 {
3034     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
3035     HRESULT hr;
3036 
3037     TRACE("iface %p, start_register %u, data %p, count %u.\n",
3038             iface, start_register, data, count);
3039 
3040     wined3d_mutex_lock();
3041     hr = wined3d_device_get_ps_consts_f(device->wined3d_device, start_register, count, data);
3042     wined3d_mutex_unlock();
3043 
3044     return hr;
3045 }
3046 
3047 static HRESULT WINAPI d3d8_device_GetPixelShaderFunction(IDirect3DDevice8 *iface,
3048         DWORD shader, void *data, DWORD *data_size)
3049 {
3050     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
3051     struct d3d8_pixel_shader *shader_impl = NULL;
3052     HRESULT hr;
3053 
3054     TRACE("iface %p, shader %#x, data %p, data_size %p.\n",
3055             iface, shader, data, data_size);
3056 
3057     wined3d_mutex_lock();
3058     if (!(shader_impl = d3d8_get_object(&device->handle_table, shader - (VS_HIGHESTFIXEDFXF + 1), D3D8_HANDLE_PS)))
3059     {
3060         WARN("Invalid handle (%#x) passed.\n", shader);
3061         wined3d_mutex_unlock();
3062 
3063         return D3DERR_INVALIDCALL;
3064     }
3065 
3066     hr = wined3d_shader_get_byte_code(shader_impl->wined3d_shader, data, data_size);
3067     wined3d_mutex_unlock();
3068 
3069     return hr;
3070 }
3071 
3072 static HRESULT WINAPI d3d8_device_DrawRectPatch(IDirect3DDevice8 *iface, UINT handle,
3073         const float *segment_count, const D3DRECTPATCH_INFO *patch_info)
3074 {
3075     FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
3076             iface, handle, segment_count, patch_info);
3077     return D3D_OK;
3078 }
3079 
3080 static HRESULT WINAPI d3d8_device_DrawTriPatch(IDirect3DDevice8 *iface, UINT handle,
3081         const float *segment_count, const D3DTRIPATCH_INFO *patch_info)
3082 {
3083     FIXME("iface %p, handle %#x, segment_count %p, patch_info %p unimplemented.\n",
3084             iface, handle, segment_count, patch_info);
3085     return D3D_OK;
3086 }
3087 
3088 static HRESULT WINAPI d3d8_device_DeletePatch(IDirect3DDevice8 *iface, UINT handle)
3089 {
3090     FIXME("iface %p, handle %#x unimplemented.\n", iface, handle);
3091     return D3DERR_INVALIDCALL;
3092 }
3093 
3094 static HRESULT WINAPI d3d8_device_SetStreamSource(IDirect3DDevice8 *iface,
3095         UINT stream_idx, IDirect3DVertexBuffer8 *buffer, UINT stride)
3096 {
3097     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
3098     struct d3d8_vertexbuffer *buffer_impl = unsafe_impl_from_IDirect3DVertexBuffer8(buffer);
3099     HRESULT hr;
3100 
3101     TRACE("iface %p, stream_idx %u, buffer %p, stride %u.\n",
3102             iface, stream_idx, buffer, stride);
3103 
3104     wined3d_mutex_lock();
3105     hr = wined3d_device_set_stream_source(device->wined3d_device, stream_idx,
3106             buffer_impl ? buffer_impl->wined3d_buffer : NULL, 0, stride);
3107     wined3d_mutex_unlock();
3108 
3109     return hr;
3110 }
3111 
3112 static HRESULT WINAPI d3d8_device_GetStreamSource(IDirect3DDevice8 *iface,
3113         UINT stream_idx, IDirect3DVertexBuffer8 **buffer, UINT *stride)
3114 {
3115     struct d3d8_device *device = impl_from_IDirect3DDevice8(iface);
3116     struct d3d8_vertexbuffer *buffer_impl;
3117     struct wined3d_buffer *wined3d_buffer = NULL;
3118     HRESULT hr;
3119 
3120     TRACE("iface %p, stream_idx %u, buffer %p, stride %p.\n",
3121             iface, stream_idx, buffer, stride);
3122 
3123     if (!buffer)
3124         return D3DERR_INVALIDCALL;
3125 
3126     wined3d_mutex_lock();
3127     hr = wined3d_device_get_stream_source(device->wined3d_device, stream_idx, &wined3d_buffer, 0, stride);
3128     if (SUCCEEDED(hr) && wined3d_buffer)
3129     {
3130         buffer_impl = wined3d_buffer_get_parent(wined3d_buffer);
3131         *buffer = &buffer_impl->IDirect3DVertexBuffer8_iface;
3132         IDirect3DVertexBuffer8_AddRef(*buffer);
3133     }
3134     else
3135     {
3136         if (FAILED(hr))
3137             ERR("Failed to get wined3d stream source, hr %#x.\n", hr);
3138         *buffer = NULL;
3139     }
3140     wined3d_mutex_unlock();
3141 
3142     return hr;
3143 }
3144 
3145 static const struct IDirect3DDevice8Vtbl d3d8_device_vtbl =
3146 {
3147     d3d8_device_QueryInterface,
3148     d3d8_device_AddRef,
3149     d3d8_device_Release,
3150     d3d8_device_TestCooperativeLevel,
3151     d3d8_device_GetAvailableTextureMem,
3152     d3d8_device_ResourceManagerDiscardBytes,
3153     d3d8_device_GetDirect3D,
3154     d3d8_device_GetDeviceCaps,
3155     d3d8_device_GetDisplayMode,
3156     d3d8_device_GetCreationParameters,
3157     d3d8_device_SetCursorProperties,
3158     d3d8_device_SetCursorPosition,
3159     d3d8_device_ShowCursor,
3160     d3d8_device_CreateAdditionalSwapChain,
3161     d3d8_device_Reset,
3162     d3d8_device_Present,
3163     d3d8_device_GetBackBuffer,
3164     d3d8_device_GetRasterStatus,
3165     d3d8_device_SetGammaRamp,
3166     d3d8_device_GetGammaRamp,
3167     d3d8_device_CreateTexture,
3168     d3d8_device_CreateVolumeTexture,
3169     d3d8_device_CreateCubeTexture,
3170     d3d8_device_CreateVertexBuffer,
3171     d3d8_device_CreateIndexBuffer,
3172     d3d8_device_CreateRenderTarget,
3173     d3d8_device_CreateDepthStencilSurface,
3174     d3d8_device_CreateImageSurface,
3175     d3d8_device_CopyRects,
3176     d3d8_device_UpdateTexture,
3177     d3d8_device_GetFrontBuffer,
3178     d3d8_device_SetRenderTarget,
3179     d3d8_device_GetRenderTarget,
3180     d3d8_device_GetDepthStencilSurface,
3181     d3d8_device_BeginScene,
3182     d3d8_device_EndScene,
3183     d3d8_device_Clear,
3184     d3d8_device_SetTransform,
3185     d3d8_device_GetTransform,
3186     d3d8_device_MultiplyTransform,
3187     d3d8_device_SetViewport,
3188     d3d8_device_GetViewport,
3189     d3d8_device_SetMaterial,
3190     d3d8_device_GetMaterial,
3191     d3d8_device_SetLight,
3192     d3d8_device_GetLight,
3193     d3d8_device_LightEnable,
3194     d3d8_device_GetLightEnable,
3195     d3d8_device_SetClipPlane,
3196     d3d8_device_GetClipPlane,
3197     d3d8_device_SetRenderState,
3198     d3d8_device_GetRenderState,
3199     d3d8_device_BeginStateBlock,
3200     d3d8_device_EndStateBlock,
3201     d3d8_device_ApplyStateBlock,
3202     d3d8_device_CaptureStateBlock,
3203     d3d8_device_DeleteStateBlock,
3204     d3d8_device_CreateStateBlock,
3205     d3d8_device_SetClipStatus,
3206     d3d8_device_GetClipStatus,
3207     d3d8_device_GetTexture,
3208     d3d8_device_SetTexture,
3209     d3d8_device_GetTextureStageState,
3210     d3d8_device_SetTextureStageState,
3211     d3d8_device_ValidateDevice,
3212     d3d8_device_GetInfo,
3213     d3d8_device_SetPaletteEntries,
3214     d3d8_device_GetPaletteEntries,
3215     d3d8_device_SetCurrentTexturePalette,
3216     d3d8_device_GetCurrentTexturePalette,
3217     d3d8_device_DrawPrimitive,
3218     d3d8_device_DrawIndexedPrimitive,
3219     d3d8_device_DrawPrimitiveUP,
3220     d3d8_device_DrawIndexedPrimitiveUP,
3221     d3d8_device_ProcessVertices,
3222     d3d8_device_CreateVertexShader,
3223     d3d8_device_SetVertexShader,
3224     d3d8_device_GetVertexShader,
3225     d3d8_device_DeleteVertexShader,
3226     d3d8_device_SetVertexShaderConstant,
3227     d3d8_device_GetVertexShaderConstant,
3228     d3d8_device_GetVertexShaderDeclaration,
3229     d3d8_device_GetVertexShaderFunction,
3230     d3d8_device_SetStreamSource,
3231     d3d8_device_GetStreamSource,
3232     d3d8_device_SetIndices,
3233     d3d8_device_GetIndices,
3234     d3d8_device_CreatePixelShader,
3235     d3d8_device_SetPixelShader,
3236     d3d8_device_GetPixelShader,
3237     d3d8_device_DeletePixelShader,
3238     d3d8_device_SetPixelShaderConstant,
3239     d3d8_device_GetPixelShaderConstant,
3240     d3d8_device_GetPixelShaderFunction,
3241     d3d8_device_DrawRectPatch,
3242     d3d8_device_DrawTriPatch,
3243     d3d8_device_DeletePatch,
3244 };
3245 
3246 static inline struct d3d8_device *device_from_device_parent(struct wined3d_device_parent *device_parent)
3247 {
3248     return CONTAINING_RECORD(device_parent, struct d3d8_device, device_parent);
3249 }
3250 
3251 static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
3252         struct wined3d_device *device)
3253 {
3254     TRACE("device_parent %p, device %p\n", device_parent, device);
3255 }
3256 
3257 static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent)
3258 {
3259     TRACE("device_parent %p.\n", device_parent);
3260 }
3261 
3262 static void CDECL device_parent_activate(struct wined3d_device_parent *device_parent, BOOL activate)
3263 {
3264     struct d3d8_device *device = device_from_device_parent(device_parent);
3265 
3266     TRACE("device_parent %p, activate %#x.\n", device_parent, activate);
3267 
3268     if (!activate)
3269         InterlockedCompareExchange(&device->device_state, D3D8_DEVICE_STATE_LOST, D3D8_DEVICE_STATE_OK);
3270     else
3271         InterlockedCompareExchange(&device->device_state, D3D8_DEVICE_STATE_NOT_RESET, D3D8_DEVICE_STATE_LOST);
3272 }
3273 
3274 static HRESULT CDECL device_parent_texture_sub_resource_created(struct wined3d_device_parent *device_parent,
3275         enum wined3d_resource_type type, struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
3276         void **parent, const struct wined3d_parent_ops **parent_ops)
3277 {
3278     TRACE("device_parent %p, type %#x, wined3d_texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
3279             device_parent, type, wined3d_texture, sub_resource_idx, parent, parent_ops);
3280 
3281     if (type == WINED3D_RTYPE_TEXTURE_2D)
3282     {
3283         struct d3d8_surface *d3d_surface;
3284 
3285         if (!(d3d_surface = heap_alloc_zero(sizeof(*d3d_surface))))
3286             return E_OUTOFMEMORY;
3287 
3288         surface_init(d3d_surface, wined3d_texture, sub_resource_idx, parent_ops);
3289         *parent = d3d_surface;
3290         TRACE("Created surface %p.\n", d3d_surface);
3291     }
3292     else if (type == WINED3D_RTYPE_TEXTURE_3D)
3293     {
3294         struct d3d8_volume *d3d_volume;
3295 
3296         if (!(d3d_volume = heap_alloc_zero(sizeof(*d3d_volume))))
3297             return E_OUTOFMEMORY;
3298 
3299         volume_init(d3d_volume, wined3d_texture, sub_resource_idx, parent_ops);
3300         *parent = d3d_volume;
3301         TRACE("Created volume %p.\n", d3d_volume);
3302     }
3303     else
3304     {
3305         ERR("Unhandled resource type %#x.\n", type);
3306         return E_FAIL;
3307     }
3308 
3309     return D3D_OK;
3310 }
3311 
3312 static HRESULT CDECL device_parent_create_swapchain_texture(struct wined3d_device_parent *device_parent,
3313         void *container_parent, const struct wined3d_resource_desc *desc, DWORD texture_flags,
3314         struct wined3d_texture **texture)
3315 {
3316     struct d3d8_device *device = device_from_device_parent(device_parent);
3317     struct d3d8_surface *d3d_surface;
3318     HRESULT hr;
3319 
3320     TRACE("device_parent %p, container_parent %p, desc %p, texture flags %#x, texture %p.\n",
3321             device_parent, container_parent, desc, texture_flags, texture);
3322 
3323     if (FAILED(hr = wined3d_texture_create(device->wined3d_device, desc, 1, 1,
3324             texture_flags | WINED3D_TEXTURE_CREATE_MAPPABLE,  NULL, &device->IDirect3DDevice8_iface,
3325             &d3d8_null_wined3d_parent_ops, texture)))
3326     {
3327         WARN("Failed to create texture, hr %#x.\n", hr);
3328         return hr;
3329     }
3330 
3331     d3d_surface = wined3d_texture_get_sub_resource_parent(*texture, 0);
3332     d3d_surface->parent_device = &device->IDirect3DDevice8_iface;
3333 
3334     return hr;
3335 }
3336 
3337 static HRESULT CDECL device_parent_create_swapchain(struct wined3d_device_parent *device_parent,
3338         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain **swapchain)
3339 {
3340     struct d3d8_device *device = device_from_device_parent(device_parent);
3341     struct d3d8_swapchain *d3d_swapchain;
3342     HRESULT hr;
3343 
3344     TRACE("device_parent %p, desc %p, swapchain %p.\n", device_parent, desc, swapchain);
3345 
3346     if (FAILED(hr = d3d8_swapchain_create(device, desc, WINED3D_SWAP_INTERVAL_DEFAULT, &d3d_swapchain)))
3347     {
3348         WARN("Failed to create swapchain, hr %#x.\n", hr);
3349         *swapchain = NULL;
3350         return hr;
3351     }
3352 
3353     *swapchain = d3d_swapchain->wined3d_swapchain;
3354     wined3d_swapchain_incref(*swapchain);
3355     IDirect3DSwapChain8_Release(&d3d_swapchain->IDirect3DSwapChain8_iface);
3356 
3357     return hr;
3358 }
3359 
3360 static const struct wined3d_device_parent_ops d3d8_wined3d_device_parent_ops =
3361 {
3362     device_parent_wined3d_device_created,
3363     device_parent_mode_changed,
3364     device_parent_activate,
3365     device_parent_texture_sub_resource_created,
3366     device_parent_create_swapchain_texture,
3367     device_parent_create_swapchain,
3368 };
3369 
3370 static void setup_fpu(void)
3371 {
3372 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3373     WORD cw;
3374     __asm__ volatile ("fnstcw %0" : "=m" (cw));
3375     cw = (cw & ~0xf3f) | 0x3f;
3376     __asm__ volatile ("fldcw %0" : : "m" (cw));
3377 #elif defined(__i386__) && defined(_MSC_VER)
3378     WORD cw;
3379     __asm fnstcw cw;
3380     cw = (cw & ~0xf3f) | 0x3f;
3381     __asm fldcw cw;
3382 #else
3383     FIXME("FPU setup not implemented for this platform.\n");
3384 #endif
3385 }
3386 
3387 HRESULT device_init(struct d3d8_device *device, struct d3d8 *parent, struct wined3d *wined3d, UINT adapter,
3388         D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters)
3389 {
3390     struct wined3d_swapchain_desc swapchain_desc;
3391     struct wined3d_swapchain *wined3d_swapchain;
3392     HRESULT hr;
3393 
3394     device->IDirect3DDevice8_iface.lpVtbl = &d3d8_device_vtbl;
3395     device->device_parent.ops = &d3d8_wined3d_device_parent_ops;
3396     device->ref = 1;
3397     if (!(device->handle_table.entries = heap_alloc_zero(D3D8_INITIAL_HANDLE_TABLE_SIZE
3398             * sizeof(*device->handle_table.entries))))
3399     {
3400         ERR("Failed to allocate handle table memory.\n");
3401         return E_OUTOFMEMORY;
3402     }
3403     device->handle_table.table_size = D3D8_INITIAL_HANDLE_TABLE_SIZE;
3404 
3405     if (!(flags & D3DCREATE_FPU_PRESERVE)) setup_fpu();
3406 
3407     wined3d_mutex_lock();
3408     hr = wined3d_device_create(wined3d, adapter, device_type, focus_window, flags, 4,
3409             &device->device_parent, &device->wined3d_device);
3410     if (FAILED(hr))
3411     {
3412         WARN("Failed to create wined3d device, hr %#x.\n", hr);
3413         wined3d_mutex_unlock();
3414         heap_free(device->handle_table.entries);
3415         return hr;
3416     }
3417 
3418     if (!parameters->Windowed)
3419     {
3420         HWND device_window = parameters->hDeviceWindow;
3421 
3422         if (!focus_window)
3423             focus_window = device_window;
3424         if (FAILED(hr = wined3d_device_acquire_focus_window(device->wined3d_device, focus_window)))
3425         {
3426             ERR("Failed to acquire focus window, hr %#x.\n", hr);
3427             wined3d_device_decref(device->wined3d_device);
3428             wined3d_mutex_unlock();
3429             heap_free(device->handle_table.entries);
3430             return hr;
3431         }
3432 
3433         if (!device_window)
3434             device_window = focus_window;
3435         wined3d_device_setup_fullscreen_window(device->wined3d_device, device_window,
3436                 parameters->BackBufferWidth,
3437                 parameters->BackBufferHeight);
3438     }
3439 
3440     if (flags & D3DCREATE_MULTITHREADED)
3441         wined3d_device_set_multithreaded(device->wined3d_device);
3442 
3443     if (!wined3d_swapchain_desc_from_present_parameters(&swapchain_desc, parameters))
3444     {
3445         wined3d_device_release_focus_window(device->wined3d_device);
3446         wined3d_device_decref(device->wined3d_device);
3447         wined3d_mutex_unlock();
3448         heap_free(device->handle_table.entries);
3449         return D3DERR_INVALIDCALL;
3450     }
3451 
3452     if (FAILED(hr = wined3d_device_init_3d(device->wined3d_device, &swapchain_desc)))
3453     {
3454         WARN("Failed to initialize 3D, hr %#x.\n", hr);
3455         wined3d_device_release_focus_window(device->wined3d_device);
3456         wined3d_device_decref(device->wined3d_device);
3457         wined3d_mutex_unlock();
3458         heap_free(device->handle_table.entries);
3459         return hr;
3460     }
3461 
3462     wined3d_device_set_render_state(device->wined3d_device,
3463             WINED3D_RS_ZENABLE, !!swapchain_desc.enable_auto_depth_stencil);
3464     wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_POINTSIZE_MIN, 0);
3465     wined3d_mutex_unlock();
3466 
3467     present_parameters_from_wined3d_swapchain_desc(parameters,
3468             &swapchain_desc, parameters->FullScreen_PresentationInterval);
3469 
3470     device->declArraySize = 16;
3471     if (!(device->decls = heap_alloc(device->declArraySize * sizeof(*device->decls))))
3472     {
3473         ERR("Failed to allocate FVF vertex declaration map memory.\n");
3474         hr = E_OUTOFMEMORY;
3475         goto err;
3476     }
3477 
3478     wined3d_swapchain = wined3d_device_get_swapchain(device->wined3d_device, 0);
3479     device->implicit_swapchain = wined3d_swapchain_get_parent(wined3d_swapchain);
3480     device->implicit_swapchain->swap_interval
3481             = wined3dswapinterval_from_d3d(parameters->FullScreen_PresentationInterval);
3482 
3483     device->d3d_parent = &parent->IDirect3D8_iface;
3484     IDirect3D8_AddRef(device->d3d_parent);
3485 
3486     return D3D_OK;
3487 
3488 err:
3489     wined3d_mutex_lock();
3490     wined3d_device_uninit_3d(device->wined3d_device);
3491     wined3d_device_release_focus_window(device->wined3d_device);
3492     wined3d_device_decref(device->wined3d_device);
3493     wined3d_mutex_unlock();
3494     heap_free(device->handle_table.entries);
3495     return hr;
3496 }
3497