Release 1.5.29.
[wine] / dlls / ddraw / device.c
1 /*
2  * Copyright (c) 1998-2004 Lionel Ulmer
3  * Copyright (c) 2002-2005 Christian Costa
4  * Copyright (c) 2006-2009, 2011-2012 Stefan Dösinger
5  * Copyright (c) 2008 Alexander Dorofeyev
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  * IDirect3DDevice implementation, version 1, 2, 3 and 7. Rendering is relayed
22  * to WineD3D, some minimal DirectDraw specific management is handled here.
23  * The Direct3DDevice is NOT the parent of the WineD3DDevice, because d3d
24  * is initialized when DirectDraw creates the primary surface.
25  * Some type management is necessary, because some D3D types changed between
26  * D3D7 and D3D9.
27  *
28  */
29
30 #include "config.h"
31 #include "wine/port.h"
32
33 #include "ddraw_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
36 WINE_DECLARE_DEBUG_CHANNEL(winediag);
37
38 /* The device ID */
39 const GUID IID_D3DDEVICE_WineD3D = {
40   0xaef72d43,
41   0xb09a,
42   0x4b7b,
43   { 0xb7,0x98,0xc6,0x8a,0x77,0x2d,0x72,0x2a }
44 };
45
46 static inline void set_fpu_control_word(WORD fpucw)
47 {
48 #if defined(__i386__) && defined(__GNUC__)
49     __asm__ volatile ("fldcw %0" : : "m" (fpucw));
50 #elif defined(__i386__) && defined(_MSC_VER)
51     __asm fldcw fpucw;
52 #endif
53 }
54
55 static inline WORD d3d_fpu_setup(void)
56 {
57     WORD oldcw;
58
59 #if defined(__i386__) && defined(__GNUC__)
60     __asm__ volatile ("fnstcw %0" : "=m" (oldcw));
61 #elif defined(__i386__) && defined(_MSC_VER)
62     __asm fnstcw oldcw;
63 #else
64     static BOOL warned = FALSE;
65     if(!warned)
66     {
67         FIXME("FPUPRESERVE not implemented for this platform / compiler\n");
68         warned = TRUE;
69     }
70     return 0;
71 #endif
72
73     set_fpu_control_word(0x37f);
74
75     return oldcw;
76 }
77
78 static inline struct d3d_device *impl_from_IUnknown(IUnknown *iface)
79 {
80     return CONTAINING_RECORD(iface, struct d3d_device, IUnknown_inner);
81 }
82
83 static HRESULT WINAPI d3d_device_inner_QueryInterface(IUnknown *iface, REFIID riid, void **out)
84 {
85     struct d3d_device *device = impl_from_IUnknown(iface);
86
87     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
88
89     if (!riid)
90     {
91         *out = NULL;
92         return DDERR_INVALIDPARAMS;
93     }
94
95     if (IsEqualGUID(&IID_IUnknown, riid))
96     {
97         IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
98         *out = &device->IDirect3DDevice7_iface;
99         return S_OK;
100     }
101
102     if (device->version == 7)
103     {
104         if (IsEqualGUID(&IID_IDirect3DDevice7, riid))
105         {
106             IDirect3DDevice7_AddRef(&device->IDirect3DDevice7_iface);
107             *out = &device->IDirect3DDevice7_iface;
108             return S_OK;
109         }
110     }
111     else
112     {
113         if (IsEqualGUID(&IID_IDirect3DDevice3, riid) && device->version == 3)
114         {
115             IDirect3DDevice3_AddRef(&device->IDirect3DDevice3_iface);
116             *out = &device->IDirect3DDevice3_iface;
117             return S_OK;
118         }
119
120         if (IsEqualGUID(&IID_IDirect3DDevice2, riid) && device->version >= 2)
121         {
122             IDirect3DDevice2_AddRef(&device->IDirect3DDevice2_iface);
123             *out = &device->IDirect3DDevice2_iface;
124             return S_OK;
125         }
126
127         if (IsEqualGUID(&IID_IDirect3DDevice, riid))
128         {
129             IDirect3DDevice_AddRef(&device->IDirect3DDevice_iface);
130             *out = &device->IDirect3DDevice_iface;
131             return S_OK;
132         }
133     }
134
135     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
136
137     *out = NULL;
138     return E_NOINTERFACE;
139 }
140
141 static HRESULT WINAPI d3d_device7_QueryInterface(IDirect3DDevice7 *iface, REFIID riid, void **out)
142 {
143     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
144
145     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
146
147     return IUnknown_QueryInterface(device->outer_unknown, riid, out);
148 }
149
150 static HRESULT WINAPI d3d_device3_QueryInterface(IDirect3DDevice3 *iface, REFIID riid, void **out)
151 {
152     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
153
154     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
155
156     return IUnknown_QueryInterface(device->outer_unknown, riid, out);
157 }
158
159 static HRESULT WINAPI d3d_device2_QueryInterface(IDirect3DDevice2 *iface, REFIID riid, void **out)
160 {
161     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
162
163     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
164
165     return IUnknown_QueryInterface(device->outer_unknown, riid, out);
166 }
167
168 static HRESULT WINAPI d3d_device1_QueryInterface(IDirect3DDevice *iface, REFIID riid, void **out)
169 {
170     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
171
172     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
173
174     return IUnknown_QueryInterface(device->outer_unknown, riid, out);
175 }
176
177 static ULONG WINAPI d3d_device_inner_AddRef(IUnknown *iface)
178 {
179     struct d3d_device *device = impl_from_IUnknown(iface);
180     ULONG ref = InterlockedIncrement(&device->ref);
181
182     TRACE("%p increasing refcount to %u.\n", device, ref);
183
184     return ref;
185 }
186
187 static ULONG WINAPI d3d_device7_AddRef(IDirect3DDevice7 *iface)
188 {
189     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
190
191     TRACE("iface %p.\n", iface);
192
193     return IUnknown_AddRef(device->outer_unknown);
194 }
195
196 static ULONG WINAPI d3d_device3_AddRef(IDirect3DDevice3 *iface)
197 {
198     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
199
200     TRACE("iface %p.\n", iface);
201
202     return IUnknown_AddRef(device->outer_unknown);
203 }
204
205 static ULONG WINAPI d3d_device2_AddRef(IDirect3DDevice2 *iface)
206 {
207     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
208
209     TRACE("iface %p.\n", iface);
210
211     return IUnknown_AddRef(device->outer_unknown);
212 }
213
214 static ULONG WINAPI d3d_device1_AddRef(IDirect3DDevice *iface)
215 {
216     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
217
218     TRACE("iface %p.\n", iface);
219
220     return IUnknown_AddRef(device->outer_unknown);
221 }
222
223 static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
224 {
225     struct d3d_device *This = impl_from_IUnknown(iface);
226     ULONG ref = InterlockedDecrement(&This->ref);
227
228     TRACE("%p decreasing refcount to %u.\n", This, ref);
229
230     /* This method doesn't destroy the wined3d device, because it's still in
231      * use for 2D rendering. IDirectDrawSurface7::Release will destroy the
232      * wined3d device when the render target is released. */
233     if (!ref)
234     {
235         DWORD i;
236         struct list *vp_entry, *vp_entry2;
237
238         wined3d_mutex_lock();
239
240         /* There is no need to unset any resources here, wined3d will take
241          * care of that on uninit_3d(). */
242
243         if (This->index_buffer)
244             wined3d_buffer_decref(This->index_buffer);
245         if (This->vertex_buffer)
246             wined3d_buffer_decref(This->vertex_buffer);
247
248         /* Set the device up to render to the front buffer since the back
249          * buffer will vanish soon. */
250         wined3d_device_set_render_target(This->wined3d_device, 0,
251                 This->ddraw->wined3d_frontbuffer, TRUE);
252
253         /* Release the wined3d device. This won't destroy it. */
254         if (!wined3d_device_decref(This->wined3d_device))
255             ERR("The wined3d device (%p) was destroyed unexpectedly.\n", This->wined3d_device);
256
257         /* The texture handles should be unset by now, but there might be some bits
258          * missing in our reference counting(needs test). Do a sanity check. */
259         for (i = 0; i < This->handle_table.entry_count; ++i)
260         {
261             struct ddraw_handle_entry *entry = &This->handle_table.entries[i];
262
263             switch (entry->type)
264             {
265                 case DDRAW_HANDLE_FREE:
266                     break;
267
268                 case DDRAW_HANDLE_MATERIAL:
269                 {
270                     struct d3d_material *m = entry->object;
271                     FIXME("Material handle %#x (%p) not unset properly.\n", i + 1, m);
272                     m->Handle = 0;
273                     break;
274                 }
275
276                 case DDRAW_HANDLE_MATRIX:
277                 {
278                     /* No FIXME here because this might happen because of sloppy applications. */
279                     WARN("Leftover matrix handle %#x (%p), deleting.\n", i + 1, entry->object);
280                     IDirect3DDevice_DeleteMatrix(&This->IDirect3DDevice_iface, i + 1);
281                     break;
282                 }
283
284                 case DDRAW_HANDLE_STATEBLOCK:
285                 {
286                     /* No FIXME here because this might happen because of sloppy applications. */
287                     WARN("Leftover stateblock handle %#x (%p), deleting.\n", i + 1, entry->object);
288                     IDirect3DDevice7_DeleteStateBlock(&This->IDirect3DDevice7_iface, i + 1);
289                     break;
290                 }
291
292                 case DDRAW_HANDLE_SURFACE:
293                 {
294                     struct ddraw_surface *surf = entry->object;
295                     FIXME("Texture handle %#x (%p) not unset properly.\n", i + 1, surf);
296                     surf->Handle = 0;
297                     break;
298                 }
299
300                 default:
301                     FIXME("Handle %#x (%p) has unknown type %#x.\n", i + 1, entry->object, entry->type);
302                     break;
303             }
304         }
305
306         ddraw_handle_table_destroy(&This->handle_table);
307
308         LIST_FOR_EACH_SAFE(vp_entry, vp_entry2, &This->viewport_list)
309         {
310             struct d3d_viewport *vp = LIST_ENTRY(vp_entry, struct d3d_viewport, entry);
311             IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
312         }
313
314         TRACE("Releasing target %p.\n", This->target);
315         /* Release the render target. */
316         if (This->version != 1)
317             IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface);
318         TRACE("Target release done\n");
319
320         This->ddraw->d3ddevice = NULL;
321
322         /* Now free the structure */
323         HeapFree(GetProcessHeap(), 0, This);
324         wined3d_mutex_unlock();
325     }
326
327     TRACE("Done\n");
328     return ref;
329 }
330
331 static ULONG WINAPI d3d_device7_Release(IDirect3DDevice7 *iface)
332 {
333     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
334
335     TRACE("iface %p.\n", iface);
336
337     return IUnknown_Release(device->outer_unknown);
338 }
339
340 static ULONG WINAPI d3d_device3_Release(IDirect3DDevice3 *iface)
341 {
342     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
343
344     TRACE("iface %p.\n", iface);
345
346     return IUnknown_Release(device->outer_unknown);
347 }
348
349 static ULONG WINAPI d3d_device2_Release(IDirect3DDevice2 *iface)
350 {
351     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
352
353     TRACE("iface %p.\n", iface);
354
355     return IUnknown_Release(device->outer_unknown);
356 }
357
358 static ULONG WINAPI d3d_device1_Release(IDirect3DDevice *iface)
359 {
360     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
361
362     TRACE("iface %p.\n", iface);
363
364     return IUnknown_Release(device->outer_unknown);
365 }
366
367 /*****************************************************************************
368  * IDirect3DDevice Methods
369  *****************************************************************************/
370
371 /*****************************************************************************
372  * IDirect3DDevice::Initialize
373  *
374  * Initializes a Direct3DDevice. This implementation is a no-op, as all
375  * initialization is done at create time.
376  *
377  * Exists in Version 1
378  *
379  * Parameters:
380  *  No idea what they mean, as the MSDN page is gone
381  *
382  * Returns: DD_OK
383  *
384  *****************************************************************************/
385 static HRESULT WINAPI d3d_device1_Initialize(IDirect3DDevice *iface,
386         IDirect3D *d3d, GUID *guid, D3DDEVICEDESC *device_desc)
387 {
388     /* It shouldn't be crucial, but print a FIXME, I'm interested if
389      * any game calls it and when. */
390     FIXME("iface %p, d3d %p, guid %s, device_desc %p nop!\n",
391             iface, d3d, debugstr_guid(guid), device_desc);
392
393     return D3D_OK;
394 }
395
396 /*****************************************************************************
397  * IDirect3DDevice7::GetCaps
398  *
399  * Retrieves the device's capabilities
400  *
401  * This implementation is used for Version 7 only, the older versions have
402  * their own implementation.
403  *
404  * Parameters:
405  *  Desc: Pointer to a D3DDEVICEDESC7 structure to fill
406  *
407  * Returns:
408  *  D3D_OK on success
409  *  D3DERR_* if a problem occurs. See WineD3D
410  *
411  *****************************************************************************/
412 static HRESULT d3d_device7_GetCaps(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *Desc)
413 {
414     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
415     D3DDEVICEDESC OldDesc;
416
417     TRACE("iface %p, device_desc %p.\n", iface, Desc);
418
419     if (!Desc)
420     {
421         WARN("Desc is NULL, returning DDERR_INVALIDPARAMS.\n");
422         return DDERR_INVALIDPARAMS;
423     }
424
425     /* Call the same function used by IDirect3D, this saves code */
426     return IDirect3DImpl_GetCaps(device->ddraw->wined3d, &OldDesc, Desc);
427 }
428
429 static HRESULT WINAPI d3d_device7_GetCaps_FPUSetup(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
430 {
431     return d3d_device7_GetCaps(iface, desc);
432 }
433
434 static HRESULT WINAPI d3d_device7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface, D3DDEVICEDESC7 *desc)
435 {
436     HRESULT hr;
437     WORD old_fpucw;
438
439     old_fpucw = d3d_fpu_setup();
440     hr = d3d_device7_GetCaps(iface, desc);
441     set_fpu_control_word(old_fpucw);
442
443     return hr;
444 }
445 /*****************************************************************************
446  * IDirect3DDevice3::GetCaps
447  *
448  * Retrieves the capabilities of the hardware device and the emulation
449  * device. For Wine, hardware and emulation are the same (it's all HW).
450  *
451  * This implementation is used for Version 1, 2, and 3. Version 7 has its own
452  *
453  * Parameters:
454  *  HWDesc: Structure to fill with the HW caps
455  *  HelDesc: Structure to fill with the hardware emulation caps
456  *
457  * Returns:
458  *  D3D_OK on success
459  *  D3DERR_* if a problem occurs. See WineD3D
460  *
461  *****************************************************************************/
462
463 /* There are 3 versions of D3DDEVICEDESC. All 3 share the same name because
464  * Microsoft just expanded the existing structure without naming them
465  * D3DDEVICEDESC2 and D3DDEVICEDESC3. Which version is used have depends
466  * on the version of the DirectX SDK. DirectX 6+ and Wine use the latest
467  * one with 252 bytes.
468  *
469  * All 3 versions are allowed as parameters and only the specified amount of
470  * bytes is written.
471  *
472  * Note that Direct3D7 and earlier are not available in native Win64
473  * ddraw.dll builds, so possible size differences between 32 bit and
474  * 64 bit are a non-issue.
475  */
476 static inline BOOL check_d3ddevicedesc_size(DWORD size)
477 {
478     if (size == FIELD_OFFSET(D3DDEVICEDESC, dwMinTextureWidth) /* 172 */
479             || size == FIELD_OFFSET(D3DDEVICEDESC, dwMaxTextureRepeat) /* 204 */
480             || size == sizeof(D3DDEVICEDESC) /* 252 */) return TRUE;
481     return FALSE;
482 }
483
484 static HRESULT WINAPI d3d_device3_GetCaps(IDirect3DDevice3 *iface,
485         D3DDEVICEDESC *HWDesc, D3DDEVICEDESC *HelDesc)
486 {
487     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
488     D3DDEVICEDESC oldDesc;
489     D3DDEVICEDESC7 newDesc;
490     HRESULT hr;
491
492     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, HWDesc, HelDesc);
493
494     if (!HWDesc)
495     {
496         WARN("HWDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
497         return DDERR_INVALIDPARAMS;
498     }
499     if (!check_d3ddevicedesc_size(HWDesc->dwSize))
500     {
501         WARN("HWDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HWDesc->dwSize);
502         return DDERR_INVALIDPARAMS;
503     }
504     if (!HelDesc)
505     {
506         WARN("HelDesc is NULL, returning DDERR_INVALIDPARAMS.\n");
507         return DDERR_INVALIDPARAMS;
508     }
509     if (!check_d3ddevicedesc_size(HelDesc->dwSize))
510     {
511         WARN("HelDesc->dwSize is %u, returning DDERR_INVALIDPARAMS.\n", HelDesc->dwSize);
512         return DDERR_INVALIDPARAMS;
513     }
514
515     hr = IDirect3DImpl_GetCaps(device->ddraw->wined3d, &oldDesc, &newDesc);
516     if (hr != D3D_OK)
517         return hr;
518
519     DD_STRUCT_COPY_BYSIZE(HWDesc, &oldDesc);
520     DD_STRUCT_COPY_BYSIZE(HelDesc, &oldDesc);
521     return D3D_OK;
522 }
523
524 static HRESULT WINAPI d3d_device2_GetCaps(IDirect3DDevice2 *iface,
525         D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
526 {
527     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
528
529     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
530
531     return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
532 }
533
534 static HRESULT WINAPI d3d_device1_GetCaps(IDirect3DDevice *iface,
535         D3DDEVICEDESC *hw_desc, D3DDEVICEDESC *hel_desc)
536 {
537     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
538
539     TRACE("iface %p, hw_desc %p, hel_desc %p.\n", iface, hw_desc, hel_desc);
540
541     return d3d_device3_GetCaps(&device->IDirect3DDevice3_iface, hw_desc, hel_desc);
542 }
543
544 /*****************************************************************************
545  * IDirect3DDevice2::SwapTextureHandles
546  *
547  * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
548  *
549  * Parameters:
550  *  Tex1, Tex2: The 2 Textures to swap
551  *
552  * Returns:
553  *  D3D_OK
554  *
555  *****************************************************************************/
556 static HRESULT WINAPI d3d_device2_SwapTextureHandles(IDirect3DDevice2 *iface,
557         IDirect3DTexture2 *tex1, IDirect3DTexture2 *tex2)
558 {
559     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
560     struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture2(tex1);
561     struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture2(tex2);
562     DWORD h1, h2;
563
564     TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
565
566     wined3d_mutex_lock();
567
568     h1 = surf1->Handle - 1;
569     h2 = surf2->Handle - 1;
570     device->handle_table.entries[h1].object = surf2;
571     device->handle_table.entries[h2].object = surf1;
572     surf2->Handle = h1 + 1;
573     surf1->Handle = h2 + 1;
574
575     wined3d_mutex_unlock();
576
577     return D3D_OK;
578 }
579
580 static HRESULT WINAPI d3d_device1_SwapTextureHandles(IDirect3DDevice *iface,
581         IDirect3DTexture *tex1, IDirect3DTexture *tex2)
582 {
583     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
584     struct ddraw_surface *surf1 = unsafe_impl_from_IDirect3DTexture(tex1);
585     struct ddraw_surface *surf2 = unsafe_impl_from_IDirect3DTexture(tex2);
586     IDirect3DTexture2 *t1 = surf1 ? &surf1->IDirect3DTexture2_iface : NULL;
587     IDirect3DTexture2 *t2 = surf2 ? &surf2->IDirect3DTexture2_iface : NULL;
588
589     TRACE("iface %p, tex1 %p, tex2 %p.\n", iface, tex1, tex2);
590
591     return d3d_device2_SwapTextureHandles(&device->IDirect3DDevice2_iface, t1, t2);
592 }
593
594 /*****************************************************************************
595  * IDirect3DDevice3::GetStats
596  *
597  * This method seems to retrieve some stats from the device.
598  * The MSDN documentation doesn't exist any more, but the D3DSTATS
599  * structure suggests that the amount of drawn primitives and processed
600  * vertices is returned.
601  *
602  * Exists in Version 1, 2 and 3
603  *
604  * Parameters:
605  *  Stats: Pointer to a D3DSTATS structure to be filled
606  *
607  * Returns:
608  *  D3D_OK on success
609  *  DDERR_INVALIDPARAMS if Stats == NULL
610  *
611  *****************************************************************************/
612 static HRESULT WINAPI d3d_device3_GetStats(IDirect3DDevice3 *iface, D3DSTATS *Stats)
613 {
614     FIXME("iface %p, stats %p stub!\n", iface, Stats);
615
616     if(!Stats)
617         return DDERR_INVALIDPARAMS;
618
619     /* Fill the Stats with 0 */
620     Stats->dwTrianglesDrawn = 0;
621     Stats->dwLinesDrawn = 0;
622     Stats->dwPointsDrawn = 0;
623     Stats->dwSpansDrawn = 0;
624     Stats->dwVerticesProcessed = 0;
625
626     return D3D_OK;
627 }
628
629 static HRESULT WINAPI d3d_device2_GetStats(IDirect3DDevice2 *iface, D3DSTATS *stats)
630 {
631     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
632
633     TRACE("iface %p, stats %p.\n", iface, stats);
634
635     return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
636 }
637
638 static HRESULT WINAPI d3d_device1_GetStats(IDirect3DDevice *iface, D3DSTATS *stats)
639 {
640     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
641
642     TRACE("iface %p, stats %p.\n", iface, stats);
643
644     return d3d_device3_GetStats(&device->IDirect3DDevice3_iface, stats);
645 }
646
647 /*****************************************************************************
648  * IDirect3DDevice::CreateExecuteBuffer
649  *
650  * Creates an IDirect3DExecuteBuffer, used for rendering with a
651  * Direct3DDevice.
652  *
653  * Version 1 only.
654  *
655  * Params:
656  *  Desc: Buffer description
657  *  ExecuteBuffer: Address to return the Interface pointer at
658  *  UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
659  *            support
660  *
661  * Returns:
662  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
663  *  DDERR_OUTOFMEMORY if we ran out of memory
664  *  D3D_OK on success
665  *
666  *****************************************************************************/
667 static HRESULT WINAPI d3d_device1_CreateExecuteBuffer(IDirect3DDevice *iface,
668         D3DEXECUTEBUFFERDESC *buffer_desc, IDirect3DExecuteBuffer **ExecuteBuffer, IUnknown *outer_unknown)
669 {
670     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
671     struct d3d_execute_buffer *object;
672     HRESULT hr;
673
674     TRACE("iface %p, buffer_desc %p, buffer %p, outer_unknown %p.\n",
675             iface, buffer_desc, ExecuteBuffer, outer_unknown);
676
677     if (outer_unknown)
678         return CLASS_E_NOAGGREGATION;
679
680     /* Allocate the new Execute Buffer */
681     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
682     if(!object)
683     {
684         ERR("Failed to allocate execute buffer memory.\n");
685         return DDERR_OUTOFMEMORY;
686     }
687
688     hr = d3d_execute_buffer_init(object, device, buffer_desc);
689     if (FAILED(hr))
690     {
691         WARN("Failed to initialize execute buffer, hr %#x.\n", hr);
692         HeapFree(GetProcessHeap(), 0, object);
693         return hr;
694     }
695
696     *ExecuteBuffer = &object->IDirect3DExecuteBuffer_iface;
697
698     TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);
699
700     return D3D_OK;
701 }
702
703 /*****************************************************************************
704  * IDirect3DDevice::Execute
705  *
706  * Executes all the stuff in an execute buffer.
707  *
708  * Params:
709  *  ExecuteBuffer: The buffer to execute
710  *  Viewport: The viewport used for rendering
711  *  Flags: Some flags
712  *
713  * Returns:
714  *  DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
715  *  D3D_OK on success
716  *
717  *****************************************************************************/
718 static HRESULT WINAPI d3d_device1_Execute(IDirect3DDevice *iface,
719         IDirect3DExecuteBuffer *ExecuteBuffer, IDirect3DViewport *viewport, DWORD flags)
720 {
721     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
722     struct d3d_execute_buffer *buffer = unsafe_impl_from_IDirect3DExecuteBuffer(ExecuteBuffer);
723     struct d3d_viewport *viewport_impl = unsafe_impl_from_IDirect3DViewport(viewport);
724     HRESULT hr;
725
726     TRACE("iface %p, buffer %p, viewport %p, flags %#x.\n", iface, ExecuteBuffer, viewport, flags);
727
728     if(!buffer)
729         return DDERR_INVALIDPARAMS;
730
731     /* Execute... */
732     wined3d_mutex_lock();
733     hr = d3d_execute_buffer_execute(buffer, device, viewport_impl);
734     wined3d_mutex_unlock();
735
736     return hr;
737 }
738
739 /*****************************************************************************
740  * IDirect3DDevice3::AddViewport
741  *
742  * Add a Direct3DViewport to the device's viewport list. These viewports
743  * are wrapped to IDirect3DDevice7 viewports in viewport.c
744  *
745  * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
746  * are the same interfaces.
747  *
748  * Params:
749  *  Viewport: The viewport to add
750  *
751  * Returns:
752  *  DDERR_INVALIDPARAMS if Viewport == NULL
753  *  D3D_OK on success
754  *
755  *****************************************************************************/
756 static HRESULT WINAPI d3d_device3_AddViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
757 {
758     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
759     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
760
761     TRACE("iface %p, viewport %p.\n", iface, viewport);
762
763     /* Sanity check */
764     if(!vp)
765         return DDERR_INVALIDPARAMS;
766
767     wined3d_mutex_lock();
768     IDirect3DViewport3_AddRef(viewport);
769     list_add_head(&device->viewport_list, &vp->entry);
770     /* Viewport must be usable for Clear() after AddViewport, so set active_device here. */
771     vp->active_device = device;
772     wined3d_mutex_unlock();
773
774     return D3D_OK;
775 }
776
777 static HRESULT WINAPI d3d_device2_AddViewport(IDirect3DDevice2 *iface,
778         IDirect3DViewport2 *viewport)
779 {
780     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
781     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
782
783     TRACE("iface %p, viewport %p.\n", iface, viewport);
784
785     return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
786 }
787
788 static HRESULT WINAPI d3d_device1_AddViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
789 {
790     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
791     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
792
793     TRACE("iface %p, viewport %p.\n", iface, viewport);
794
795     return d3d_device3_AddViewport(&device->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
796 }
797
798 /*****************************************************************************
799  * IDirect3DDevice3::DeleteViewport
800  *
801  * Deletes a Direct3DViewport from the device's viewport list.
802  *
803  * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
804  * are equal.
805  *
806  * Params:
807  *  Viewport: The viewport to delete
808  *
809  * Returns:
810  *  D3D_OK on success
811  *  DDERR_INVALIDPARAMS if the viewport wasn't found in the list
812  *
813  *****************************************************************************/
814 static HRESULT WINAPI d3d_device3_DeleteViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *viewport)
815 {
816     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
817     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(viewport);
818
819     TRACE("iface %p, viewport %p.\n", iface, viewport);
820
821     if (!vp)
822     {
823         WARN("NULL viewport, returning DDERR_INVALIDPARAMS\n");
824         return DDERR_INVALIDPARAMS;
825     }
826
827     wined3d_mutex_lock();
828
829     if (vp->active_device != device)
830     {
831         WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
832         wined3d_mutex_unlock();
833         return DDERR_INVALIDPARAMS;
834     }
835
836     if (device->current_viewport == vp)
837     {
838         TRACE("Deleting current viewport, unsetting and releasing\n");
839         IDirect3DViewport3_Release(viewport);
840         device->current_viewport = NULL;
841     }
842
843     vp->active_device = NULL;
844     list_remove(&vp->entry);
845
846     IDirect3DViewport3_Release(viewport);
847
848     wined3d_mutex_unlock();
849
850     return D3D_OK;
851 }
852
853 static HRESULT WINAPI d3d_device2_DeleteViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
854 {
855     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
856     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
857
858     TRACE("iface %p, viewport %p.\n", iface, viewport);
859
860     return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
861             vp ? &vp->IDirect3DViewport3_iface : NULL);
862 }
863
864 static HRESULT WINAPI d3d_device1_DeleteViewport(IDirect3DDevice *iface, IDirect3DViewport *viewport)
865 {
866     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
867     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
868
869     TRACE("iface %p, viewport %p.\n", iface, viewport);
870
871     return d3d_device3_DeleteViewport(&device->IDirect3DDevice3_iface,
872             vp ? &vp->IDirect3DViewport3_iface : NULL);
873 }
874
875 /*****************************************************************************
876  * IDirect3DDevice3::NextViewport
877  *
878  * Returns a viewport from the viewport list, depending on the
879  * passed viewport and the flags.
880  *
881  * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
882  * are equal.
883  *
884  * Params:
885  *  Viewport: Viewport to use for beginning the search
886  *  Flags: D3DNEXT_NEXT, D3DNEXT_HEAD or D3DNEXT_TAIL
887  *
888  * Returns:
889  *  D3D_OK on success
890  *  DDERR_INVALIDPARAMS if the flags were wrong, or Viewport was NULL
891  *
892  *****************************************************************************/
893 static HRESULT WINAPI d3d_device3_NextViewport(IDirect3DDevice3 *iface,
894         IDirect3DViewport3 *Viewport3, IDirect3DViewport3 **lplpDirect3DViewport3, DWORD flags)
895 {
896     struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
897     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Viewport3);
898     struct d3d_viewport *next;
899     struct list *entry;
900
901     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
902             iface, Viewport3, lplpDirect3DViewport3, flags);
903
904     if(!vp)
905     {
906         *lplpDirect3DViewport3 = NULL;
907         return DDERR_INVALIDPARAMS;
908     }
909
910
911     wined3d_mutex_lock();
912     switch (flags)
913     {
914         case D3DNEXT_NEXT:
915             entry = list_next(&This->viewport_list, &vp->entry);
916             break;
917
918         case D3DNEXT_HEAD:
919             entry = list_head(&This->viewport_list);
920             break;
921
922         case D3DNEXT_TAIL:
923             entry = list_tail(&This->viewport_list);
924             break;
925
926         default:
927             WARN("Invalid flags %#x.\n", flags);
928             *lplpDirect3DViewport3 = NULL;
929             wined3d_mutex_unlock();
930             return DDERR_INVALIDPARAMS;
931     }
932
933     if (entry)
934     {
935         next = LIST_ENTRY(entry, struct d3d_viewport, entry);
936         *lplpDirect3DViewport3 = &next->IDirect3DViewport3_iface;
937     }
938     else
939         *lplpDirect3DViewport3 = NULL;
940
941     wined3d_mutex_unlock();
942
943     return D3D_OK;
944 }
945
946 static HRESULT WINAPI d3d_device2_NextViewport(IDirect3DDevice2 *iface,
947         IDirect3DViewport2 *viewport, IDirect3DViewport2 **next, DWORD flags)
948 {
949     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
950     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
951     IDirect3DViewport3 *res;
952     HRESULT hr;
953
954     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
955             iface, viewport, next, flags);
956
957     hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
958             &vp->IDirect3DViewport3_iface, &res, flags);
959     *next = (IDirect3DViewport2 *)res;
960     return hr;
961 }
962
963 static HRESULT WINAPI d3d_device1_NextViewport(IDirect3DDevice *iface,
964         IDirect3DViewport *viewport, IDirect3DViewport **next, DWORD flags)
965 {
966     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
967     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport(viewport);
968     IDirect3DViewport3 *res;
969     HRESULT hr;
970
971     TRACE("iface %p, viewport %p, next %p, flags %#x.\n",
972             iface, viewport, next, flags);
973
974     hr = d3d_device3_NextViewport(&device->IDirect3DDevice3_iface,
975             &vp->IDirect3DViewport3_iface, &res, flags);
976     *next = (IDirect3DViewport *)res;
977     return hr;
978 }
979
980 /*****************************************************************************
981  * IDirect3DDevice::Pick
982  *
983  * Executes an execute buffer without performing rendering. Instead, a
984  * list of primitives that intersect with (x1,y1) of the passed rectangle
985  * is created. IDirect3DDevice::GetPickRecords can be used to retrieve
986  * this list.
987  *
988  * Version 1 only
989  *
990  * Params:
991  *  ExecuteBuffer: Buffer to execute
992  *  Viewport: Viewport to use for execution
993  *  Flags: None are defined, according to the SDK
994  *  Rect: Specifies the coordinates to be picked. Only x1 and y2 are used,
995  *        x2 and y2 are ignored.
996  *
997  * Returns:
998  *  D3D_OK because it's a stub
999  *
1000  *****************************************************************************/
1001 static HRESULT WINAPI d3d_device1_Pick(IDirect3DDevice *iface, IDirect3DExecuteBuffer *buffer,
1002         IDirect3DViewport *viewport, DWORD flags, D3DRECT *rect)
1003 {
1004     FIXME("iface %p, buffer %p, viewport %p, flags %#x, rect %s stub!\n",
1005             iface, buffer, viewport, flags, wine_dbgstr_rect((RECT *)rect));
1006
1007     return D3D_OK;
1008 }
1009
1010 /*****************************************************************************
1011  * IDirect3DDevice::GetPickRecords
1012  *
1013  * Retrieves the pick records generated by IDirect3DDevice::GetPickRecords
1014  *
1015  * Version 1 only
1016  *
1017  * Params:
1018  *  Count: Pointer to a DWORD containing the numbers of pick records to
1019  *         retrieve
1020  *  D3DPickRec: Address to store the resulting D3DPICKRECORD array.
1021  *
1022  * Returns:
1023  *  D3D_OK, because it's a stub
1024  *
1025  *****************************************************************************/
1026 static HRESULT WINAPI d3d_device1_GetPickRecords(IDirect3DDevice *iface,
1027         DWORD *count, D3DPICKRECORD *records)
1028 {
1029     FIXME("iface %p, count %p, records %p stub!\n", iface, count, records);
1030
1031     return D3D_OK;
1032 }
1033
1034 /*****************************************************************************
1035  * IDirect3DDevice7::EnumTextureformats
1036  *
1037  * Enumerates the supported texture formats. It has a list of all possible
1038  * formats and calls IWineD3D::CheckDeviceFormat for each format to see if
1039  * WineD3D supports it. If so, then it is passed to the app.
1040  *
1041  * This is for Version 7 and 3, older versions have a different
1042  * callback function and their own implementation
1043  *
1044  * Params:
1045  *  Callback: Callback to call for each enumerated format
1046  *  Arg: Argument to pass to the callback
1047  *
1048  * Returns:
1049  *  D3D_OK on success
1050  *  DDERR_INVALIDPARAMS if Callback == NULL
1051  *
1052  *****************************************************************************/
1053 static HRESULT d3d_device7_EnumTextureFormats(IDirect3DDevice7 *iface,
1054         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1055 {
1056     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1057     struct wined3d_display_mode mode;
1058     HRESULT hr;
1059     unsigned int i;
1060
1061     static const enum wined3d_format_id FormatList[] =
1062     {
1063         /* 16 bit */
1064         WINED3DFMT_B5G5R5X1_UNORM,
1065         WINED3DFMT_B5G5R5A1_UNORM,
1066         WINED3DFMT_B4G4R4A4_UNORM,
1067         WINED3DFMT_B5G6R5_UNORM,
1068         /* 32 bit */
1069         WINED3DFMT_B8G8R8X8_UNORM,
1070         WINED3DFMT_B8G8R8A8_UNORM,
1071         /* 8 bit */
1072         WINED3DFMT_B2G3R3_UNORM,
1073         WINED3DFMT_P8_UINT,
1074         /* FOURCC codes */
1075         WINED3DFMT_DXT1,
1076         WINED3DFMT_DXT3,
1077         WINED3DFMT_DXT5,
1078     };
1079
1080     static const enum wined3d_format_id BumpFormatList[] =
1081     {
1082         WINED3DFMT_R8G8_SNORM,
1083         WINED3DFMT_R5G5_SNORM_L6_UNORM,
1084         WINED3DFMT_R8G8_SNORM_L8X8_UNORM,
1085         WINED3DFMT_R16G16_SNORM,
1086         WINED3DFMT_R10G11B11_SNORM,
1087         WINED3DFMT_R10G10B10_SNORM_A2_UNORM
1088     };
1089
1090     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1091
1092     if (!callback)
1093         return DDERR_INVALIDPARAMS;
1094
1095     wined3d_mutex_lock();
1096
1097     memset(&mode, 0, sizeof(mode));
1098     if (FAILED(hr = wined3d_get_adapter_display_mode(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
1099     {
1100         wined3d_mutex_unlock();
1101         WARN("Cannot get the current adapter format\n");
1102         return hr;
1103     }
1104
1105     for (i = 0; i < sizeof(FormatList) / sizeof(*FormatList); ++i)
1106     {
1107         if (wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, WINED3D_DEVICE_TYPE_HAL,
1108                 mode.format_id, 0, WINED3D_RTYPE_TEXTURE, FormatList[i]) == D3D_OK)
1109         {
1110             DDPIXELFORMAT pformat;
1111
1112             memset(&pformat, 0, sizeof(pformat));
1113             pformat.dwSize = sizeof(pformat);
1114             PixelFormat_WineD3DtoDD(&pformat, FormatList[i]);
1115
1116             TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1117             hr = callback(&pformat, context);
1118             if(hr != DDENUMRET_OK)
1119             {
1120                 TRACE("Format enumeration cancelled by application\n");
1121                 wined3d_mutex_unlock();
1122                 return D3D_OK;
1123             }
1124         }
1125     }
1126
1127     for (i = 0; i < sizeof(BumpFormatList) / sizeof(*BumpFormatList); ++i)
1128     {
1129         if (wined3d_check_device_format(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT,
1130                 WINED3D_DEVICE_TYPE_HAL, mode.format_id, WINED3DUSAGE_QUERY_LEGACYBUMPMAP,
1131                 WINED3D_RTYPE_TEXTURE, BumpFormatList[i]) == D3D_OK)
1132         {
1133             DDPIXELFORMAT pformat;
1134
1135             memset(&pformat, 0, sizeof(pformat));
1136             pformat.dwSize = sizeof(pformat);
1137             PixelFormat_WineD3DtoDD(&pformat, BumpFormatList[i]);
1138
1139             TRACE("Enumerating WineD3DFormat %d\n", BumpFormatList[i]);
1140             hr = callback(&pformat, context);
1141             if(hr != DDENUMRET_OK)
1142             {
1143                 TRACE("Format enumeration cancelled by application\n");
1144                 wined3d_mutex_unlock();
1145                 return D3D_OK;
1146             }
1147         }
1148     }
1149     TRACE("End of enumeration\n");
1150     wined3d_mutex_unlock();
1151
1152     return D3D_OK;
1153 }
1154
1155 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUSetup(IDirect3DDevice7 *iface,
1156         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1157 {
1158     return d3d_device7_EnumTextureFormats(iface, callback, context);
1159 }
1160
1161 static HRESULT WINAPI d3d_device7_EnumTextureFormats_FPUPreserve(IDirect3DDevice7 *iface,
1162         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1163 {
1164     HRESULT hr;
1165     WORD old_fpucw;
1166
1167     old_fpucw = d3d_fpu_setup();
1168     hr = d3d_device7_EnumTextureFormats(iface, callback, context);
1169     set_fpu_control_word(old_fpucw);
1170
1171     return hr;
1172 }
1173
1174 static HRESULT WINAPI d3d_device3_EnumTextureFormats(IDirect3DDevice3 *iface,
1175         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
1176 {
1177     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1178
1179     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1180
1181     return IDirect3DDevice7_EnumTextureFormats(&device->IDirect3DDevice7_iface, callback, context);
1182 }
1183
1184 /*****************************************************************************
1185  * IDirect3DDevice2::EnumTextureformats
1186  *
1187  * EnumTextureFormats for Version 1 and 2, see
1188  * IDirect3DDevice7::EnumTexureFormats for a more detailed description.
1189  *
1190  * This version has a different callback and does not enumerate FourCC
1191  * formats
1192  *
1193  *****************************************************************************/
1194 static HRESULT WINAPI d3d_device2_EnumTextureFormats(IDirect3DDevice2 *iface,
1195         LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1196 {
1197     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1198     struct wined3d_display_mode mode;
1199     HRESULT hr;
1200     unsigned int i;
1201
1202     static const enum wined3d_format_id FormatList[] =
1203     {
1204         /* 16 bit */
1205         WINED3DFMT_B5G5R5X1_UNORM,
1206         WINED3DFMT_B5G5R5A1_UNORM,
1207         WINED3DFMT_B4G4R4A4_UNORM,
1208         WINED3DFMT_B5G6R5_UNORM,
1209         /* 32 bit */
1210         WINED3DFMT_B8G8R8X8_UNORM,
1211         WINED3DFMT_B8G8R8A8_UNORM,
1212         /* 8 bit */
1213         WINED3DFMT_B2G3R3_UNORM,
1214         WINED3DFMT_P8_UINT,
1215         /* FOURCC codes - Not in this version*/
1216     };
1217
1218     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1219
1220     if (!callback)
1221         return DDERR_INVALIDPARAMS;
1222
1223     wined3d_mutex_lock();
1224
1225     memset(&mode, 0, sizeof(mode));
1226     if (FAILED(hr = wined3d_get_adapter_display_mode(device->ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
1227     {
1228         wined3d_mutex_unlock();
1229         WARN("Cannot get the current adapter format\n");
1230         return hr;
1231     }
1232
1233     for (i = 0; i < sizeof(FormatList) / sizeof(*FormatList); ++i)
1234     {
1235         if (wined3d_check_device_format(device->ddraw->wined3d, 0, WINED3D_DEVICE_TYPE_HAL,
1236                 mode.format_id, 0, WINED3D_RTYPE_TEXTURE, FormatList[i]) == D3D_OK)
1237         {
1238             DDSURFACEDESC sdesc;
1239
1240             memset(&sdesc, 0, sizeof(sdesc));
1241             sdesc.dwSize = sizeof(sdesc);
1242             sdesc.dwFlags = DDSD_PIXELFORMAT | DDSD_CAPS;
1243             sdesc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
1244             sdesc.ddpfPixelFormat.dwSize = sizeof(sdesc.ddpfPixelFormat);
1245             PixelFormat_WineD3DtoDD(&sdesc.ddpfPixelFormat, FormatList[i]);
1246
1247             TRACE("Enumerating WineD3DFormat %d\n", FormatList[i]);
1248             hr = callback(&sdesc, context);
1249             if(hr != DDENUMRET_OK)
1250             {
1251                 TRACE("Format enumeration cancelled by application\n");
1252                 wined3d_mutex_unlock();
1253                 return D3D_OK;
1254             }
1255         }
1256     }
1257     TRACE("End of enumeration\n");
1258     wined3d_mutex_unlock();
1259
1260     return D3D_OK;
1261 }
1262
1263 static HRESULT WINAPI d3d_device1_EnumTextureFormats(IDirect3DDevice *iface,
1264         LPD3DENUMTEXTUREFORMATSCALLBACK callback, void *context)
1265 {
1266     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1267
1268     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
1269
1270     return d3d_device2_EnumTextureFormats(&device->IDirect3DDevice2_iface, callback, context);
1271 }
1272
1273 /*****************************************************************************
1274  * IDirect3DDevice::CreateMatrix
1275  *
1276  * Creates a matrix handle. A handle is created and memory for a D3DMATRIX is
1277  * allocated for the handle.
1278  *
1279  * Version 1 only
1280  *
1281  * Params
1282  *  D3DMatHandle: Address to return the handle at
1283  *
1284  * Returns:
1285  *  D3D_OK on success
1286  *  DDERR_INVALIDPARAMS if D3DMatHandle = NULL
1287  *
1288  *****************************************************************************/
1289 static HRESULT WINAPI d3d_device1_CreateMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE *D3DMatHandle)
1290 {
1291     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1292     D3DMATRIX *Matrix;
1293     DWORD h;
1294
1295     TRACE("iface %p, matrix_handle %p.\n", iface, D3DMatHandle);
1296
1297     if(!D3DMatHandle)
1298         return DDERR_INVALIDPARAMS;
1299
1300     Matrix = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(D3DMATRIX));
1301     if(!Matrix)
1302     {
1303         ERR("Out of memory when allocating a D3DMATRIX\n");
1304         return DDERR_OUTOFMEMORY;
1305     }
1306
1307     wined3d_mutex_lock();
1308
1309     h = ddraw_allocate_handle(&device->handle_table, Matrix, DDRAW_HANDLE_MATRIX);
1310     if (h == DDRAW_INVALID_HANDLE)
1311     {
1312         ERR("Failed to allocate a matrix handle.\n");
1313         HeapFree(GetProcessHeap(), 0, Matrix);
1314         wined3d_mutex_unlock();
1315         return DDERR_OUTOFMEMORY;
1316     }
1317
1318     *D3DMatHandle = h + 1;
1319
1320     TRACE(" returning matrix handle %d\n", *D3DMatHandle);
1321
1322     wined3d_mutex_unlock();
1323
1324     return D3D_OK;
1325 }
1326
1327 /*****************************************************************************
1328  * IDirect3DDevice::SetMatrix
1329  *
1330  * Sets a matrix for a matrix handle. The matrix is copied into the memory
1331  * allocated for the handle
1332  *
1333  * Version 1 only
1334  *
1335  * Params:
1336  *  D3DMatHandle: Handle to set the matrix to
1337  *  D3DMatrix: Matrix to set
1338  *
1339  * Returns:
1340  *  D3D_OK on success
1341  *  DDERR_INVALIDPARAMS if the handle of the matrix is invalid or the matrix
1342  *   to set is NULL
1343  *
1344  *****************************************************************************/
1345 static HRESULT WINAPI d3d_device1_SetMatrix(IDirect3DDevice *iface,
1346         D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1347 {
1348     struct d3d_device *This = impl_from_IDirect3DDevice(iface);
1349     D3DMATRIX *m;
1350
1351     TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1352
1353     if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1354
1355     wined3d_mutex_lock();
1356
1357     m = ddraw_get_object(&This->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1358     if (!m)
1359     {
1360         WARN("Invalid matrix handle.\n");
1361         wined3d_mutex_unlock();
1362         return DDERR_INVALIDPARAMS;
1363     }
1364
1365     if (TRACE_ON(ddraw))
1366         dump_D3DMATRIX(D3DMatrix);
1367
1368     *m = *D3DMatrix;
1369
1370     if (D3DMatHandle == This->world)
1371         wined3d_device_set_transform(This->wined3d_device,
1372                 WINED3D_TS_WORLD_MATRIX(0), (struct wined3d_matrix *)D3DMatrix);
1373
1374     if (D3DMatHandle == This->view)
1375         wined3d_device_set_transform(This->wined3d_device,
1376                 WINED3D_TS_VIEW, (struct wined3d_matrix *)D3DMatrix);
1377
1378     if (D3DMatHandle == This->proj)
1379         wined3d_device_set_transform(This->wined3d_device,
1380                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)D3DMatrix);
1381
1382     wined3d_mutex_unlock();
1383
1384     return D3D_OK;
1385 }
1386
1387 /*****************************************************************************
1388  * IDirect3DDevice::GetMatrix
1389  *
1390  * Returns the content of a D3DMATRIX handle
1391  *
1392  * Version 1 only
1393  *
1394  * Params:
1395  *  D3DMatHandle: Matrix handle to read the content from
1396  *  D3DMatrix: Address to store the content at
1397  *
1398  * Returns:
1399  *  D3D_OK on success
1400  *  DDERR_INVALIDPARAMS if D3DMatHandle is invalid or D3DMatrix is NULL
1401  *
1402  *****************************************************************************/
1403 static HRESULT WINAPI d3d_device1_GetMatrix(IDirect3DDevice *iface,
1404         D3DMATRIXHANDLE D3DMatHandle, D3DMATRIX *D3DMatrix)
1405 {
1406     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1407     D3DMATRIX *m;
1408
1409     TRACE("iface %p, matrix_handle %#x, matrix %p.\n", iface, D3DMatHandle, D3DMatrix);
1410
1411     if (!D3DMatrix) return DDERR_INVALIDPARAMS;
1412
1413     wined3d_mutex_lock();
1414
1415     m = ddraw_get_object(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1416     if (!m)
1417     {
1418         WARN("Invalid matrix handle.\n");
1419         wined3d_mutex_unlock();
1420         return DDERR_INVALIDPARAMS;
1421     }
1422
1423     *D3DMatrix = *m;
1424
1425     wined3d_mutex_unlock();
1426
1427     return D3D_OK;
1428 }
1429
1430 /*****************************************************************************
1431  * IDirect3DDevice::DeleteMatrix
1432  *
1433  * Destroys a Matrix handle. Frees the memory and unsets the handle data
1434  *
1435  * Version 1 only
1436  *
1437  * Params:
1438  *  D3DMatHandle: Handle to destroy
1439  *
1440  * Returns:
1441  *  D3D_OK on success
1442  *  DDERR_INVALIDPARAMS if D3DMatHandle is invalid
1443  *
1444  *****************************************************************************/
1445 static HRESULT WINAPI d3d_device1_DeleteMatrix(IDirect3DDevice *iface, D3DMATRIXHANDLE D3DMatHandle)
1446 {
1447     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1448     D3DMATRIX *m;
1449
1450     TRACE("iface %p, matrix_handle %#x.\n", iface, D3DMatHandle);
1451
1452     wined3d_mutex_lock();
1453
1454     m = ddraw_free_handle(&device->handle_table, D3DMatHandle - 1, DDRAW_HANDLE_MATRIX);
1455     if (!m)
1456     {
1457         WARN("Invalid matrix handle.\n");
1458         wined3d_mutex_unlock();
1459         return DDERR_INVALIDPARAMS;
1460     }
1461
1462     wined3d_mutex_unlock();
1463
1464     HeapFree(GetProcessHeap(), 0, m);
1465
1466     return D3D_OK;
1467 }
1468
1469 /*****************************************************************************
1470  * IDirect3DDevice7::BeginScene
1471  *
1472  * This method must be called before any rendering is performed.
1473  * IDirect3DDevice::EndScene has to be called after the scene is complete
1474  *
1475  * Version 1, 2, 3 and 7
1476  *
1477  * Returns:
1478  *  D3D_OK on success, for details see IWineD3DDevice::BeginScene
1479  *  D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already
1480  *  started scene).
1481  *
1482  *****************************************************************************/
1483 static HRESULT d3d_device7_BeginScene(IDirect3DDevice7 *iface)
1484 {
1485     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1486     HRESULT hr;
1487
1488     TRACE("iface %p.\n", iface);
1489
1490     wined3d_mutex_lock();
1491     hr = wined3d_device_begin_scene(device->wined3d_device);
1492     wined3d_mutex_unlock();
1493
1494     if(hr == WINED3D_OK) return D3D_OK;
1495     else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */
1496 }
1497
1498 static HRESULT WINAPI d3d_device7_BeginScene_FPUSetup(IDirect3DDevice7 *iface)
1499 {
1500     return d3d_device7_BeginScene(iface);
1501 }
1502
1503 static HRESULT WINAPI d3d_device7_BeginScene_FPUPreserve(IDirect3DDevice7 *iface)
1504 {
1505     HRESULT hr;
1506     WORD old_fpucw;
1507
1508     old_fpucw = d3d_fpu_setup();
1509     hr = d3d_device7_BeginScene(iface);
1510     set_fpu_control_word(old_fpucw);
1511
1512     return hr;
1513 }
1514
1515 static HRESULT WINAPI d3d_device3_BeginScene(IDirect3DDevice3 *iface)
1516 {
1517     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1518
1519     TRACE("iface %p.\n", iface);
1520
1521     return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1522 }
1523
1524 static HRESULT WINAPI d3d_device2_BeginScene(IDirect3DDevice2 *iface)
1525 {
1526     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1527
1528     TRACE("iface %p.\n", iface);
1529
1530     return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1531 }
1532
1533 static HRESULT WINAPI d3d_device1_BeginScene(IDirect3DDevice *iface)
1534 {
1535     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1536
1537     TRACE("iface %p.\n", iface);
1538
1539     return IDirect3DDevice7_BeginScene(&device->IDirect3DDevice7_iface);
1540 }
1541
1542 /*****************************************************************************
1543  * IDirect3DDevice7::EndScene
1544  *
1545  * Ends a scene that has been begun with IDirect3DDevice7::BeginScene.
1546  * This method must be called after rendering is finished.
1547  *
1548  * Version 1, 2, 3 and 7
1549  *
1550  * Returns:
1551  *  D3D_OK on success, for details see IWineD3DDevice::EndScene
1552  *  D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does
1553  *  that only if the scene was already ended.
1554  *
1555  *****************************************************************************/
1556 static HRESULT d3d_device7_EndScene(IDirect3DDevice7 *iface)
1557 {
1558     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1559     HRESULT hr;
1560
1561     TRACE("iface %p.\n", iface);
1562
1563     wined3d_mutex_lock();
1564     hr = wined3d_device_end_scene(device->wined3d_device);
1565     wined3d_mutex_unlock();
1566
1567     if(hr == WINED3D_OK) return D3D_OK;
1568     else return D3DERR_SCENE_NOT_IN_SCENE;
1569 }
1570
1571 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUSetup(IDirect3DDevice7 *iface)
1572 {
1573     return d3d_device7_EndScene(iface);
1574 }
1575
1576 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device7_EndScene_FPUPreserve(IDirect3DDevice7 *iface)
1577 {
1578     HRESULT hr;
1579     WORD old_fpucw;
1580
1581     old_fpucw = d3d_fpu_setup();
1582     hr = d3d_device7_EndScene(iface);
1583     set_fpu_control_word(old_fpucw);
1584
1585     return hr;
1586 }
1587
1588 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device3_EndScene(IDirect3DDevice3 *iface)
1589 {
1590     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1591
1592     TRACE("iface %p.\n", iface);
1593
1594     return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1595 }
1596
1597 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device2_EndScene(IDirect3DDevice2 *iface)
1598 {
1599     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1600
1601     TRACE("iface %p.\n", iface);
1602
1603     return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1604 }
1605
1606 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d_device1_EndScene(IDirect3DDevice *iface)
1607 {
1608     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1609
1610     TRACE("iface %p.\n", iface);
1611
1612     return IDirect3DDevice7_EndScene(&device->IDirect3DDevice7_iface);
1613 }
1614
1615 /*****************************************************************************
1616  * IDirect3DDevice7::GetDirect3D
1617  *
1618  * Returns the IDirect3D(= interface to the DirectDraw object) used to create
1619  * this device.
1620  *
1621  * Params:
1622  *  Direct3D7: Address to store the interface pointer at
1623  *
1624  * Returns:
1625  *  D3D_OK on success
1626  *  DDERR_INVALIDPARAMS if Direct3D7 == NULL
1627  *
1628  *****************************************************************************/
1629 static HRESULT WINAPI d3d_device7_GetDirect3D(IDirect3DDevice7 *iface, IDirect3D7 **d3d)
1630 {
1631     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1632
1633     TRACE("iface %p, d3d %p.\n", iface, d3d);
1634
1635     if (!d3d)
1636         return DDERR_INVALIDPARAMS;
1637
1638     *d3d = &device->ddraw->IDirect3D7_iface;
1639     IDirect3D7_AddRef(*d3d);
1640
1641     TRACE("Returning interface %p.\n", *d3d);
1642     return D3D_OK;
1643 }
1644
1645 static HRESULT WINAPI d3d_device3_GetDirect3D(IDirect3DDevice3 *iface, IDirect3D3 **d3d)
1646 {
1647     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1648
1649     TRACE("iface %p, d3d %p.\n", iface, d3d);
1650
1651     if (!d3d)
1652         return DDERR_INVALIDPARAMS;
1653
1654     *d3d = &device->ddraw->IDirect3D3_iface;
1655     IDirect3D3_AddRef(*d3d);
1656
1657     TRACE("Returning interface %p.\n", *d3d);
1658     return D3D_OK;
1659 }
1660
1661 static HRESULT WINAPI d3d_device2_GetDirect3D(IDirect3DDevice2 *iface, IDirect3D2 **d3d)
1662 {
1663     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1664
1665     TRACE("iface %p, d3d %p.\n", iface, d3d);
1666
1667     if (!d3d)
1668         return DDERR_INVALIDPARAMS;
1669
1670     *d3d = &device->ddraw->IDirect3D2_iface;
1671     IDirect3D2_AddRef(*d3d);
1672
1673     TRACE("Returning interface %p.\n", *d3d);
1674     return D3D_OK;
1675 }
1676
1677 static HRESULT WINAPI d3d_device1_GetDirect3D(IDirect3DDevice *iface, IDirect3D **d3d)
1678 {
1679     struct d3d_device *device = impl_from_IDirect3DDevice(iface);
1680
1681     TRACE("iface %p, d3d %p.\n", iface, d3d);
1682
1683     if (!d3d)
1684         return DDERR_INVALIDPARAMS;
1685
1686     *d3d = &device->ddraw->IDirect3D_iface;
1687     IDirect3D_AddRef(*d3d);
1688
1689     TRACE("Returning interface %p.\n", *d3d);
1690     return D3D_OK;
1691 }
1692
1693 /*****************************************************************************
1694  * IDirect3DDevice3::SetCurrentViewport
1695  *
1696  * Sets a Direct3DViewport as the current viewport.
1697  * For the thunks note that all viewport interface versions are equal
1698  *
1699  * Params:
1700  *  Direct3DViewport3: The viewport to set
1701  *
1702  * Version 2 and 3
1703  *
1704  * Returns:
1705  *  D3D_OK on success
1706  *  (Is a NULL viewport valid?)
1707  *
1708  *****************************************************************************/
1709 static HRESULT WINAPI d3d_device3_SetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 *Direct3DViewport3)
1710 {
1711     struct d3d_device *This = impl_from_IDirect3DDevice3(iface);
1712     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport3(Direct3DViewport3);
1713
1714     TRACE("iface %p, viewport %p.\n", iface, Direct3DViewport3);
1715
1716     if (!vp)
1717     {
1718         WARN("Direct3DViewport3 is NULL, returning DDERR_INVALIDPARAMS\n");
1719         return DDERR_INVALIDPARAMS;
1720     }
1721
1722     wined3d_mutex_lock();
1723     /* Do nothing if the specified viewport is the same as the current one */
1724     if (This->current_viewport == vp)
1725     {
1726         wined3d_mutex_unlock();
1727         return D3D_OK;
1728     }
1729
1730     if (vp->active_device != This)
1731     {
1732         WARN("Viewport %p active device is %p.\n", vp, vp->active_device);
1733         wined3d_mutex_unlock();
1734         return DDERR_INVALIDPARAMS;
1735     }
1736
1737     /* Release previous viewport and AddRef the new one */
1738     if (This->current_viewport)
1739     {
1740         TRACE("ViewportImpl is at %p, interface is at %p\n", This->current_viewport,
1741                 &This->current_viewport->IDirect3DViewport3_iface);
1742         IDirect3DViewport3_Release(&This->current_viewport->IDirect3DViewport3_iface);
1743     }
1744     IDirect3DViewport3_AddRef(Direct3DViewport3);
1745
1746     /* Set this viewport as the current viewport */
1747     This->current_viewport = vp;
1748
1749     /* Activate this viewport */
1750     viewport_activate(This->current_viewport, FALSE);
1751
1752     wined3d_mutex_unlock();
1753
1754     return D3D_OK;
1755 }
1756
1757 static HRESULT WINAPI d3d_device2_SetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 *viewport)
1758 {
1759     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1760     struct d3d_viewport *vp = unsafe_impl_from_IDirect3DViewport2(viewport);
1761
1762     TRACE("iface %p, viewport %p.\n", iface, viewport);
1763
1764     return d3d_device3_SetCurrentViewport(&device->IDirect3DDevice3_iface,
1765             vp ? &vp->IDirect3DViewport3_iface : NULL);
1766 }
1767
1768 /*****************************************************************************
1769  * IDirect3DDevice3::GetCurrentViewport
1770  *
1771  * Returns the currently active viewport.
1772  *
1773  * Version 2 and 3
1774  *
1775  * Params:
1776  *  Direct3DViewport3: Address to return the interface pointer at
1777  *
1778  * Returns:
1779  *  D3D_OK on success
1780  *  DDERR_INVALIDPARAMS if Direct3DViewport == NULL
1781  *
1782  *****************************************************************************/
1783 static HRESULT WINAPI d3d_device3_GetCurrentViewport(IDirect3DDevice3 *iface, IDirect3DViewport3 **viewport)
1784 {
1785     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1786
1787     TRACE("iface %p, viewport %p.\n", iface, viewport);
1788
1789     wined3d_mutex_lock();
1790     if (!device->current_viewport)
1791     {
1792         wined3d_mutex_unlock();
1793         WARN("No current viewport, returning D3DERR_NOCURRENTVIEWPORT\n");
1794         return D3DERR_NOCURRENTVIEWPORT;
1795     }
1796
1797     *viewport = &device->current_viewport->IDirect3DViewport3_iface;
1798     IDirect3DViewport3_AddRef(*viewport);
1799
1800     TRACE("Returning interface %p.\n", *viewport);
1801     wined3d_mutex_unlock();
1802     return D3D_OK;
1803 }
1804
1805 static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, IDirect3DViewport2 **viewport)
1806 {
1807     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1808
1809     TRACE("iface %p, viewport %p.\n", iface, viewport);
1810
1811     return d3d_device3_GetCurrentViewport(&device->IDirect3DDevice3_iface,
1812             (IDirect3DViewport3 **)viewport);
1813 }
1814
1815 /*****************************************************************************
1816  * IDirect3DDevice7::SetRenderTarget
1817  *
1818  * Sets the render target for the Direct3DDevice.
1819  * For the thunks note that IDirectDrawSurface7 == IDirectDrawSurface4 and
1820  * IDirectDrawSurface3 == IDirectDrawSurface
1821  *
1822  * Version 2, 3 and 7
1823  *
1824  * Params:
1825  *  NewTarget: Pointer to an IDirectDrawSurface7 interface to set as the new
1826  *             render target
1827  *  Flags: Some flags
1828  *
1829  * Returns:
1830  *  D3D_OK on success, for details see IWineD3DDevice::SetRenderTarget
1831  *
1832  *****************************************************************************/
1833 static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct ddraw_surface *target)
1834 {
1835     HRESULT hr;
1836
1837     wined3d_mutex_lock();
1838
1839     if (device->target == target)
1840     {
1841         TRACE("No-op SetRenderTarget operation, not doing anything\n");
1842         wined3d_mutex_unlock();
1843         return D3D_OK;
1844     }
1845     device->target = target;
1846     hr = wined3d_device_set_render_target(device->wined3d_device, 0,
1847             target ? target->wined3d_surface : NULL, FALSE);
1848     if(hr != D3D_OK)
1849     {
1850         wined3d_mutex_unlock();
1851         return hr;
1852     }
1853     d3d_device_update_depth_stencil(device);
1854
1855     wined3d_mutex_unlock();
1856
1857     return D3D_OK;
1858 }
1859
1860 static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
1861         IDirectDrawSurface7 *NewTarget, DWORD flags)
1862 {
1863     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1864     struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface7(NewTarget);
1865
1866     TRACE("iface %p, target %p, flags %#x.\n", iface, NewTarget, flags);
1867
1868     IDirectDrawSurface7_AddRef(NewTarget);
1869     IDirectDrawSurface7_Release(&device->target->IDirectDrawSurface7_iface);
1870     return d3d_device_set_render_target(device, target);
1871 }
1872
1873 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
1874         IDirectDrawSurface7 *NewTarget, DWORD flags)
1875 {
1876     return d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1877 }
1878
1879 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *iface,
1880         IDirectDrawSurface7 *NewTarget, DWORD flags)
1881 {
1882     HRESULT hr;
1883     WORD old_fpucw;
1884
1885     old_fpucw = d3d_fpu_setup();
1886     hr = d3d_device7_SetRenderTarget(iface, NewTarget, flags);
1887     set_fpu_control_word(old_fpucw);
1888
1889     return hr;
1890 }
1891
1892 static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
1893         IDirectDrawSurface4 *NewRenderTarget, DWORD flags)
1894 {
1895     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1896     struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface4(NewRenderTarget);
1897
1898     TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, flags);
1899
1900     IDirectDrawSurface4_AddRef(NewRenderTarget);
1901     IDirectDrawSurface4_Release(&device->target->IDirectDrawSurface4_iface);
1902     return d3d_device_set_render_target(device, target);
1903 }
1904
1905 static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
1906         IDirectDrawSurface *NewRenderTarget, DWORD flags)
1907 {
1908     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1909     struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface(NewRenderTarget);
1910
1911     TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, flags);
1912
1913     IDirectDrawSurface_AddRef(NewRenderTarget);
1914     IDirectDrawSurface_Release(&device->target->IDirectDrawSurface_iface);
1915     return d3d_device_set_render_target(device, target);
1916 }
1917
1918 /*****************************************************************************
1919  * IDirect3DDevice7::GetRenderTarget
1920  *
1921  * Returns the current render target.
1922  * This is handled locally, because the WineD3D render target's parent
1923  * is an IParent
1924  *
1925  * Version 2, 3 and 7
1926  *
1927  * Params:
1928  *  RenderTarget: Address to store the surface interface pointer
1929  *
1930  * Returns:
1931  *  D3D_OK on success
1932  *  DDERR_INVALIDPARAMS if RenderTarget == NULL
1933  *
1934  *****************************************************************************/
1935 static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
1936 {
1937     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
1938
1939     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1940
1941     if(!RenderTarget)
1942         return DDERR_INVALIDPARAMS;
1943
1944     wined3d_mutex_lock();
1945     *RenderTarget = &device->target->IDirectDrawSurface7_iface;
1946     IDirectDrawSurface7_AddRef(*RenderTarget);
1947     wined3d_mutex_unlock();
1948
1949     return D3D_OK;
1950 }
1951
1952 static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
1953 {
1954     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
1955     IDirectDrawSurface7 *RenderTarget7;
1956     struct ddraw_surface *RenderTargetImpl;
1957     HRESULT hr;
1958
1959     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1960
1961     if(!RenderTarget)
1962         return DDERR_INVALIDPARAMS;
1963
1964     hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
1965     if(hr != D3D_OK) return hr;
1966     RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
1967     *RenderTarget = &RenderTargetImpl->IDirectDrawSurface4_iface;
1968     IDirectDrawSurface4_AddRef(*RenderTarget);
1969     IDirectDrawSurface7_Release(RenderTarget7);
1970     return D3D_OK;
1971 }
1972
1973 static HRESULT WINAPI d3d_device2_GetRenderTarget(IDirect3DDevice2 *iface, IDirectDrawSurface **RenderTarget)
1974 {
1975     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
1976     IDirectDrawSurface7 *RenderTarget7;
1977     struct ddraw_surface *RenderTargetImpl;
1978     HRESULT hr;
1979
1980     TRACE("iface %p, target %p.\n", iface, RenderTarget);
1981
1982     if(!RenderTarget)
1983         return DDERR_INVALIDPARAMS;
1984
1985     hr = d3d_device7_GetRenderTarget(&device->IDirect3DDevice7_iface, &RenderTarget7);
1986     if(hr != D3D_OK) return hr;
1987     RenderTargetImpl = impl_from_IDirectDrawSurface7(RenderTarget7);
1988     *RenderTarget = &RenderTargetImpl->IDirectDrawSurface_iface;
1989     IDirectDrawSurface_AddRef(*RenderTarget);
1990     IDirectDrawSurface7_Release(RenderTarget7);
1991     return D3D_OK;
1992 }
1993
1994 /*****************************************************************************
1995  * IDirect3DDevice3::Begin
1996  *
1997  * Begins a description block of vertices. This is similar to glBegin()
1998  * and glEnd(). After a call to IDirect3DDevice3::End, the vertices
1999  * described with IDirect3DDevice::Vertex are drawn.
2000  *
2001  * Version 2 and 3
2002  *
2003  * Params:
2004  *  PrimitiveType: The type of primitives to draw
2005  *  VertexTypeDesc: A flexible vertex format description of the vertices
2006  *  Flags: Some flags..
2007  *
2008  * Returns:
2009  *  D3D_OK on success
2010  *
2011  *****************************************************************************/
2012 static HRESULT WINAPI d3d_device3_Begin(IDirect3DDevice3 *iface,
2013         D3DPRIMITIVETYPE primitive_type, DWORD fvf, DWORD flags)
2014 {
2015     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2016
2017     TRACE("iface %p, primitive_type %#x, fvf %#x, flags %#x.\n",
2018             iface, primitive_type, fvf, flags);
2019
2020     wined3d_mutex_lock();
2021     device->primitive_type = primitive_type;
2022     device->vertex_type = fvf;
2023     device->render_flags = flags;
2024     device->vertex_size = get_flexible_vertex_size(device->vertex_type);
2025     device->nb_vertices = 0;
2026     wined3d_mutex_unlock();
2027
2028     return D3D_OK;
2029 }
2030
2031 static HRESULT WINAPI d3d_device2_Begin(IDirect3DDevice2 *iface,
2032         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, DWORD flags)
2033 {
2034     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2035     DWORD fvf;
2036
2037     TRACE("iface %p, primitive_type %#x, vertex_type %#x, flags %#x.\n",
2038             iface, primitive_type, vertex_type, flags);
2039
2040     switch (vertex_type)
2041     {
2042         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2043         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2044         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2045         default:
2046             ERR("Unexpected vertex type %#x.\n", vertex_type);
2047             return DDERR_INVALIDPARAMS;  /* Should never happen */
2048     };
2049
2050     return d3d_device3_Begin(&device->IDirect3DDevice3_iface, primitive_type, fvf, flags);
2051 }
2052
2053 /*****************************************************************************
2054  * IDirect3DDevice3::BeginIndexed
2055  *
2056  * Draws primitives based on vertices in a vertex array which are specified
2057  * by indices.
2058  *
2059  * Version 2 and 3
2060  *
2061  * Params:
2062  *  PrimitiveType: Primitive type to draw
2063  *  VertexType: A FVF description of the vertex format
2064  *  Vertices: pointer to an array containing the vertices
2065  *  NumVertices: The number of vertices in the vertex array
2066  *  Flags: Some flags ...
2067  *
2068  * Returns:
2069  *  D3D_OK, because it's a stub
2070  *
2071  *****************************************************************************/
2072 static HRESULT WINAPI d3d_device3_BeginIndexed(IDirect3DDevice3 *iface,
2073         D3DPRIMITIVETYPE primitive_type, DWORD fvf,
2074         void *vertices, DWORD vertex_count, DWORD flags)
2075 {
2076     FIXME("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2077             iface, primitive_type, fvf, vertices, vertex_count, flags);
2078
2079     return D3D_OK;
2080 }
2081
2082
2083 static HRESULT WINAPI d3d_device2_BeginIndexed(IDirect3DDevice2 *iface,
2084         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type,
2085         void *vertices, DWORD vertex_count, DWORD flags)
2086 {
2087     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2088     DWORD fvf;
2089
2090     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x stub!\n",
2091             iface, primitive_type, vertex_type, vertices, vertex_count, flags);
2092
2093     switch (vertex_type)
2094     {
2095         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
2096         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
2097         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
2098         default:
2099             ERR("Unexpected vertex type %#x.\n", vertex_type);
2100             return DDERR_INVALIDPARAMS;  /* Should never happen */
2101     };
2102
2103     return d3d_device3_BeginIndexed(&device->IDirect3DDevice3_iface,
2104             primitive_type, fvf, vertices, vertex_count, flags);
2105 }
2106
2107 /*****************************************************************************
2108  * IDirect3DDevice3::Vertex
2109  *
2110  * Draws a vertex as described by IDirect3DDevice3::Begin. It places all
2111  * drawn vertices in a vertex buffer. If the buffer is too small, its
2112  * size is increased.
2113  *
2114  * Version 2 and 3
2115  *
2116  * Params:
2117  *  Vertex: Pointer to the vertex
2118  *
2119  * Returns:
2120  *  D3D_OK, on success
2121  *  DDERR_INVALIDPARAMS if Vertex is NULL
2122  *
2123  *****************************************************************************/
2124 static HRESULT WINAPI d3d_device3_Vertex(IDirect3DDevice3 *iface, void *vertex)
2125 {
2126     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2127
2128     TRACE("iface %p, vertex %p.\n", iface, vertex);
2129
2130     if (!vertex)
2131         return DDERR_INVALIDPARAMS;
2132
2133     wined3d_mutex_lock();
2134     if ((device->nb_vertices + 1) * device->vertex_size > device->buffer_size)
2135     {
2136         BYTE *old_buffer;
2137
2138         device->buffer_size = device->buffer_size ? device->buffer_size * 2 : device->vertex_size * 3;
2139         old_buffer = device->sysmem_vertex_buffer;
2140         device->sysmem_vertex_buffer = HeapAlloc(GetProcessHeap(), 0, device->buffer_size);
2141         if (old_buffer)
2142         {
2143             memcpy(device->sysmem_vertex_buffer, old_buffer, device->nb_vertices * device->vertex_size);
2144             HeapFree(GetProcessHeap(), 0, old_buffer);
2145         }
2146     }
2147
2148     memcpy(device->sysmem_vertex_buffer + device->nb_vertices++ * device->vertex_size, vertex, device->vertex_size);
2149     wined3d_mutex_unlock();
2150
2151     return D3D_OK;
2152 }
2153
2154 static HRESULT WINAPI d3d_device2_Vertex(IDirect3DDevice2 *iface, void *vertex)
2155 {
2156     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2157
2158     TRACE("iface %p, vertex %p.\n", iface, vertex);
2159
2160     return d3d_device3_Vertex(&device->IDirect3DDevice3_iface, vertex);
2161 }
2162
2163 /*****************************************************************************
2164  * IDirect3DDevice3::Index
2165  *
2166  * Specifies an index to a vertex to be drawn. The vertex array has to
2167  * be specified with BeginIndexed first.
2168  *
2169  * Parameters:
2170  *  VertexIndex: The index of the vertex to draw
2171  *
2172  * Returns:
2173  *  D3D_OK because it's a stub
2174  *
2175  *****************************************************************************/
2176 static HRESULT WINAPI d3d_device3_Index(IDirect3DDevice3 *iface, WORD index)
2177 {
2178     FIXME("iface %p, index %#x stub!\n", iface, index);
2179
2180     return D3D_OK;
2181 }
2182
2183 static HRESULT WINAPI d3d_device2_Index(IDirect3DDevice2 *iface, WORD index)
2184 {
2185     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2186
2187     TRACE("iface %p, index %#x.\n", iface, index);
2188
2189     return d3d_device3_Index(&device->IDirect3DDevice3_iface, index);
2190 }
2191
2192 /*****************************************************************************
2193  * IDirect3DDevice3::End
2194  *
2195  * Ends a draw begun with IDirect3DDevice3::Begin or
2196  * IDirect3DDevice::BeginIndexed. The vertices specified with
2197  * IDirect3DDevice::Vertex or IDirect3DDevice::Index are drawn using
2198  * the IDirect3DDevice7::DrawPrimitive method. So far only
2199  * non-indexed mode is supported
2200  *
2201  * Version 2 and 3
2202  *
2203  * Params:
2204  *  Flags: Some flags, as usual. Don't know which are defined
2205  *
2206  * Returns:
2207  *  The return value of IDirect3DDevice7::DrawPrimitive
2208  *
2209  *****************************************************************************/
2210 static HRESULT WINAPI d3d_device3_End(IDirect3DDevice3 *iface, DWORD flags)
2211 {
2212     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2213
2214     TRACE("iface %p, flags %#x.\n", iface, flags);
2215
2216     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface, device->primitive_type,
2217             device->vertex_type, device->sysmem_vertex_buffer, device->nb_vertices, device->render_flags);
2218 }
2219
2220 static HRESULT WINAPI d3d_device2_End(IDirect3DDevice2 *iface, DWORD flags)
2221 {
2222     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2223
2224     TRACE("iface %p, flags %#x.\n", iface, flags);
2225
2226     return d3d_device3_End(&device->IDirect3DDevice3_iface, flags);
2227 }
2228
2229 /*****************************************************************************
2230  * IDirect3DDevice7::GetRenderState
2231  *
2232  * Returns the value of a render state. The possible render states are
2233  * defined in include/d3dtypes.h
2234  *
2235  * Version 2, 3 and 7
2236  *
2237  * Params:
2238  *  RenderStateType: Render state to return the current setting of
2239  *  Value: Address to store the value at
2240  *
2241  * Returns:
2242  *  D3D_OK on success, for details see IWineD3DDevice::GetRenderState
2243  *  DDERR_INVALIDPARAMS if Value == NULL
2244  *
2245  *****************************************************************************/
2246 static HRESULT d3d_device7_GetRenderState(IDirect3DDevice7 *iface,
2247         D3DRENDERSTATETYPE state, DWORD *value)
2248 {
2249     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2250     HRESULT hr = D3D_OK;
2251
2252     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2253
2254     if (!value)
2255         return DDERR_INVALIDPARAMS;
2256
2257     wined3d_mutex_lock();
2258     switch (state)
2259     {
2260         case D3DRENDERSTATE_TEXTUREMAG:
2261         {
2262             enum wined3d_texture_filter_type tex_mag;
2263
2264             tex_mag = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MAG_FILTER);
2265             switch (tex_mag)
2266             {
2267                 case WINED3D_TEXF_POINT:
2268                     *value = D3DFILTER_NEAREST;
2269                     break;
2270                 case WINED3D_TEXF_LINEAR:
2271                     *value = D3DFILTER_LINEAR;
2272                     break;
2273                 default:
2274                     ERR("Unhandled texture mag %d !\n",tex_mag);
2275                     *value = 0;
2276             }
2277             break;
2278         }
2279
2280         case D3DRENDERSTATE_TEXTUREMIN:
2281         {
2282             enum wined3d_texture_filter_type tex_min;
2283             enum wined3d_texture_filter_type tex_mip;
2284
2285             tex_min = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MIN_FILTER);
2286             tex_mip = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MIP_FILTER);
2287             switch (tex_min)
2288             {
2289                 case WINED3D_TEXF_POINT:
2290                     switch (tex_mip)
2291                     {
2292                         case WINED3D_TEXF_NONE:
2293                             *value = D3DFILTER_NEAREST;
2294                             break;
2295                         case WINED3D_TEXF_POINT:
2296                             *value = D3DFILTER_MIPNEAREST;
2297                             break;
2298                         case WINED3D_TEXF_LINEAR:
2299                             *value = D3DFILTER_LINEARMIPNEAREST;
2300                             break;
2301                         default:
2302                             ERR("Unhandled mip filter %#x.\n", tex_mip);
2303                             *value = D3DFILTER_NEAREST;
2304                             break;
2305                     }
2306                     break;
2307                 case WINED3D_TEXF_LINEAR:
2308                     switch (tex_mip)
2309                     {
2310                         case WINED3D_TEXF_NONE:
2311                             *value = D3DFILTER_LINEAR;
2312                             break;
2313                         case WINED3D_TEXF_POINT:
2314                             *value = D3DFILTER_MIPLINEAR;
2315                             break;
2316                         case WINED3D_TEXF_LINEAR:
2317                             *value = D3DFILTER_LINEARMIPLINEAR;
2318                             break;
2319                         default:
2320                             ERR("Unhandled mip filter %#x.\n", tex_mip);
2321                             *value = D3DFILTER_LINEAR;
2322                             break;
2323                     }
2324                     break;
2325                 default:
2326                     ERR("Unhandled texture min filter %#x.\n",tex_min);
2327                     *value = D3DFILTER_NEAREST;
2328                     break;
2329             }
2330             break;
2331         }
2332
2333         case D3DRENDERSTATE_TEXTUREADDRESS:
2334         case D3DRENDERSTATE_TEXTUREADDRESSU:
2335             *value = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_ADDRESS_U);
2336             break;
2337         case D3DRENDERSTATE_TEXTUREADDRESSV:
2338             *value = wined3d_device_get_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_ADDRESS_V);
2339             break;
2340
2341         case D3DRENDERSTATE_BORDERCOLOR:
2342             FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2343             hr = E_NOTIMPL;
2344             break;
2345
2346         case D3DRENDERSTATE_TEXTUREHANDLE:
2347         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2348             WARN("Render state %#x is invalid in d3d7.\n", state);
2349             hr = DDERR_INVALIDPARAMS;
2350             break;
2351
2352         case D3DRENDERSTATE_ZBIAS:
2353             *value = wined3d_device_get_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS);
2354             break;
2355
2356         default:
2357             if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2358                     && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2359             {
2360                 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2361                 hr = E_NOTIMPL;
2362                 break;
2363             }
2364             *value = wined3d_device_get_render_state(device->wined3d_device, state);
2365     }
2366     wined3d_mutex_unlock();
2367
2368     return hr;
2369 }
2370
2371 static HRESULT WINAPI d3d_device7_GetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2372         D3DRENDERSTATETYPE state, DWORD *value)
2373 {
2374     return d3d_device7_GetRenderState(iface, state, value);
2375 }
2376
2377 static HRESULT WINAPI d3d_device7_GetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2378         D3DRENDERSTATETYPE state, DWORD *value)
2379 {
2380     HRESULT hr;
2381     WORD old_fpucw;
2382
2383     old_fpucw = d3d_fpu_setup();
2384     hr = d3d_device7_GetRenderState(iface, state, value);
2385     set_fpu_control_word(old_fpucw);
2386
2387     return hr;
2388 }
2389
2390 static HRESULT WINAPI d3d_device3_GetRenderState(IDirect3DDevice3 *iface,
2391         D3DRENDERSTATETYPE state, DWORD *value)
2392 {
2393     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2394
2395     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2396
2397     switch (state)
2398     {
2399         case D3DRENDERSTATE_TEXTUREHANDLE:
2400         {
2401             /* This state is wrapped to SetTexture in SetRenderState, so
2402              * it has to be wrapped to GetTexture here. */
2403             struct wined3d_texture *tex = NULL;
2404             *value = 0;
2405
2406             wined3d_mutex_lock();
2407             if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2408             {
2409                 /* The parent of the texture is the IDirectDrawSurface7
2410                  * interface of the ddraw surface. */
2411                 struct ddraw_surface *parent = wined3d_texture_get_parent(tex);
2412                 if (parent)
2413                     *value = parent->Handle;
2414             }
2415             wined3d_mutex_unlock();
2416
2417             return D3D_OK;
2418         }
2419
2420         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2421         {
2422             /* D3DRENDERSTATE_TEXTUREMAPBLEND is mapped to texture state stages in SetRenderState; reverse
2423                the mapping to get the value. */
2424             DWORD colorop, colorarg1, colorarg2;
2425             DWORD alphaop, alphaarg1, alphaarg2;
2426
2427             wined3d_mutex_lock();
2428
2429             device->legacyTextureBlending = TRUE;
2430
2431             colorop = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_OP);
2432             colorarg1 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG1);
2433             colorarg2 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG2);
2434             alphaop = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_OP);
2435             alphaarg1 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG1);
2436             alphaarg2 = wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG2);
2437
2438             if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
2439                     && alphaop == WINED3D_TOP_SELECT_ARG1 && alphaarg1 == WINED3DTA_TEXTURE)
2440                 *value = D3DTBLEND_DECAL;
2441             else if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
2442                     && alphaop == WINED3D_TOP_MODULATE
2443                     && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2444                 *value = D3DTBLEND_DECALALPHA;
2445             else if (colorop == WINED3D_TOP_MODULATE
2446                     && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
2447                     && alphaop == WINED3D_TOP_MODULATE
2448                     && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2449                 *value = D3DTBLEND_MODULATEALPHA;
2450             else
2451             {
2452                 struct wined3d_texture *tex = NULL;
2453                 BOOL tex_alpha = FALSE;
2454                 DDPIXELFORMAT ddfmt;
2455
2456                 if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2457                 {
2458                     struct wined3d_resource *sub_resource;
2459
2460                     if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2461                     {
2462                         struct wined3d_resource_desc desc;
2463
2464                         wined3d_resource_get_desc(sub_resource, &desc);
2465                         ddfmt.dwSize = sizeof(ddfmt);
2466                         PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2467                         if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2468                     }
2469                 }
2470
2471                 if (!(colorop == WINED3D_TOP_MODULATE
2472                         && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
2473                         && alphaop == (tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2)
2474                         && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT))
2475                     ERR("Unexpected texture stage state setup, returning D3DTBLEND_MODULATE - likely erroneous.\n");
2476
2477                 *value = D3DTBLEND_MODULATE;
2478             }
2479
2480             wined3d_mutex_unlock();
2481
2482             return D3D_OK;
2483         }
2484
2485         default:
2486             return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2487     }
2488 }
2489
2490 static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
2491         D3DRENDERSTATETYPE state, DWORD *value)
2492 {
2493     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2494
2495     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2496
2497     return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2498 }
2499
2500 /*****************************************************************************
2501  * IDirect3DDevice7::SetRenderState
2502  *
2503  * Sets a render state. The possible render states are defined in
2504  * include/d3dtypes.h
2505  *
2506  * Version 2, 3 and 7
2507  *
2508  * Params:
2509  *  RenderStateType: State to set
2510  *  Value: Value to assign to that state
2511  *
2512  * Returns:
2513  *  D3D_OK on success,
2514  *  for details see IWineD3DDevice::SetRenderState
2515  *
2516  *****************************************************************************/
2517 static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
2518         D3DRENDERSTATETYPE state, DWORD value)
2519 {
2520     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2521     HRESULT hr = D3D_OK;
2522
2523     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2524
2525     wined3d_mutex_lock();
2526     /* Some render states need special care */
2527     switch (state)
2528     {
2529         /*
2530          * The ddraw texture filter mapping works like this:
2531          *     D3DFILTER_NEAREST            Point min/mag, no mip
2532          *     D3DFILTER_MIPNEAREST         Point min/mag, point mip
2533          *     D3DFILTER_LINEARMIPNEAREST:  Point min/mag, linear mip
2534          *
2535          *     D3DFILTER_LINEAR             Linear min/mag, no mip
2536          *     D3DFILTER_MIPLINEAR          Linear min/mag, point mip
2537          *     D3DFILTER_LINEARMIPLINEAR    Linear min/mag, linear mip
2538          *
2539          * This is the opposite of the GL naming convention,
2540          * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2541          */
2542         case D3DRENDERSTATE_TEXTUREMAG:
2543         {
2544             enum wined3d_texture_filter_type tex_mag;
2545
2546             switch (value)
2547             {
2548                 case D3DFILTER_NEAREST:
2549                 case D3DFILTER_MIPNEAREST:
2550                 case D3DFILTER_LINEARMIPNEAREST:
2551                     tex_mag = WINED3D_TEXF_POINT;
2552                     break;
2553                 case D3DFILTER_LINEAR:
2554                 case D3DFILTER_MIPLINEAR:
2555                 case D3DFILTER_LINEARMIPLINEAR:
2556                     tex_mag = WINED3D_TEXF_LINEAR;
2557                     break;
2558                 default:
2559                     tex_mag = WINED3D_TEXF_POINT;
2560                     FIXME("Unhandled texture mag %#x.\n", value);
2561                     break;
2562             }
2563
2564             wined3d_device_set_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2565             break;
2566         }
2567
2568         case D3DRENDERSTATE_TEXTUREMIN:
2569         {
2570             enum wined3d_texture_filter_type tex_min;
2571             enum wined3d_texture_filter_type tex_mip;
2572
2573             switch (value)
2574             {
2575                 case D3DFILTER_NEAREST:
2576                     tex_min = WINED3D_TEXF_POINT;
2577                     tex_mip = WINED3D_TEXF_NONE;
2578                     break;
2579                 case D3DFILTER_LINEAR:
2580                     tex_min = WINED3D_TEXF_LINEAR;
2581                     tex_mip = WINED3D_TEXF_NONE;
2582                     break;
2583                 case D3DFILTER_MIPNEAREST:
2584                     tex_min = WINED3D_TEXF_POINT;
2585                     tex_mip = WINED3D_TEXF_POINT;
2586                     break;
2587                 case D3DFILTER_MIPLINEAR:
2588                     tex_min = WINED3D_TEXF_LINEAR;
2589                     tex_mip = WINED3D_TEXF_POINT;
2590                     break;
2591                 case D3DFILTER_LINEARMIPNEAREST:
2592                     tex_min = WINED3D_TEXF_POINT;
2593                     tex_mip = WINED3D_TEXF_LINEAR;
2594                     break;
2595                 case D3DFILTER_LINEARMIPLINEAR:
2596                     tex_min = WINED3D_TEXF_LINEAR;
2597                     tex_mip = WINED3D_TEXF_LINEAR;
2598                     break;
2599
2600                 default:
2601                     FIXME("Unhandled texture min %#x.\n",value);
2602                     tex_min = WINED3D_TEXF_POINT;
2603                     tex_mip = WINED3D_TEXF_NONE;
2604                     break;
2605             }
2606
2607             wined3d_device_set_sampler_state(device->wined3d_device,
2608                     0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2609             wined3d_device_set_sampler_state(device->wined3d_device,
2610                     0, WINED3D_SAMP_MIN_FILTER, tex_min);
2611             break;
2612         }
2613
2614         case D3DRENDERSTATE_TEXTUREADDRESS:
2615             wined3d_device_set_sampler_state(device->wined3d_device,
2616                     0, WINED3D_SAMP_ADDRESS_V, value);
2617             /* Drop through */
2618         case D3DRENDERSTATE_TEXTUREADDRESSU:
2619             wined3d_device_set_sampler_state(device->wined3d_device,
2620                     0, WINED3D_SAMP_ADDRESS_U, value);
2621             break;
2622         case D3DRENDERSTATE_TEXTUREADDRESSV:
2623             wined3d_device_set_sampler_state(device->wined3d_device,
2624                     0, WINED3D_SAMP_ADDRESS_V, value);
2625             break;
2626
2627         case D3DRENDERSTATE_BORDERCOLOR:
2628             /* This should probably just forward to the corresponding sampler
2629              * state. Needs tests. */
2630             FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2631             hr = E_NOTIMPL;
2632             break;
2633
2634         case D3DRENDERSTATE_TEXTUREHANDLE:
2635         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2636             WARN("Render state %#x is invalid in d3d7.\n", state);
2637             hr = DDERR_INVALIDPARAMS;
2638             break;
2639
2640         case D3DRENDERSTATE_ZBIAS:
2641             wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
2642             break;
2643
2644         default:
2645             if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2646                     && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2647             {
2648                 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2649                 hr = E_NOTIMPL;
2650                 break;
2651             }
2652
2653             wined3d_device_set_render_state(device->wined3d_device, state, value);
2654             break;
2655     }
2656     wined3d_mutex_unlock();
2657
2658     return hr;
2659 }
2660
2661 static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2662         D3DRENDERSTATETYPE state, DWORD value)
2663 {
2664     return d3d_device7_SetRenderState(iface, state, value);
2665 }
2666
2667 static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2668         D3DRENDERSTATETYPE state, DWORD value)
2669 {
2670     HRESULT hr;
2671     WORD old_fpucw;
2672
2673     old_fpucw = d3d_fpu_setup();
2674     hr = d3d_device7_SetRenderState(iface, state, value);
2675     set_fpu_control_word(old_fpucw);
2676
2677     return hr;
2678 }
2679
2680 static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
2681         D3DRENDERSTATETYPE state, DWORD value)
2682 {
2683     /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2684     for this state can be directly mapped to texture stage colorop and alphaop, but
2685     D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2686     from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2687     alphaarg when needed.
2688
2689     Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2690
2691     Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2692     TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2693     are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2694     requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2695     with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2696     in device - TRUE if the app is using TEXTUREMAPBLEND.
2697
2698     Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2699     GetTextureStageState and vice versa. Not so on Wine, but it is 'undefined' anyway so, probably, ok,
2700     unless some broken game will be found that cares. */
2701
2702     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2703     HRESULT hr;
2704
2705     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2706
2707     wined3d_mutex_lock();
2708
2709     switch (state)
2710     {
2711         case D3DRENDERSTATE_TEXTUREHANDLE:
2712         {
2713             struct ddraw_surface *surf;
2714
2715             if (value == 0)
2716             {
2717                 hr = wined3d_device_set_texture(device->wined3d_device, 0, NULL);
2718                 break;
2719             }
2720
2721             surf = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_SURFACE);
2722             if (!surf)
2723             {
2724                 WARN("Invalid texture handle.\n");
2725                 hr = DDERR_INVALIDPARAMS;
2726                 break;
2727             }
2728
2729             hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2730             break;
2731         }
2732
2733         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2734         {
2735             device->legacyTextureBlending = TRUE;
2736
2737             switch (value)
2738             {
2739                 case D3DTBLEND_MODULATE:
2740                 {
2741                     struct wined3d_texture *tex = NULL;
2742                     BOOL tex_alpha = FALSE;
2743                     DDPIXELFORMAT ddfmt;
2744
2745                     if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
2746                     {
2747                         struct wined3d_resource *sub_resource;
2748
2749                         if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2750                         {
2751                             struct wined3d_resource_desc desc;
2752
2753                             wined3d_resource_get_desc(sub_resource, &desc);
2754                             ddfmt.dwSize = sizeof(ddfmt);
2755                             PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2756                             if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2757                         }
2758                     }
2759
2760                     if (tex_alpha)
2761                         wined3d_device_set_texture_stage_state(device->wined3d_device,
2762                                 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2763                     else
2764                         wined3d_device_set_texture_stage_state(device->wined3d_device,
2765                                 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2766                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2767                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2768                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2769                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2770                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2771                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2772                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2773                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2774                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2775                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2776                     break;
2777                 }
2778
2779                 case D3DTBLEND_ADD:
2780                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2781                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2782                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2783                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2784                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2785                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2786                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2787                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2788                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2789                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2790                     break;
2791
2792                 case D3DTBLEND_MODULATEALPHA:
2793                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2794                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2795                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2796                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2797                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2798                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2799                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2800                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2801                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2802                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2803                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2804                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2805                     break;
2806
2807                 case D3DTBLEND_COPY:
2808                 case D3DTBLEND_DECAL:
2809                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2810                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2811                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2812                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2813                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2814                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2815                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2816                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2817                     break;
2818
2819                 case D3DTBLEND_DECALALPHA:
2820                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2821                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2822                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2823                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2824                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2825                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2826                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2827                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2828                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2829                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2830                     break;
2831
2832                 default:
2833                     FIXME("Unhandled texture environment %#x.\n", value);
2834             }
2835
2836             hr = D3D_OK;
2837             break;
2838         }
2839
2840         default:
2841             hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2842             break;
2843     }
2844     wined3d_mutex_unlock();
2845
2846     return hr;
2847 }
2848
2849 static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
2850         D3DRENDERSTATETYPE state, DWORD value)
2851 {
2852     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2853
2854     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2855
2856     return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2857 }
2858
2859 /*****************************************************************************
2860  * Direct3DDevice3::SetLightState
2861  *
2862  * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2863  * light states are forwarded to Direct3DDevice7 render states
2864  *
2865  * Version 2 and 3
2866  *
2867  * Params:
2868  *  LightStateType: The light state to change
2869  *  Value: The value to assign to that light state
2870  *
2871  * Returns:
2872  *  D3D_OK on success
2873  *  DDERR_INVALIDPARAMS if the parameters were incorrect
2874  *  Also check IDirect3DDevice7::SetRenderState
2875  *
2876  *****************************************************************************/
2877 static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
2878         D3DLIGHTSTATETYPE state, DWORD value)
2879 {
2880     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2881     HRESULT hr;
2882
2883     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2884
2885     if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2886     {
2887         TRACE("Unexpected Light State Type\n");
2888         return DDERR_INVALIDPARAMS;
2889     }
2890
2891     wined3d_mutex_lock();
2892     if (state == D3DLIGHTSTATE_MATERIAL)
2893     {
2894         struct d3d_material *m = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_MATERIAL);
2895         if (!m)
2896         {
2897             WARN("Invalid material handle.\n");
2898             wined3d_mutex_unlock();
2899             return DDERR_INVALIDPARAMS;
2900         }
2901
2902         TRACE(" activating material %p.\n", m);
2903         material_activate(m);
2904
2905         device->material = value;
2906     }
2907     else if (state == D3DLIGHTSTATE_COLORMODEL)
2908     {
2909         switch (value)
2910         {
2911             case D3DCOLOR_MONO:
2912                 ERR("DDCOLOR_MONO should not happen!\n");
2913                 break;
2914             case D3DCOLOR_RGB:
2915                 /* We are already in this mode */
2916                 TRACE("Setting color model to RGB (no-op).\n");
2917                 break;
2918             default:
2919                 ERR("Unknown color model!\n");
2920                 wined3d_mutex_unlock();
2921                 return DDERR_INVALIDPARAMS;
2922         }
2923     }
2924     else
2925     {
2926         D3DRENDERSTATETYPE rs;
2927         switch (state)
2928         {
2929             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
2930                 rs = D3DRENDERSTATE_AMBIENT;
2931                 break;
2932             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
2933                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2934                 break;
2935             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
2936                 rs = D3DRENDERSTATE_FOGSTART;
2937                 break;
2938             case D3DLIGHTSTATE_FOGEND:        /* 6 */
2939                 rs = D3DRENDERSTATE_FOGEND;
2940                 break;
2941             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
2942                 rs = D3DRENDERSTATE_FOGDENSITY;
2943                 break;
2944             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
2945                 rs = D3DRENDERSTATE_COLORVERTEX;
2946                 break;
2947             default:
2948                 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2949                 wined3d_mutex_unlock();
2950                 return DDERR_INVALIDPARAMS;
2951         }
2952
2953         hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
2954         wined3d_mutex_unlock();
2955         return hr;
2956     }
2957     wined3d_mutex_unlock();
2958
2959     return D3D_OK;
2960 }
2961
2962 static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
2963         D3DLIGHTSTATETYPE state, DWORD value)
2964 {
2965     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2966
2967     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2968
2969     return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
2970 }
2971
2972 /*****************************************************************************
2973  * IDirect3DDevice3::GetLightState
2974  *
2975  * Returns the current setting of a light state. The state is read from
2976  * the Direct3DDevice7 render state.
2977  *
2978  * Version 2 and 3
2979  *
2980  * Params:
2981  *  LightStateType: The light state to return
2982  *  Value: The address to store the light state setting at
2983  *
2984  * Returns:
2985  *  D3D_OK on success
2986  *  DDDERR_INVALIDPARAMS if the parameters were incorrect
2987  *  Also see IDirect3DDevice7::GetRenderState
2988  *
2989  *****************************************************************************/
2990 static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
2991         D3DLIGHTSTATETYPE state, DWORD *value)
2992 {
2993     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2994     HRESULT hr;
2995
2996     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2997
2998     if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2999     {
3000         TRACE("Unexpected Light State Type\n");
3001         return DDERR_INVALIDPARAMS;
3002     }
3003
3004     if (!value)
3005         return DDERR_INVALIDPARAMS;
3006
3007     wined3d_mutex_lock();
3008     if (state == D3DLIGHTSTATE_MATERIAL)
3009     {
3010         *value = device->material;
3011     }
3012     else if (state == D3DLIGHTSTATE_COLORMODEL)
3013     {
3014         *value = D3DCOLOR_RGB;
3015     }
3016     else
3017     {
3018         D3DRENDERSTATETYPE rs;
3019         switch (state)
3020         {
3021             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
3022                 rs = D3DRENDERSTATE_AMBIENT;
3023                 break;
3024             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
3025                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3026                 break;
3027             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
3028                 rs = D3DRENDERSTATE_FOGSTART;
3029                 break;
3030             case D3DLIGHTSTATE_FOGEND:        /* 6 */
3031                 rs = D3DRENDERSTATE_FOGEND;
3032                 break;
3033             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
3034                 rs = D3DRENDERSTATE_FOGDENSITY;
3035                 break;
3036             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
3037                 rs = D3DRENDERSTATE_COLORVERTEX;
3038                 break;
3039             default:
3040                 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3041                 wined3d_mutex_unlock();
3042                 return DDERR_INVALIDPARAMS;
3043         }
3044
3045         hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3046         wined3d_mutex_unlock();
3047         return hr;
3048     }
3049     wined3d_mutex_unlock();
3050
3051     return D3D_OK;
3052 }
3053
3054 static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
3055         D3DLIGHTSTATETYPE state, DWORD *value)
3056 {
3057     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3058
3059     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3060
3061     return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3062 }
3063
3064 /*****************************************************************************
3065  * IDirect3DDevice7::SetTransform
3066  *
3067  * Assigns a D3DMATRIX to a transform type. The transform types are defined
3068  * in include/d3dtypes.h.
3069  * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3070  * (=255) for wined3d, because the 1 transform state was removed in d3d8
3071  * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3072  *
3073  * Version 2, 3 and 7
3074  *
3075  * Params:
3076  *  TransformStateType: transform state to set
3077  *  Matrix: Matrix to assign to the state
3078  *
3079  * Returns:
3080  *  D3D_OK on success
3081  *  DDERR_INVALIDPARAMS if Matrix == NULL
3082  *  For details see IWineD3DDevice::SetTransform
3083  *
3084  *****************************************************************************/
3085 static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
3086         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3087 {
3088     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3089     enum wined3d_transform_state wined3d_state;
3090
3091     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3092
3093     switch (state)
3094     {
3095         case D3DTRANSFORMSTATE_WORLD:
3096             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3097             break;
3098         case D3DTRANSFORMSTATE_WORLD1:
3099             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3100             break;
3101         case D3DTRANSFORMSTATE_WORLD2:
3102             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3103             break;
3104         case D3DTRANSFORMSTATE_WORLD3:
3105             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3106             break;
3107         default:
3108             wined3d_state = state;
3109     }
3110
3111     if (!matrix)
3112         return DDERR_INVALIDPARAMS;
3113
3114     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3115     wined3d_mutex_lock();
3116     wined3d_device_set_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3117     wined3d_mutex_unlock();
3118
3119     return D3D_OK;
3120 }
3121
3122 static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3123         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3124 {
3125     return d3d_device7_SetTransform(iface, state, matrix);
3126 }
3127
3128 static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3129         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3130 {
3131     HRESULT hr;
3132     WORD old_fpucw;
3133
3134     old_fpucw = d3d_fpu_setup();
3135     hr = d3d_device7_SetTransform(iface, state, matrix);
3136     set_fpu_control_word(old_fpucw);
3137
3138     return hr;
3139 }
3140
3141 static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3142         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3143 {
3144     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3145
3146     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3147
3148     if (!matrix)
3149         return DDERR_INVALIDPARAMS;
3150
3151     if (state == D3DTRANSFORMSTATE_PROJECTION)
3152     {
3153         D3DMATRIX projection;
3154
3155         wined3d_mutex_lock();
3156         multiply_matrix(&projection, &device->legacy_clipspace, matrix);
3157         wined3d_device_set_transform(device->wined3d_device,
3158                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3159         device->legacy_projection = *matrix;
3160         wined3d_mutex_unlock();
3161
3162         return D3D_OK;
3163     }
3164
3165     return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3166 }
3167
3168 static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
3169         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3170 {
3171     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3172
3173     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3174
3175     return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3176 }
3177
3178 /*****************************************************************************
3179  * IDirect3DDevice7::GetTransform
3180  *
3181  * Returns the matrix assigned to a transform state
3182  * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3183  * SetTransform
3184  *
3185  * Params:
3186  *  TransformStateType: State to read the matrix from
3187  *  Matrix: Address to store the matrix at
3188  *
3189  * Returns:
3190  *  D3D_OK on success
3191  *  DDERR_INVALIDPARAMS if Matrix == NULL
3192  *  For details, see IWineD3DDevice::GetTransform
3193  *
3194  *****************************************************************************/
3195 static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
3196         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3197 {
3198     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3199     enum wined3d_transform_state wined3d_state;
3200
3201     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3202
3203     switch (state)
3204     {
3205         case D3DTRANSFORMSTATE_WORLD:
3206             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3207             break;
3208         case D3DTRANSFORMSTATE_WORLD1:
3209             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3210             break;
3211         case D3DTRANSFORMSTATE_WORLD2:
3212             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3213             break;
3214         case D3DTRANSFORMSTATE_WORLD3:
3215             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3216             break;
3217         default:
3218             wined3d_state = state;
3219     }
3220
3221     if (!matrix)
3222         return DDERR_INVALIDPARAMS;
3223
3224     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3225     wined3d_mutex_lock();
3226     wined3d_device_get_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3227     wined3d_mutex_unlock();
3228
3229     return D3D_OK;
3230 }
3231
3232 static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3233         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3234 {
3235     return d3d_device7_GetTransform(iface, state, matrix);
3236 }
3237
3238 static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3239         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3240 {
3241     HRESULT hr;
3242     WORD old_fpucw;
3243
3244     old_fpucw = d3d_fpu_setup();
3245     hr = d3d_device7_GetTransform(iface, state, matrix);
3246     set_fpu_control_word(old_fpucw);
3247
3248     return hr;
3249 }
3250
3251 static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3252         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3253 {
3254     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3255
3256     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3257
3258     if (!matrix)
3259         return DDERR_INVALIDPARAMS;
3260
3261     if (state == D3DTRANSFORMSTATE_PROJECTION)
3262     {
3263         wined3d_mutex_lock();
3264         *matrix = device->legacy_projection;
3265         wined3d_mutex_unlock();
3266         return DD_OK;
3267     }
3268
3269     return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3270 }
3271
3272 static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
3273         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3274 {
3275     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3276
3277     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3278
3279     return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3280 }
3281
3282 /*****************************************************************************
3283  * IDirect3DDevice7::MultiplyTransform
3284  *
3285  * Multiplies the already-set transform matrix of a transform state
3286  * with another matrix. For the world matrix, see SetTransform
3287  *
3288  * Version 2, 3 and 7
3289  *
3290  * Params:
3291  *  TransformStateType: Transform state to multiply
3292  *  D3DMatrix Matrix to multiply with.
3293  *
3294  * Returns
3295  *  D3D_OK on success
3296  *  DDERR_INVALIDPARAMS if D3DMatrix is NULL
3297  *  For details, see IWineD3DDevice::MultiplyTransform
3298  *
3299  *****************************************************************************/
3300 static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
3301         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3302 {
3303     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3304     enum wined3d_transform_state wined3d_state;
3305
3306     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3307
3308     switch (state)
3309     {
3310         case D3DTRANSFORMSTATE_WORLD:
3311             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3312             break;
3313         case D3DTRANSFORMSTATE_WORLD1:
3314             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3315             break;
3316         case D3DTRANSFORMSTATE_WORLD2:
3317             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3318             break;
3319         case D3DTRANSFORMSTATE_WORLD3:
3320             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3321             break;
3322         default:
3323             wined3d_state = state;
3324     }
3325
3326     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3327     wined3d_mutex_lock();
3328     wined3d_device_multiply_transform(device->wined3d_device,
3329             wined3d_state, (struct wined3d_matrix *)matrix);
3330     wined3d_mutex_unlock();
3331
3332     return D3D_OK;
3333 }
3334
3335 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3336         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3337 {
3338     return d3d_device7_MultiplyTransform(iface, state, matrix);
3339 }
3340
3341 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3342         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3343 {
3344     HRESULT hr;
3345     WORD old_fpucw;
3346
3347     old_fpucw = d3d_fpu_setup();
3348     hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3349     set_fpu_control_word(old_fpucw);
3350
3351     return hr;
3352 }
3353
3354 static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3355         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3356 {
3357     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3358
3359     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3360
3361     if (state == D3DTRANSFORMSTATE_PROJECTION)
3362     {
3363         D3DMATRIX projection, tmp;
3364
3365         wined3d_mutex_lock();
3366         multiply_matrix(&tmp, &device->legacy_projection, matrix);
3367         multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3368         wined3d_device_set_transform(device->wined3d_device,
3369                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3370         device->legacy_projection = tmp;
3371         wined3d_mutex_unlock();
3372
3373         return D3D_OK;
3374     }
3375
3376     return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3377 }
3378
3379 static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
3380         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3381 {
3382     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3383
3384     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3385
3386     return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3387 }
3388
3389 /*****************************************************************************
3390  * IDirect3DDevice7::DrawPrimitive
3391  *
3392  * Draws primitives based on vertices in an application-provided pointer
3393  *
3394  * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3395  * an FVF format for D3D7
3396  *
3397  * Params:
3398  *  PrimitiveType: The type of the primitives to draw
3399  *  Vertex type: Flexible vertex format vertex description
3400  *  Vertices: Pointer to the vertex array
3401  *  VertexCount: The number of vertices to draw
3402  *  Flags: As usual a few flags
3403  *
3404  * Returns:
3405  *  D3D_OK on success
3406  *  DDERR_INVALIDPARAMS if Vertices is NULL
3407  *  For details, see IWineD3DDevice::DrawPrimitiveUP
3408  *
3409  *****************************************************************************/
3410
3411 /* The caller is responsible for wined3d locking */
3412 static HRESULT d3d_device_prepare_vertex_buffer(struct d3d_device *device, UINT min_size)
3413 {
3414     HRESULT hr;
3415
3416     if (device->vertex_buffer_size < min_size || !device->vertex_buffer)
3417     {
3418         UINT size = max(device->vertex_buffer_size * 2, min_size);
3419         struct wined3d_buffer *buffer;
3420
3421         TRACE("Growing vertex buffer to %u bytes\n", size);
3422
3423         hr = wined3d_buffer_create_vb(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
3424                 WINED3D_POOL_DEFAULT, NULL, &ddraw_null_wined3d_parent_ops, &buffer);
3425         if (FAILED(hr))
3426         {
3427             ERR("(%p) wined3d_buffer_create_vb failed with hr = %08x\n", device, hr);
3428             return hr;
3429         }
3430
3431         if (device->vertex_buffer)
3432             wined3d_buffer_decref(device->vertex_buffer);
3433
3434         device->vertex_buffer = buffer;
3435         device->vertex_buffer_size = size;
3436         device->vertex_buffer_pos = 0;
3437     }
3438     return D3D_OK;
3439 }
3440
3441 static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
3442         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3443         DWORD vertex_count, DWORD flags)
3444 {
3445     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3446     UINT stride, vb_pos, size, align;
3447     HRESULT hr;
3448     BYTE *data;
3449
3450     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3451             iface, primitive_type, fvf, vertices, vertex_count, flags);
3452
3453     if (!vertices)
3454         return DDERR_INVALIDPARAMS;
3455
3456     /* Get the stride */
3457     stride = get_flexible_vertex_size(fvf);
3458     size = vertex_count * stride;
3459
3460     wined3d_mutex_lock();
3461     hr = d3d_device_prepare_vertex_buffer(device, size);
3462     if (FAILED(hr))
3463         goto done;
3464
3465     vb_pos = device->vertex_buffer_pos;
3466     align = vb_pos % stride;
3467     if (align) align = stride - align;
3468     if (vb_pos + size + align > device->vertex_buffer_size)
3469         vb_pos = 0;
3470     else
3471         vb_pos += align;
3472
3473     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, size, &data,
3474             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
3475     if (FAILED(hr))
3476         goto done;
3477     memcpy(data, vertices, size);
3478     wined3d_buffer_unmap(device->vertex_buffer);
3479     device->vertex_buffer_pos = vb_pos + size;
3480
3481     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
3482     if (FAILED(hr))
3483         goto done;
3484
3485     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3486     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
3487     hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / stride, vertex_count);
3488
3489 done:
3490     wined3d_mutex_unlock();
3491     return hr;
3492 }
3493
3494 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3495         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3496         DWORD vertex_count, DWORD flags)
3497 {
3498     return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3499 }
3500
3501 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3502         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3503         DWORD vertex_count, DWORD flags)
3504 {
3505     HRESULT hr;
3506     WORD old_fpucw;
3507
3508     old_fpucw = d3d_fpu_setup();
3509     hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3510     set_fpu_control_word(old_fpucw);
3511
3512     return hr;
3513 }
3514
3515 static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
3516         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3517         DWORD flags)
3518 {
3519     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3520
3521     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3522             iface, primitive_type, fvf, vertices, vertex_count, flags);
3523
3524     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3525             primitive_type, fvf, vertices, vertex_count, flags);
3526 }
3527
3528 static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
3529         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3530         DWORD vertex_count, DWORD flags)
3531 {
3532     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3533     DWORD fvf;
3534
3535     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3536             iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3537
3538     switch (vertex_type)
3539     {
3540         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3541         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3542         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3543         default:
3544             FIXME("Unhandled vertex type %#x.\n", vertex_type);
3545             return DDERR_INVALIDPARAMS;  /* Should never happen */
3546     }
3547
3548     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3549             primitive_type, fvf, vertices, vertex_count, flags);
3550 }
3551
3552 /*****************************************************************************
3553  * IDirect3DDevice7::DrawIndexedPrimitive
3554  *
3555  * Draws vertices from an application-provided pointer, based on the index
3556  * numbers in a WORD array.
3557  *
3558  * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3559  * an FVF format for D3D7
3560  *
3561  * Params:
3562  *  PrimitiveType: The primitive type to draw
3563  *  VertexType: The FVF vertex description
3564  *  Vertices: Pointer to the vertex array
3565  *  VertexCount: ?
3566  *  Indices: Pointer to the index array
3567  *  IndexCount: Number of indices = Number of vertices to draw
3568  *  Flags: As usual, some flags
3569  *
3570  * Returns:
3571  *  D3D_OK on success
3572  *  DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3573  *  For details, see IWineD3DDevice::DrawIndexedPrimitiveUP
3574  *
3575  *****************************************************************************/
3576 /* The caller is responsible for wined3d locking */
3577 static HRESULT d3d_device_prepare_index_buffer(struct d3d_device *device, UINT min_size)
3578 {
3579     HRESULT hr;
3580
3581     if (device->index_buffer_size < min_size || !device->index_buffer)
3582     {
3583         UINT size = max(device->index_buffer_size * 2, min_size);
3584         struct wined3d_buffer *buffer;
3585
3586         TRACE("Growing index buffer to %u bytes\n", size);
3587
3588         hr = wined3d_buffer_create_ib(device->wined3d_device, size, WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_WRITEONLY,
3589                 WINED3D_POOL_DEFAULT, NULL, &ddraw_null_wined3d_parent_ops, &buffer);
3590         if (FAILED(hr))
3591         {
3592             ERR("(%p) wined3d_buffer_create_ib failed with hr = %08x\n", device, hr);
3593             return hr;
3594         }
3595
3596         if (device->index_buffer)
3597             wined3d_buffer_decref(device->index_buffer);
3598         device->index_buffer = buffer;
3599         device->index_buffer_size = size;
3600         device->index_buffer_pos = 0;
3601     }
3602     return D3D_OK;
3603 }
3604
3605 static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3606         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3607         WORD *indices, DWORD index_count, DWORD flags)
3608 {
3609     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3610     HRESULT hr;
3611     UINT stride = get_flexible_vertex_size(fvf);
3612     UINT vtx_size = stride * vertex_count, idx_size = index_count * sizeof(*indices);
3613     UINT vb_pos, ib_pos, align;
3614     BYTE *data;
3615
3616     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3617             "indices %p, index_count %u, flags %#x.\n",
3618             iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3619
3620     /* Set the D3DDevice's FVF */
3621     wined3d_mutex_lock();
3622
3623     hr = d3d_device_prepare_vertex_buffer(device, vtx_size);
3624     if (FAILED(hr))
3625         goto done;
3626
3627     vb_pos = device->vertex_buffer_pos;
3628     align = vb_pos % stride;
3629     if (align) align = stride - align;
3630     if (vb_pos + vtx_size + align > device->vertex_buffer_size)
3631         vb_pos = 0;
3632     else
3633         vb_pos += align;
3634
3635     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, vtx_size, &data,
3636             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
3637     if (FAILED(hr))
3638         goto done;
3639     memcpy(data, vertices, vtx_size);
3640     wined3d_buffer_unmap(device->vertex_buffer);
3641     device->vertex_buffer_pos = vb_pos + vtx_size;
3642
3643     hr = d3d_device_prepare_index_buffer(device, idx_size);
3644     if (FAILED(hr))
3645         goto done;
3646     ib_pos = device->index_buffer_pos;
3647     if (device->index_buffer_size - idx_size < ib_pos)
3648         ib_pos = 0;
3649
3650     hr = wined3d_buffer_map(device->index_buffer, ib_pos, idx_size, &data,
3651             ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
3652     if (FAILED(hr))
3653         goto done;
3654     memcpy(data, indices, idx_size);
3655     wined3d_buffer_unmap(device->index_buffer);
3656     device->index_buffer_pos = ib_pos + idx_size;
3657
3658     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, stride);
3659     if (FAILED(hr))
3660         goto done;
3661     wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer, WINED3DFMT_R16_UINT);
3662
3663     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3664     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
3665     wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / stride);
3666     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / sizeof(*indices), index_count);
3667
3668 done:
3669     wined3d_mutex_unlock();
3670     return hr;
3671 }
3672
3673 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3674         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3675         WORD *indices, DWORD index_count, DWORD flags)
3676 {
3677     return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3678             vertices, vertex_count, indices, index_count, flags);
3679 }
3680
3681 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3682         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3683         WORD *indices, DWORD index_count, DWORD flags)
3684 {
3685     HRESULT hr;
3686     WORD old_fpucw;
3687
3688     old_fpucw = d3d_fpu_setup();
3689     hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3690             vertices, vertex_count, indices, index_count, flags);
3691     set_fpu_control_word(old_fpucw);
3692
3693     return hr;
3694 }
3695
3696 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3697         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3698         WORD *indices, DWORD index_count, DWORD flags)
3699 {
3700     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3701
3702     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3703             "indices %p, index_count %u, flags %#x.\n",
3704             iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3705
3706     return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3707             primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3708 }
3709
3710 static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3711         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3712         DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3713 {
3714     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3715     DWORD fvf;
3716
3717     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, "
3718             "indices %p, index_count %u, flags %#x.\n",
3719             iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3720
3721     switch (vertex_type)
3722     {
3723         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3724         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3725         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3726         default:
3727             ERR("Unhandled vertex type %#x.\n", vertex_type);
3728             return DDERR_INVALIDPARAMS;  /* Should never happen */
3729     }
3730
3731     return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3732             primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3733 }
3734
3735 /*****************************************************************************
3736  * IDirect3DDevice7::SetClipStatus
3737  *
3738  * Sets the clip status. This defines things as clipping conditions and
3739  * the extents of the clipping region.
3740  *
3741  * Version 2, 3 and 7
3742  *
3743  * Params:
3744  *  ClipStatus:
3745  *
3746  * Returns:
3747  *  D3D_OK because it's a stub
3748  *  (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3749  *
3750  *****************************************************************************/
3751 static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3752 {
3753     FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3754
3755     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them
3756      * Perhaps this needs a new data type and an additional IWineD3DDevice method
3757      */
3758     /* return IWineD3DDevice_SetClipStatus(This->wineD3DDevice, ClipStatus);*/
3759     return D3D_OK;
3760 }
3761
3762 static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3763 {
3764     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3765
3766     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3767
3768     return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3769 }
3770
3771 static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3772 {
3773     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3774
3775     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3776
3777     return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3778 }
3779
3780 /*****************************************************************************
3781  * IDirect3DDevice7::GetClipStatus
3782  *
3783  * Returns the clip status
3784  *
3785  * Params:
3786  *  ClipStatus: Address to write the clip status to
3787  *
3788  * Returns:
3789  *  D3D_OK because it's a stub
3790  *
3791  *****************************************************************************/
3792 static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3793 {
3794     FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3795
3796     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them */
3797     /* return IWineD3DDevice_GetClipStatus(This->wineD3DDevice, ClipStatus);*/
3798     return D3D_OK;
3799 }
3800
3801 static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3802 {
3803     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3804
3805     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3806
3807     return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3808 }
3809
3810 static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3811 {
3812     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3813
3814     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3815
3816     return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3817 }
3818
3819 /*****************************************************************************
3820  * IDirect3DDevice::DrawPrimitiveStrided
3821  *
3822  * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3823  *
3824  * Version 3 and 7
3825  *
3826  * Params:
3827  *  PrimitiveType: The primitive type to draw
3828  *  VertexType: The FVF description of the vertices to draw (for the stride??)
3829  *  D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3830  *                         the vertex data locations
3831  *  VertexCount: The number of vertices to draw
3832  *  Flags: Some flags
3833  *
3834  * Returns:
3835  *  D3D_OK, because it's a stub
3836  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3837  *  (For details, see IWineD3DDevice::DrawPrimitiveStrided)
3838  *
3839  *****************************************************************************/
3840 static void pack_strided_data(BYTE *dst, DWORD count, const D3DDRAWPRIMITIVESTRIDEDDATA *src, DWORD fvf)
3841 {
3842     DWORD i, tex, offset;
3843
3844     for (i = 0; i < count; i++)
3845     {
3846         /* The contents of the strided data are determined by the fvf,
3847          * not by the members set in src. So it's valid
3848          * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3849          * not set in the fvf. */
3850         if (fvf & D3DFVF_POSITION_MASK)
3851         {
3852             offset = i * src->position.dwStride;
3853             if (fvf & D3DFVF_XYZRHW)
3854             {
3855                 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 4 * sizeof(float));
3856                 dst += 4 * sizeof(float);
3857             }
3858             else
3859             {
3860                 memcpy(dst, ((BYTE *)src->position.lpvData) + offset, 3 * sizeof(float));
3861                 dst += 3 * sizeof(float);
3862             }
3863         }
3864
3865         if (fvf & D3DFVF_NORMAL)
3866         {
3867             offset = i * src->normal.dwStride;
3868             memcpy(dst, ((BYTE *)src->normal.lpvData) + offset, 3 * sizeof(float));
3869             dst += 3 * sizeof(float);
3870         }
3871
3872         if (fvf & D3DFVF_DIFFUSE)
3873         {
3874             offset = i * src->diffuse.dwStride;
3875             memcpy(dst, ((BYTE *)src->diffuse.lpvData) + offset, sizeof(DWORD));
3876             dst += sizeof(DWORD);
3877         }
3878
3879         if (fvf & D3DFVF_SPECULAR)
3880         {
3881             offset = i * src->specular.dwStride;
3882             memcpy(dst, ((BYTE *)src->specular.lpvData) + offset, sizeof(DWORD));
3883             dst += sizeof(DWORD);
3884         }
3885
3886         for (tex = 0; tex < GET_TEXCOUNT_FROM_FVF(fvf); ++tex)
3887         {
3888             DWORD attrib_count = GET_TEXCOORD_SIZE_FROM_FVF(fvf, tex);
3889             offset = i * src->textureCoords[tex].dwStride;
3890             memcpy(dst, ((BYTE *)src->textureCoords[tex].lpvData) + offset, attrib_count * sizeof(float));
3891             dst += attrib_count * sizeof(float);
3892         }
3893     }
3894 }
3895
3896 static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
3897         DWORD VertexType, D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3898 {
3899     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3900     HRESULT hr;
3901     UINT dst_stride = get_flexible_vertex_size(VertexType);
3902     UINT dst_size = dst_stride * VertexCount;
3903     UINT vb_pos, align;
3904     BYTE *dst_data;
3905
3906     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3907             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3908
3909     wined3d_mutex_lock();
3910     hr = d3d_device_prepare_vertex_buffer(device, dst_size);
3911     if (FAILED(hr))
3912         goto done;
3913
3914     vb_pos = device->vertex_buffer_pos;
3915     align = vb_pos % dst_stride;
3916     if (align) align = dst_stride - align;
3917     if (vb_pos + dst_size + align > device->vertex_buffer_size)
3918         vb_pos = 0;
3919     else
3920         vb_pos += align;
3921
3922     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, dst_size, &dst_data,
3923             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
3924     if (FAILED(hr))
3925         goto done;
3926     pack_strided_data(dst_data, VertexCount, D3DDrawPrimStrideData, VertexType);
3927     wined3d_buffer_unmap(device->vertex_buffer);
3928     device->vertex_buffer_pos = vb_pos + dst_size;
3929
3930     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, dst_stride);
3931     if (FAILED(hr))
3932         goto done;
3933     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, VertexType));
3934
3935     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
3936     hr = wined3d_device_draw_primitive(device->wined3d_device, vb_pos / dst_stride, VertexCount);
3937
3938 done:
3939     wined3d_mutex_unlock();
3940     return hr;
3941 }
3942
3943 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3944         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3945         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3946 {
3947     return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3948             VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3949 }
3950
3951 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3952         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3953         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3954 {
3955     HRESULT hr;
3956     WORD old_fpucw;
3957
3958     old_fpucw = d3d_fpu_setup();
3959     hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3960             VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3961     set_fpu_control_word(old_fpucw);
3962
3963     return hr;
3964 }
3965
3966 static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
3967         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3968         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3969 {
3970     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3971
3972     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3973             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3974
3975     return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
3976             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3977 }
3978
3979 /*****************************************************************************
3980  * IDirect3DDevice7::DrawIndexedPrimitiveStrided
3981  *
3982  * Draws primitives specified by strided data locations based on indices
3983  *
3984  * Version 3 and 7
3985  *
3986  * Params:
3987  *  PrimitiveType:
3988  *
3989  * Returns:
3990  *  D3D_OK, because it's a stub
3991  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3992  *  (DDERR_INVALIDPARAMS if Indices is NULL)
3993  *  (For more details, see IWineD3DDevice::DrawIndexedPrimitiveStrided)
3994  *
3995  *****************************************************************************/
3996 static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
3997         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3998         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
3999         WORD *Indices, DWORD IndexCount, DWORD Flags)
4000 {
4001     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4002     HRESULT hr;
4003     UINT vtx_dst_stride = get_flexible_vertex_size(VertexType);
4004     UINT vtx_dst_size = VertexCount * vtx_dst_stride;
4005     UINT vb_pos, align;
4006     UINT idx_size = IndexCount * sizeof(WORD);
4007     UINT ib_pos;
4008     BYTE *dst_data;
4009
4010     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4011             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4012
4013     wined3d_mutex_lock();
4014
4015     hr = d3d_device_prepare_vertex_buffer(device, vtx_dst_size);
4016     if (FAILED(hr))
4017         goto done;
4018
4019     vb_pos = device->vertex_buffer_pos;
4020     align = vb_pos % vtx_dst_stride;
4021     if (align) align = vtx_dst_stride - align;
4022     if (vb_pos + vtx_dst_size + align > device->vertex_buffer_size)
4023         vb_pos = 0;
4024     else
4025         vb_pos += align;
4026
4027     hr = wined3d_buffer_map(device->vertex_buffer, vb_pos, vtx_dst_size, &dst_data,
4028             vb_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
4029     if (FAILED(hr))
4030         goto done;
4031     pack_strided_data(dst_data, VertexCount, D3DDrawPrimStrideData, VertexType);
4032     wined3d_buffer_unmap(device->vertex_buffer);
4033     device->vertex_buffer_pos = vb_pos + vtx_dst_size;
4034
4035     hr = d3d_device_prepare_index_buffer(device, idx_size);
4036     if (FAILED(hr))
4037         goto done;
4038     ib_pos = device->index_buffer_pos;
4039     if (device->index_buffer_size - idx_size < ib_pos)
4040         ib_pos = 0;
4041
4042     hr = wined3d_buffer_map(device->index_buffer, ib_pos, idx_size, &dst_data,
4043             ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
4044     if (FAILED(hr))
4045         goto done;
4046     memcpy(dst_data, Indices, idx_size);
4047     wined3d_buffer_unmap(device->index_buffer);
4048     device->index_buffer_pos = ib_pos + idx_size;
4049
4050     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, device->vertex_buffer, 0, vtx_dst_stride);
4051     if (FAILED(hr))
4052         goto done;
4053     wined3d_device_set_index_buffer(device->wined3d_device, device->index_buffer, WINED3DFMT_R16_UINT);
4054     wined3d_device_set_base_vertex_index(device->wined3d_device, vb_pos / vtx_dst_stride);
4055
4056     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, VertexType));
4057     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
4058     hr = wined3d_device_draw_indexed_primitive(device->wined3d_device, ib_pos / sizeof(WORD), IndexCount);
4059
4060 done:
4061     wined3d_mutex_unlock();
4062     return hr;
4063 }
4064
4065 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
4066         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4067         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4068         WORD *Indices, DWORD IndexCount, DWORD Flags)
4069 {
4070     return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4071             D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4072 }
4073
4074 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
4075         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4076         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
4077         WORD *Indices, DWORD IndexCount, DWORD Flags)
4078 {
4079     HRESULT hr;
4080     WORD old_fpucw;
4081
4082     old_fpucw = d3d_fpu_setup();
4083     hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
4084             D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4085     set_fpu_control_word(old_fpucw);
4086
4087     return hr;
4088 }
4089
4090 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
4091         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
4092         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
4093         DWORD IndexCount, DWORD Flags)
4094 {
4095     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4096
4097     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4098             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4099
4100     return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
4101             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
4102 }
4103
4104 /*****************************************************************************
4105  * IDirect3DDevice7::DrawPrimitiveVB
4106  *
4107  * Draws primitives from a vertex buffer to the screen.
4108  *
4109  * Version 3 and 7
4110  *
4111  * Params:
4112  *  PrimitiveType: Type of primitive to be rendered.
4113  *  D3DVertexBuf: Source Vertex Buffer
4114  *  StartVertex: Index of the first vertex from the buffer to be rendered
4115  *  NumVertices: Number of vertices to be rendered
4116  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4117  *
4118  * Return values
4119  *  D3D_OK on success
4120  *  DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
4121  *
4122  *****************************************************************************/
4123 static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4124         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4125 {
4126     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4127     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4128     HRESULT hr;
4129     DWORD stride;
4130
4131     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4132             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4133
4134     /* Sanity checks */
4135     if (!vb)
4136     {
4137         WARN("No Vertex buffer specified.\n");
4138         return DDERR_INVALIDPARAMS;
4139     }
4140     stride = get_flexible_vertex_size(vb->fvf);
4141
4142     wined3d_mutex_lock();
4143     wined3d_device_set_vertex_declaration(device->wined3d_device, vb->wineD3DVertexDeclaration);
4144     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4145     if (FAILED(hr))
4146     {
4147         WARN("Failed to set stream source, hr %#x.\n", hr);
4148         wined3d_mutex_unlock();
4149         return hr;
4150     }
4151
4152     /* Now draw the primitives */
4153     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
4154     hr = wined3d_device_draw_primitive(device->wined3d_device, StartVertex, NumVertices);
4155
4156     if (SUCCEEDED(hr))
4157         vb->read_since_last_map = TRUE;
4158
4159     wined3d_mutex_unlock();
4160
4161     return hr;
4162 }
4163
4164 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4165         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4166 {
4167     return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4168 }
4169
4170 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4171         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4172 {
4173     HRESULT hr;
4174     WORD old_fpucw;
4175
4176     old_fpucw = d3d_fpu_setup();
4177     hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4178     set_fpu_control_word(old_fpucw);
4179
4180     return hr;
4181 }
4182
4183 static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
4184         IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4185 {
4186     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4187     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4188
4189     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4190             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4191
4192     return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4193             PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4194 }
4195
4196 /*****************************************************************************
4197  * IDirect3DDevice7::DrawIndexedPrimitiveVB
4198  *
4199  * Draws primitives from a vertex buffer to the screen
4200  *
4201  * Params:
4202  *  PrimitiveType: Type of primitive to be rendered.
4203  *  D3DVertexBuf: Source Vertex Buffer
4204  *  StartVertex: Index of the first vertex from the buffer to be rendered
4205  *  NumVertices: Number of vertices to be rendered
4206  *  Indices: Array of DWORDs used to index into the Vertices
4207  *  IndexCount: Number of indices in Indices
4208  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4209  *
4210  * Return values
4211  *
4212  *****************************************************************************/
4213 static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4214         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4215         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4216 {
4217     struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
4218     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4219     DWORD stride = get_flexible_vertex_size(vb->fvf);
4220     WORD *LockedIndices;
4221     HRESULT hr;
4222     UINT ib_pos;
4223
4224     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4225             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4226
4227     /* Steps:
4228      * 1) Upload the Indices to the index buffer
4229      * 2) Set the index source
4230      * 3) Set the Vertex Buffer as the Stream source
4231      * 4) Call IWineD3DDevice::DrawIndexedPrimitive
4232      */
4233
4234     wined3d_mutex_lock();
4235
4236     wined3d_device_set_vertex_declaration(This->wined3d_device, vb->wineD3DVertexDeclaration);
4237
4238     hr = d3d_device_prepare_index_buffer(This, IndexCount * sizeof(WORD));
4239     if (FAILED(hr))
4240     {
4241         wined3d_mutex_unlock();
4242         return hr;
4243     }
4244     ib_pos = This->index_buffer_pos;
4245
4246     if (This->index_buffer_size - IndexCount * sizeof(WORD) < ib_pos)
4247         ib_pos = 0;
4248
4249     /* Copy the index stream into the index buffer. A new IWineD3DDevice
4250      * method could be created which takes an user pointer containing the
4251      * indices or a SetData-Method for the index buffer, which overrides the
4252      * index buffer data with our pointer. */
4253     hr = wined3d_buffer_map(This->index_buffer, ib_pos, IndexCount * sizeof(WORD),
4254             (BYTE **)&LockedIndices, ib_pos ? WINED3D_MAP_NOOVERWRITE : WINED3D_MAP_DISCARD);
4255     if (FAILED(hr))
4256     {
4257         ERR("Failed to map buffer, hr %#x.\n", hr);
4258         wined3d_mutex_unlock();
4259         return hr;
4260     }
4261     memcpy(LockedIndices, Indices, IndexCount * sizeof(WORD));
4262     wined3d_buffer_unmap(This->index_buffer);
4263     This->index_buffer_pos = ib_pos + IndexCount * sizeof(WORD);
4264
4265     /* Set the index stream */
4266     wined3d_device_set_base_vertex_index(This->wined3d_device, StartVertex);
4267     wined3d_device_set_index_buffer(This->wined3d_device, This->index_buffer, WINED3DFMT_R16_UINT);
4268
4269     /* Set the vertex stream source */
4270     hr = wined3d_device_set_stream_source(This->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4271     if (FAILED(hr))
4272     {
4273         ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4274         wined3d_mutex_unlock();
4275         return hr;
4276     }
4277
4278
4279     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
4280     hr = wined3d_device_draw_indexed_primitive(This->wined3d_device, ib_pos / sizeof(WORD), IndexCount);
4281
4282     if (SUCCEEDED(hr))
4283         vb->read_since_last_map = TRUE;
4284
4285     wined3d_mutex_unlock();
4286
4287     return hr;
4288 }
4289
4290 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4291         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4292         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4293 {
4294     return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4295             D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4296 }
4297
4298 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4299         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4300         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4301 {
4302     HRESULT hr;
4303     WORD old_fpucw;
4304
4305     old_fpucw = d3d_fpu_setup();
4306     hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4307             D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4308     set_fpu_control_word(old_fpucw);
4309
4310     return hr;
4311 }
4312
4313 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4314         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer *D3DVertexBuf, WORD *Indices,
4315         DWORD IndexCount, DWORD Flags)
4316 {
4317     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4318     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4319
4320     TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
4321             iface, PrimitiveType, D3DVertexBuf, Indices, IndexCount, Flags);
4322
4323     return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, PrimitiveType,
4324             &vb->IDirect3DVertexBuffer7_iface, 0, IndexCount, Indices, IndexCount, Flags);
4325 }
4326
4327 /*****************************************************************************
4328  * IDirect3DDevice7::ComputeSphereVisibility
4329  *
4330  * Calculates the visibility of spheres in the current viewport. The spheres
4331  * are passed in the Centers and Radii arrays, the results are passed back
4332  * in the ReturnValues array. Return values are either completely visible,
4333  * partially visible or completely invisible.
4334  * The return value consist of a combination of D3DCLIP_* flags, or it's
4335  * 0 if the sphere is completely visible(according to the SDK, not checked)
4336  *
4337  * Version 3 and 7
4338  *
4339  * Params:
4340  *  Centers: Array containing the sphere centers
4341  *  Radii: Array containing the sphere radii
4342  *  NumSpheres: The number of centers and radii in the arrays
4343  *  Flags: Some flags
4344  *  ReturnValues: Array to write the results to
4345  *
4346  * Returns:
4347  *  D3D_OK
4348  *  (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4349  *  (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4350  *  is singular)
4351  *
4352  *****************************************************************************/
4353
4354 static DWORD in_plane(UINT plane, D3DVECTOR normal, D3DVALUE origin_plane, D3DVECTOR center, D3DVALUE radius)
4355 {
4356     float distance, norm;
4357
4358     norm = sqrt( normal.u1.x * normal.u1.x + normal.u2.y * normal.u2.y + normal.u3.z * normal.u3.z );
4359     distance = ( origin_plane + normal.u1.x * center.u1.x + normal.u2.y * center.u2.y + normal.u3.z * center.u3.z ) / norm;
4360
4361     if ( fabs( distance ) < radius ) return D3DSTATUS_CLIPUNIONLEFT << plane;
4362     if ( distance < -radius ) return (D3DSTATUS_CLIPUNIONLEFT  | D3DSTATUS_CLIPINTERSECTIONLEFT) << plane;
4363     return 0;
4364 }
4365
4366 static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4367         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4368 {
4369     D3DMATRIX m, temp;
4370     D3DVALUE origin_plane[6];
4371     D3DVECTOR vec[6];
4372     HRESULT hr;
4373     UINT i, j;
4374
4375     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4376             iface, centers, radii, sphere_count, flags, return_values);
4377
4378     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
4379     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4380     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
4381     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4382     multiply_matrix(&m, &temp, &m);
4383
4384     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
4385     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4386     multiply_matrix(&m, &temp, &m);
4387
4388 /* Left plane */
4389     vec[0].u1.x = m._14 + m._11;
4390     vec[0].u2.y = m._24 + m._21;
4391     vec[0].u3.z = m._34 + m._31;
4392     origin_plane[0] = m._44 + m._41;
4393
4394 /* Right plane */
4395     vec[1].u1.x = m._14 - m._11;
4396     vec[1].u2.y = m._24 - m._21;
4397     vec[1].u3.z = m._34 - m._31;
4398     origin_plane[1] = m._44 - m._41;
4399
4400 /* Top plane */
4401     vec[2].u1.x = m._14 - m._12;
4402     vec[2].u2.y = m._24 - m._22;
4403     vec[2].u3.z = m._34 - m._32;
4404     origin_plane[2] = m._44 - m._42;
4405
4406 /* Bottom plane */
4407     vec[3].u1.x = m._14 + m._12;
4408     vec[3].u2.y = m._24 + m._22;
4409     vec[3].u3.z = m._34 + m._32;
4410     origin_plane[3] = m._44 + m._42;
4411
4412 /* Front plane */
4413     vec[4].u1.x = m._13;
4414     vec[4].u2.y = m._23;
4415     vec[4].u3.z = m._33;
4416     origin_plane[4] = m._43;
4417
4418 /* Back plane*/
4419     vec[5].u1.x = m._14 - m._13;
4420     vec[5].u2.y = m._24 - m._23;
4421     vec[5].u3.z = m._34 - m._33;
4422     origin_plane[5] = m._44 - m._43;
4423
4424     for (i = 0; i < sphere_count; ++i)
4425     {
4426         return_values[i] = 0;
4427         for (j = 0; j < 6; ++j)
4428             return_values[i] |= in_plane(j, vec[j], origin_plane[j], centers[i], radii[i]);
4429     }
4430
4431     return D3D_OK;
4432 }
4433
4434 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4435         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4436 {
4437     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4438
4439     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4440             iface, centers, radii, sphere_count, flags, return_values);
4441
4442     return IDirect3DDevice7_ComputeSphereVisibility(&device->IDirect3DDevice7_iface,
4443             centers, radii, sphere_count, flags, return_values);
4444 }
4445
4446 /*****************************************************************************
4447  * IDirect3DDevice7::GetTexture
4448  *
4449  * Returns the texture interface handle assigned to a texture stage.
4450  * The returned texture is AddRefed. This is taken from old ddraw,
4451  * not checked in Windows.
4452  *
4453  * Version 3 and 7
4454  *
4455  * Params:
4456  *  Stage: Texture stage to read the texture from
4457  *  Texture: Address to store the interface pointer at
4458  *
4459  * Returns:
4460  *  D3D_OK on success
4461  *  DDERR_INVALIDPARAMS if Texture is NULL
4462  *  For details, see IWineD3DDevice::GetTexture
4463  *
4464  *****************************************************************************/
4465 static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
4466         DWORD stage, IDirectDrawSurface7 **texture)
4467 {
4468     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4469     struct wined3d_texture *wined3d_texture;
4470     struct ddraw_surface *surface;
4471
4472     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4473
4474     if (!texture)
4475         return DDERR_INVALIDPARAMS;
4476
4477     wined3d_mutex_lock();
4478     if (!(wined3d_texture = wined3d_device_get_texture(device->wined3d_device, stage)))
4479     {
4480         *texture = NULL;
4481         wined3d_mutex_unlock();
4482         return D3D_OK;
4483     }
4484
4485     surface = wined3d_texture_get_parent(wined3d_texture);
4486     *texture = &surface->IDirectDrawSurface7_iface;
4487     IDirectDrawSurface7_AddRef(*texture);
4488     wined3d_mutex_unlock();
4489
4490     return D3D_OK;
4491 }
4492
4493 static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4494         DWORD stage, IDirectDrawSurface7 **Texture)
4495 {
4496     return d3d_device7_GetTexture(iface, stage, Texture);
4497 }
4498
4499 static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4500         DWORD stage, IDirectDrawSurface7 **Texture)
4501 {
4502     HRESULT hr;
4503     WORD old_fpucw;
4504
4505     old_fpucw = d3d_fpu_setup();
4506     hr = d3d_device7_GetTexture(iface, stage, Texture);
4507     set_fpu_control_word(old_fpucw);
4508
4509     return hr;
4510 }
4511
4512 static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4513 {
4514     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4515     struct ddraw_surface *ret_val_impl;
4516     HRESULT ret;
4517     IDirectDrawSurface7 *ret_val;
4518
4519     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, Texture2);
4520
4521     ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4522
4523     ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4524     *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4525
4526     TRACE("Returning texture %p.\n", *Texture2);
4527
4528     return ret;
4529 }
4530
4531 /*****************************************************************************
4532  * IDirect3DDevice7::SetTexture
4533  *
4534  * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4535  *
4536  * Version 3 and 7
4537  *
4538  * Params:
4539  *  Stage: The stage to assign the texture to
4540  *  Texture: Interface pointer to the texture surface
4541  *
4542  * Returns
4543  * D3D_OK on success
4544  * For details, see IWineD3DDevice::SetTexture
4545  *
4546  *****************************************************************************/
4547 static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
4548         DWORD stage, IDirectDrawSurface7 *texture)
4549 {
4550     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4551     struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4552     HRESULT hr;
4553
4554     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4555
4556     /* Texture may be NULL here */
4557     wined3d_mutex_lock();
4558     hr = wined3d_device_set_texture(device->wined3d_device,
4559             stage, surf ? surf->wined3d_texture : NULL);
4560     wined3d_mutex_unlock();
4561
4562     return hr;
4563 }
4564
4565 static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4566         DWORD stage, IDirectDrawSurface7 *texture)
4567 {
4568     return d3d_device7_SetTexture(iface, stage, texture);
4569 }
4570
4571 static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4572         DWORD stage, IDirectDrawSurface7 *texture)
4573 {
4574     HRESULT hr;
4575     WORD old_fpucw;
4576
4577     old_fpucw = d3d_fpu_setup();
4578     hr = d3d_device7_SetTexture(iface, stage, texture);
4579     set_fpu_control_word(old_fpucw);
4580
4581     return hr;
4582 }
4583
4584 static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
4585         DWORD stage, IDirect3DTexture2 *texture)
4586 {
4587     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4588     struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4589     DWORD texmapblend;
4590     HRESULT hr;
4591
4592     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4593
4594     wined3d_mutex_lock();
4595
4596     if (device->legacyTextureBlending)
4597         IDirect3DDevice3_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend);
4598
4599     hr = IDirect3DDevice7_SetTexture(&device->IDirect3DDevice7_iface, stage, &tex->IDirectDrawSurface7_iface);
4600
4601     if (device->legacyTextureBlending && texmapblend == D3DTBLEND_MODULATE)
4602     {
4603         /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
4604            See d3d_device3_SetRenderState() for details. */
4605         struct wined3d_texture *tex = NULL;
4606         BOOL tex_alpha = FALSE;
4607         DDPIXELFORMAT ddfmt;
4608
4609         if ((tex = wined3d_device_get_texture(device->wined3d_device, 0)))
4610         {
4611             struct wined3d_resource *sub_resource;
4612
4613             if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
4614             {
4615                 struct wined3d_resource_desc desc;
4616
4617                 wined3d_resource_get_desc(sub_resource, &desc);
4618                 ddfmt.dwSize = sizeof(ddfmt);
4619                 PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
4620                 if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
4621             }
4622         }
4623
4624         /* Arg 1/2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
4625         if (tex_alpha)
4626             wined3d_device_set_texture_stage_state(device->wined3d_device,
4627                     0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
4628         else
4629             wined3d_device_set_texture_stage_state(device->wined3d_device,
4630                     0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
4631     }
4632
4633     wined3d_mutex_unlock();
4634
4635     return hr;
4636 }
4637
4638 static const struct tss_lookup
4639 {
4640     BOOL sampler_state;
4641     enum wined3d_texture_stage_state state;
4642 }
4643 tss_lookup[] =
4644 {
4645     {FALSE, WINED3D_TSS_INVALID},                   /*  0, unused */
4646     {FALSE, WINED3D_TSS_COLOR_OP},                  /*  1, D3DTSS_COLOROP */
4647     {FALSE, WINED3D_TSS_COLOR_ARG1},                /*  2, D3DTSS_COLORARG1 */
4648     {FALSE, WINED3D_TSS_COLOR_ARG2},                /*  3, D3DTSS_COLORARG2 */
4649     {FALSE, WINED3D_TSS_ALPHA_OP},                  /*  4, D3DTSS_ALPHAOP */
4650     {FALSE, WINED3D_TSS_ALPHA_ARG1},                /*  5, D3DTSS_ALPHAARG1 */
4651     {FALSE, WINED3D_TSS_ALPHA_ARG2},                /*  6, D3DTSS_ALPHAARG2 */
4652     {FALSE, WINED3D_TSS_BUMPENV_MAT00},             /*  7, D3DTSS_BUMPENVMAT00 */
4653     {FALSE, WINED3D_TSS_BUMPENV_MAT01},             /*  8, D3DTSS_BUMPENVMAT01 */
4654     {FALSE, WINED3D_TSS_BUMPENV_MAT10},             /*  9, D3DTSS_BUMPENVMAT10 */
4655     {FALSE, WINED3D_TSS_BUMPENV_MAT11},             /* 10, D3DTSS_BUMPENVMAT11 */
4656     {FALSE, WINED3D_TSS_TEXCOORD_INDEX},            /* 11, D3DTSS_TEXCOORDINDEX */
4657     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 12, D3DTSS_ADDRESS */
4658     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 13, D3DTSS_ADDRESSU */
4659     {TRUE,  WINED3D_SAMP_ADDRESS_V},                /* 14, D3DTSS_ADDRESSV */
4660     {TRUE,  WINED3D_SAMP_BORDER_COLOR},             /* 15, D3DTSS_BORDERCOLOR */
4661     {TRUE,  WINED3D_SAMP_MAG_FILTER},               /* 16, D3DTSS_MAGFILTER */
4662     {TRUE,  WINED3D_SAMP_MIN_FILTER},               /* 17, D3DTSS_MINFILTER */
4663     {TRUE,  WINED3D_SAMP_MIP_FILTER},               /* 18, D3DTSS_MIPFILTER */
4664     {TRUE,  WINED3D_SAMP_MIPMAP_LOD_BIAS},          /* 19, D3DTSS_MIPMAPLODBIAS */
4665     {TRUE,  WINED3D_SAMP_MAX_MIP_LEVEL},            /* 20, D3DTSS_MAXMIPLEVEL */
4666     {TRUE,  WINED3D_SAMP_MAX_ANISOTROPY},           /* 21, D3DTSS_MAXANISOTROPY */
4667     {FALSE, WINED3D_TSS_BUMPENV_LSCALE},            /* 22, D3DTSS_BUMPENVLSCALE */
4668     {FALSE, WINED3D_TSS_BUMPENV_LOFFSET},           /* 23, D3DTSS_BUMPENVLOFFSET */
4669     {FALSE, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS},   /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4670 };
4671
4672 /*****************************************************************************
4673  * IDirect3DDevice7::GetTextureStageState
4674  *
4675  * Retrieves a state from a texture stage.
4676  *
4677  * Version 3 and 7
4678  *
4679  * Params:
4680  *  Stage: The stage to retrieve the state from
4681  *  TexStageStateType: The state type to retrieve
4682  *  State: Address to store the state's value at
4683  *
4684  * Returns:
4685  *  D3D_OK on success
4686  *  DDERR_INVALIDPARAMS if State is NULL
4687  *  For details, see IWineD3DDevice::GetTextureStageState
4688  *
4689  *****************************************************************************/
4690 static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
4691         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4692 {
4693     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4694     const struct tss_lookup *l;
4695
4696     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4697             iface, stage, state, value);
4698
4699     if (!value)
4700         return DDERR_INVALIDPARAMS;
4701
4702     if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4703     {
4704         WARN("Invalid state %#x passed.\n", state);
4705         return DD_OK;
4706     }
4707
4708     l = &tss_lookup[state];
4709
4710     wined3d_mutex_lock();
4711
4712     if (l->sampler_state)
4713     {
4714         *value = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->state);
4715
4716         switch (state)
4717         {
4718             /* Mipfilter is a sampler state with different values */
4719             case D3DTSS_MIPFILTER:
4720             {
4721                 switch (*value)
4722                 {
4723                     case WINED3D_TEXF_NONE:
4724                         *value = D3DTFP_NONE;
4725                         break;
4726                     case WINED3D_TEXF_POINT:
4727                         *value = D3DTFP_POINT;
4728                         break;
4729                     case WINED3D_TEXF_LINEAR:
4730                         *value = D3DTFP_LINEAR;
4731                         break;
4732                     default:
4733                         ERR("Unexpected mipfilter value %#x.\n", *value);
4734                         *value = D3DTFP_NONE;
4735                         break;
4736                 }
4737                 break;
4738             }
4739
4740             /* Magfilter has slightly different values */
4741             case D3DTSS_MAGFILTER:
4742             {
4743                 switch (*value)
4744                 {
4745                     case WINED3D_TEXF_POINT:
4746                             *value = D3DTFG_POINT;
4747                             break;
4748                     case WINED3D_TEXF_LINEAR:
4749                             *value = D3DTFG_LINEAR;
4750                             break;
4751                     case WINED3D_TEXF_ANISOTROPIC:
4752                             *value = D3DTFG_ANISOTROPIC;
4753                             break;
4754                     case WINED3D_TEXF_FLAT_CUBIC:
4755                             *value = D3DTFG_FLATCUBIC;
4756                             break;
4757                     case WINED3D_TEXF_GAUSSIAN_CUBIC:
4758                             *value = D3DTFG_GAUSSIANCUBIC;
4759                             break;
4760                     default:
4761                         ERR("Unexpected wined3d mag filter value %#x.\n", *value);
4762                         *value = D3DTFG_POINT;
4763                         break;
4764                 }
4765                 break;
4766             }
4767
4768             default:
4769                 break;
4770         }
4771     }
4772     else
4773     {
4774         *value = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->state);
4775     }
4776
4777     wined3d_mutex_unlock();
4778
4779     return D3D_OK;
4780 }
4781
4782 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4783         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4784 {
4785     return d3d_device7_GetTextureStageState(iface, stage, state, value);
4786 }
4787
4788 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4789         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4790 {
4791     HRESULT hr;
4792     WORD old_fpucw;
4793
4794     old_fpucw = d3d_fpu_setup();
4795     hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
4796     set_fpu_control_word(old_fpucw);
4797
4798     return hr;
4799 }
4800
4801 static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
4802         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4803 {
4804     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4805
4806     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4807             iface, stage, state, value);
4808
4809     return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4810 }
4811
4812 /*****************************************************************************
4813  * IDirect3DDevice7::SetTextureStageState
4814  *
4815  * Sets a texture stage state. Some stage types need to be handled specially,
4816  * because they do not exist in WineD3D and were moved to another place
4817  *
4818  * Version 3 and 7
4819  *
4820  * Params:
4821  *  Stage: The stage to modify
4822  *  TexStageStateType: The state to change
4823  *  State: The new value for the state
4824  *
4825  * Returns:
4826  *  D3D_OK on success
4827  *  For details, see IWineD3DDevice::SetTextureStageState
4828  *
4829  *****************************************************************************/
4830 static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
4831         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4832 {
4833     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4834     const struct tss_lookup *l;
4835
4836     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4837             iface, stage, state, value);
4838
4839     if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4840     {
4841         WARN("Invalid state %#x passed.\n", state);
4842         return DD_OK;
4843     }
4844
4845     l = &tss_lookup[state];
4846
4847     wined3d_mutex_lock();
4848
4849     if (l->sampler_state)
4850     {
4851         switch (state)
4852         {
4853             /* Mipfilter is a sampler state with different values */
4854             case D3DTSS_MIPFILTER:
4855             {
4856                 switch (value)
4857                 {
4858                     case D3DTFP_NONE:
4859                         value = WINED3D_TEXF_NONE;
4860                         break;
4861                     case D3DTFP_POINT:
4862                         value = WINED3D_TEXF_POINT;
4863                         break;
4864                     case 0: /* Unchecked */
4865                     case D3DTFP_LINEAR:
4866                         value = WINED3D_TEXF_LINEAR;
4867                         break;
4868                     default:
4869                         ERR("Unexpected mipfilter value %#x.\n", value);
4870                         value = WINED3D_TEXF_NONE;
4871                         break;
4872                 }
4873                 break;
4874             }
4875
4876             /* Magfilter has slightly different values */
4877             case D3DTSS_MAGFILTER:
4878             {
4879                 switch (value)
4880                 {
4881                     case D3DTFG_POINT:
4882                         value = WINED3D_TEXF_POINT;
4883                         break;
4884                     case D3DTFG_LINEAR:
4885                         value = WINED3D_TEXF_LINEAR;
4886                         break;
4887                     case D3DTFG_FLATCUBIC:
4888                         value = WINED3D_TEXF_FLAT_CUBIC;
4889                         break;
4890                     case D3DTFG_GAUSSIANCUBIC:
4891                         value = WINED3D_TEXF_GAUSSIAN_CUBIC;
4892                         break;
4893                     case D3DTFG_ANISOTROPIC:
4894                         value = WINED3D_TEXF_ANISOTROPIC;
4895                         break;
4896                     default:
4897                         ERR("Unexpected d3d7 mag filter value %#x.\n", value);
4898                         value = WINED3D_TEXF_POINT;
4899                         break;
4900                 }
4901                 break;
4902             }
4903
4904             case D3DTSS_ADDRESS:
4905                 wined3d_device_set_sampler_state(device->wined3d_device, stage, WINED3D_SAMP_ADDRESS_V, value);
4906                 break;
4907
4908             default:
4909                 break;
4910         }
4911
4912         wined3d_device_set_sampler_state(device->wined3d_device, stage, l->state, value);
4913     }
4914     else
4915     {
4916         wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->state, value);
4917     }
4918
4919     wined3d_mutex_unlock();
4920
4921     return D3D_OK;
4922 }
4923
4924 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4925         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4926 {
4927     return d3d_device7_SetTextureStageState(iface, stage, state, value);
4928 }
4929
4930 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4931         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4932 {
4933     HRESULT hr;
4934     WORD old_fpucw;
4935
4936     old_fpucw = d3d_fpu_setup();
4937     hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
4938     set_fpu_control_word(old_fpucw);
4939
4940     return hr;
4941 }
4942
4943 static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
4944         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4945 {
4946     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4947
4948     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4949             iface, stage, state, value);
4950
4951     return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4952 }
4953
4954 /*****************************************************************************
4955  * IDirect3DDevice7::ValidateDevice
4956  *
4957  * SDK: "Reports the device's ability to render the currently set
4958  * texture-blending operations in a single pass". Whatever that means
4959  * exactly...
4960  *
4961  * Version 3 and 7
4962  *
4963  * Params:
4964  *  NumPasses: Address to write the number of necessary passes for the
4965  *             desired effect to.
4966  *
4967  * Returns:
4968  *  D3D_OK on success
4969  *  See IWineD3DDevice::ValidateDevice for more details
4970  *
4971  *****************************************************************************/
4972 static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
4973 {
4974     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4975     HRESULT hr;
4976
4977     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4978
4979     wined3d_mutex_lock();
4980     hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
4981     wined3d_mutex_unlock();
4982
4983     return hr;
4984 }
4985
4986 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
4987 {
4988     return d3d_device7_ValidateDevice(iface, pass_count);
4989 }
4990
4991 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
4992 {
4993     HRESULT hr;
4994     WORD old_fpucw;
4995
4996     old_fpucw = d3d_fpu_setup();
4997     hr = d3d_device7_ValidateDevice(iface, pass_count);
4998     set_fpu_control_word(old_fpucw);
4999
5000     return hr;
5001 }
5002
5003 static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
5004 {
5005     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
5006
5007     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
5008
5009     return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
5010 }
5011
5012 /*****************************************************************************
5013  * IDirect3DDevice7::Clear
5014  *
5015  * Fills the render target, the z buffer and the stencil buffer with a
5016  * clear color / value
5017  *
5018  * Version 7 only
5019  *
5020  * Params:
5021  *  Count: Number of rectangles in Rects must be 0 if Rects is NULL
5022  *  Rects: Rectangles to clear. If NULL, the whole surface is cleared
5023  *  Flags: Some flags, as usual
5024  *  Color: Clear color for the render target
5025  *  Z: Clear value for the Z buffer
5026  *  Stencil: Clear value to store in each stencil buffer entry
5027  *
5028  * Returns:
5029  *  D3D_OK on success
5030  *  For details, see IWineD3DDevice::Clear
5031  *
5032  *****************************************************************************/
5033 static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
5034         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5035 {
5036     const struct wined3d_color c =
5037     {
5038         ((color >> 16) & 0xff) / 255.0f,
5039         ((color >>  8) & 0xff) / 255.0f,
5040         (color & 0xff) / 255.0f,
5041         ((color >> 24) & 0xff) / 255.0f,
5042     };
5043     struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
5044     HRESULT hr;
5045
5046     TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
5047             iface, count, rects, flags, color, z, stencil);
5048
5049     wined3d_mutex_lock();
5050     hr = wined3d_device_clear(This->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
5051     wined3d_mutex_unlock();
5052
5053     return hr;
5054 }
5055
5056 static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
5057         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5058 {
5059     return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5060 }
5061
5062 static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
5063         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
5064 {
5065     HRESULT hr;
5066     WORD old_fpucw;
5067
5068     old_fpucw = d3d_fpu_setup();
5069     hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
5070     set_fpu_control_word(old_fpucw);
5071
5072     return hr;
5073 }
5074
5075 /*****************************************************************************
5076  * IDirect3DDevice7::SetViewport
5077  *
5078  * Sets the current viewport.
5079  *
5080  * Version 7 only, but IDirect3DViewport uses this call for older
5081  * versions
5082  *
5083  * Params:
5084  *  Data: The new viewport to set
5085  *
5086  * Returns:
5087  *  D3D_OK on success
5088  *  DDERR_INVALIDPARAMS if Data is NULL
5089  *  For more details, see IWineDDDevice::SetViewport
5090  *
5091  *****************************************************************************/
5092 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5093 {
5094     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5095
5096     TRACE("iface %p, viewport %p.\n", iface, viewport);
5097
5098     if (!viewport)
5099         return DDERR_INVALIDPARAMS;
5100
5101     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5102     wined3d_mutex_lock();
5103     wined3d_device_set_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
5104     wined3d_mutex_unlock();
5105
5106     return D3D_OK;
5107 }
5108
5109 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5110 {
5111     return d3d_device7_SetViewport(iface, viewport);
5112 }
5113
5114 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5115 {
5116     HRESULT hr;
5117     WORD old_fpucw;
5118
5119     old_fpucw = d3d_fpu_setup();
5120     hr = d3d_device7_SetViewport(iface, viewport);
5121     set_fpu_control_word(old_fpucw);
5122
5123     return hr;
5124 }
5125
5126 /*****************************************************************************
5127  * IDirect3DDevice::GetViewport
5128  *
5129  * Returns the current viewport
5130  *
5131  * Version 7
5132  *
5133  * Params:
5134  *  Data: D3D7Viewport structure to write the viewport information to
5135  *
5136  * Returns:
5137  *  D3D_OK on success
5138  *  DDERR_INVALIDPARAMS if Data is NULL
5139  *  For more details, see IWineD3DDevice::GetViewport
5140  *
5141  *****************************************************************************/
5142 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5143 {
5144     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5145
5146     TRACE("iface %p, viewport %p.\n", iface, viewport);
5147
5148     if (!viewport)
5149         return DDERR_INVALIDPARAMS;
5150
5151     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5152     wined3d_mutex_lock();
5153     wined3d_device_get_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
5154     wined3d_mutex_unlock();
5155
5156     return D3D_OK;
5157 }
5158
5159 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5160 {
5161     return d3d_device7_GetViewport(iface, viewport);
5162 }
5163
5164 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5165 {
5166     HRESULT hr;
5167     WORD old_fpucw;
5168
5169     old_fpucw = d3d_fpu_setup();
5170     hr = d3d_device7_GetViewport(iface, viewport);
5171     set_fpu_control_word(old_fpucw);
5172
5173     return hr;
5174 }
5175
5176 /*****************************************************************************
5177  * IDirect3DDevice7::SetMaterial
5178  *
5179  * Sets the Material
5180  *
5181  * Version 7
5182  *
5183  * Params:
5184  *  Mat: The material to set
5185  *
5186  * Returns:
5187  *  D3D_OK on success
5188  *  DDERR_INVALIDPARAMS if Mat is NULL.
5189  *  For more details, see IWineD3DDevice::SetMaterial
5190  *
5191  *****************************************************************************/
5192 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5193 {
5194     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5195
5196     TRACE("iface %p, material %p.\n", iface, material);
5197
5198     if (!material)
5199         return DDERR_INVALIDPARAMS;
5200
5201     wined3d_mutex_lock();
5202     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5203     wined3d_device_set_material(device->wined3d_device, (struct wined3d_material *)material);
5204     wined3d_mutex_unlock();
5205
5206     return D3D_OK;
5207 }
5208
5209 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5210 {
5211     return d3d_device7_SetMaterial(iface, material);
5212 }
5213
5214 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5215 {
5216     HRESULT hr;
5217     WORD old_fpucw;
5218
5219     old_fpucw = d3d_fpu_setup();
5220     hr = d3d_device7_SetMaterial(iface, material);
5221     set_fpu_control_word(old_fpucw);
5222
5223     return hr;
5224 }
5225
5226 /*****************************************************************************
5227  * IDirect3DDevice7::GetMaterial
5228  *
5229  * Returns the current material
5230  *
5231  * Version 7
5232  *
5233  * Params:
5234  *  Mat: D3DMATERIAL7 structure to write the material parameters to
5235  *
5236  * Returns:
5237  *  D3D_OK on success
5238  *  DDERR_INVALIDPARAMS if Mat is NULL
5239  *  For more details, see IWineD3DDevice::GetMaterial
5240  *
5241  *****************************************************************************/
5242 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5243 {
5244     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5245
5246     TRACE("iface %p, material %p.\n", iface, material);
5247
5248     wined3d_mutex_lock();
5249     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5250     wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
5251     wined3d_mutex_unlock();
5252
5253     return D3D_OK;
5254 }
5255
5256 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5257 {
5258     return d3d_device7_GetMaterial(iface, material);
5259 }
5260
5261 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5262 {
5263     HRESULT hr;
5264     WORD old_fpucw;
5265
5266     old_fpucw = d3d_fpu_setup();
5267     hr = d3d_device7_GetMaterial(iface, material);
5268     set_fpu_control_word(old_fpucw);
5269
5270     return hr;
5271 }
5272
5273 /*****************************************************************************
5274  * IDirect3DDevice7::SetLight
5275  *
5276  * Assigns a light to a light index, but doesn't activate it yet.
5277  *
5278  * Version 7, IDirect3DLight uses this method for older versions
5279  *
5280  * Params:
5281  *  LightIndex: The index of the new light
5282  *  Light: A D3DLIGHT7 structure describing the light
5283  *
5284  * Returns:
5285  *  D3D_OK on success
5286  *  For more details, see IWineD3DDevice::SetLight
5287  *
5288  *****************************************************************************/
5289 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5290 {
5291     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5292     HRESULT hr;
5293
5294     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5295
5296     wined3d_mutex_lock();
5297     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5298     hr = wined3d_device_set_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5299     wined3d_mutex_unlock();
5300
5301     return hr_ddraw_from_wined3d(hr);
5302 }
5303
5304 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5305 {
5306     return d3d_device7_SetLight(iface, light_idx, light);
5307 }
5308
5309 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5310 {
5311     HRESULT hr;
5312     WORD old_fpucw;
5313
5314     old_fpucw = d3d_fpu_setup();
5315     hr = d3d_device7_SetLight(iface, light_idx, light);
5316     set_fpu_control_word(old_fpucw);
5317
5318     return hr;
5319 }
5320
5321 /*****************************************************************************
5322  * IDirect3DDevice7::GetLight
5323  *
5324  * Returns the light assigned to a light index
5325  *
5326  * Params:
5327  *  Light: Structure to write the light information to
5328  *
5329  * Returns:
5330  *  D3D_OK on success
5331  *  DDERR_INVALIDPARAMS if Light is NULL
5332  *  For details, see IWineD3DDevice::GetLight
5333  *
5334  *****************************************************************************/
5335 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5336 {
5337     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5338     HRESULT rc;
5339
5340     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5341
5342     wined3d_mutex_lock();
5343     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5344     rc =  wined3d_device_get_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5345     wined3d_mutex_unlock();
5346
5347     /* Translate the result. WineD3D returns other values than D3D7 */
5348     return hr_ddraw_from_wined3d(rc);
5349 }
5350
5351 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5352 {
5353     return d3d_device7_GetLight(iface, light_idx, light);
5354 }
5355
5356 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5357 {
5358     HRESULT hr;
5359     WORD old_fpucw;
5360
5361     old_fpucw = d3d_fpu_setup();
5362     hr = d3d_device7_GetLight(iface, light_idx, light);
5363     set_fpu_control_word(old_fpucw);
5364
5365     return hr;
5366 }
5367
5368 /*****************************************************************************
5369  * IDirect3DDevice7::BeginStateBlock
5370  *
5371  * Begins recording to a stateblock
5372  *
5373  * Version 7
5374  *
5375  * Returns:
5376  *  D3D_OK on success
5377  *  For details see IWineD3DDevice::BeginStateBlock
5378  *
5379  *****************************************************************************/
5380 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5381 {
5382     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5383     HRESULT hr;
5384
5385     TRACE("iface %p.\n", iface);
5386
5387     wined3d_mutex_lock();
5388     hr = wined3d_device_begin_stateblock(device->wined3d_device);
5389     wined3d_mutex_unlock();
5390
5391     return hr_ddraw_from_wined3d(hr);
5392 }
5393
5394 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5395 {
5396     return d3d_device7_BeginStateBlock(iface);
5397 }
5398
5399 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5400 {
5401     HRESULT hr;
5402     WORD old_fpucw;
5403
5404     old_fpucw = d3d_fpu_setup();
5405     hr = d3d_device7_BeginStateBlock(iface);
5406     set_fpu_control_word(old_fpucw);
5407
5408     return hr;
5409 }
5410
5411 /*****************************************************************************
5412  * IDirect3DDevice7::EndStateBlock
5413  *
5414  * Stops recording to a state block and returns the created stateblock
5415  * handle.
5416  *
5417  * Version 7
5418  *
5419  * Params:
5420  *  BlockHandle: Address to store the stateblock's handle to
5421  *
5422  * Returns:
5423  *  D3D_OK on success
5424  *  DDERR_INVALIDPARAMS if BlockHandle is NULL
5425  *  See IWineD3DDevice::EndStateBlock for more details
5426  *
5427  *****************************************************************************/
5428 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5429 {
5430     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5431     struct wined3d_stateblock *wined3d_sb;
5432     HRESULT hr;
5433     DWORD h;
5434
5435     TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5436
5437     if (!stateblock)
5438         return DDERR_INVALIDPARAMS;
5439
5440     wined3d_mutex_lock();
5441
5442     hr = wined3d_device_end_stateblock(device->wined3d_device, &wined3d_sb);
5443     if (FAILED(hr))
5444     {
5445         WARN("Failed to end stateblock, hr %#x.\n", hr);
5446         wined3d_mutex_unlock();
5447         *stateblock = 0;
5448         return hr_ddraw_from_wined3d(hr);
5449     }
5450
5451     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5452     if (h == DDRAW_INVALID_HANDLE)
5453     {
5454         ERR("Failed to allocate a stateblock handle.\n");
5455         wined3d_stateblock_decref(wined3d_sb);
5456         wined3d_mutex_unlock();
5457         *stateblock = 0;
5458         return DDERR_OUTOFMEMORY;
5459     }
5460
5461     wined3d_mutex_unlock();
5462     *stateblock = h + 1;
5463
5464     return hr_ddraw_from_wined3d(hr);
5465 }
5466
5467 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5468 {
5469     return d3d_device7_EndStateBlock(iface, stateblock);
5470 }
5471
5472 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5473 {
5474     HRESULT hr;
5475     WORD old_fpucw;
5476
5477     old_fpucw = d3d_fpu_setup();
5478     hr = d3d_device7_EndStateBlock(iface, stateblock);
5479     set_fpu_control_word(old_fpucw);
5480
5481     return hr;
5482 }
5483
5484 /*****************************************************************************
5485  * IDirect3DDevice7::PreLoad
5486  *
5487  * Allows the app to signal that a texture will be used soon, to allow
5488  * the Direct3DDevice to load it to the video card in the meantime.
5489  *
5490  * Version 7
5491  *
5492  * Params:
5493  *  Texture: The texture to preload
5494  *
5495  * Returns:
5496  *  D3D_OK on success
5497  *  DDERR_INVALIDPARAMS if Texture is NULL
5498  *  See IWineD3DSurface::PreLoad for details
5499  *
5500  *****************************************************************************/
5501 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5502 {
5503     struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5504
5505     TRACE("iface %p, texture %p.\n", iface, texture);
5506
5507     if (!texture)
5508         return DDERR_INVALIDPARAMS;
5509
5510     wined3d_mutex_lock();
5511     wined3d_surface_preload(surface->wined3d_surface);
5512     wined3d_mutex_unlock();
5513
5514     return D3D_OK;
5515 }
5516
5517 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5518 {
5519     return d3d_device7_PreLoad(iface, texture);
5520 }
5521
5522 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5523 {
5524     HRESULT hr;
5525     WORD old_fpucw;
5526
5527     old_fpucw = d3d_fpu_setup();
5528     hr = d3d_device7_PreLoad(iface, texture);
5529     set_fpu_control_word(old_fpucw);
5530
5531     return hr;
5532 }
5533
5534 /*****************************************************************************
5535  * IDirect3DDevice7::ApplyStateBlock
5536  *
5537  * Activates the state stored in a state block handle.
5538  *
5539  * Params:
5540  *  BlockHandle: The stateblock handle to activate
5541  *
5542  * Returns:
5543  *  D3D_OK on success
5544  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5545  *
5546  *****************************************************************************/
5547 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5548 {
5549     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5550     struct wined3d_stateblock *wined3d_sb;
5551
5552     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5553
5554     wined3d_mutex_lock();
5555     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5556     if (!wined3d_sb)
5557     {
5558         WARN("Invalid stateblock handle.\n");
5559         wined3d_mutex_unlock();
5560         return D3DERR_INVALIDSTATEBLOCK;
5561     }
5562
5563     wined3d_stateblock_apply(wined3d_sb);
5564     wined3d_mutex_unlock();
5565
5566     return D3D_OK;
5567 }
5568
5569 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5570 {
5571     return d3d_device7_ApplyStateBlock(iface, stateblock);
5572 }
5573
5574 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5575 {
5576     HRESULT hr;
5577     WORD old_fpucw;
5578
5579     old_fpucw = d3d_fpu_setup();
5580     hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5581     set_fpu_control_word(old_fpucw);
5582
5583     return hr;
5584 }
5585
5586 /*****************************************************************************
5587  * IDirect3DDevice7::CaptureStateBlock
5588  *
5589  * Updates a stateblock's values to the values currently set for the device
5590  *
5591  * Version 7
5592  *
5593  * Params:
5594  *  BlockHandle: Stateblock to update
5595  *
5596  * Returns:
5597  *  D3D_OK on success
5598  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5599  *  See IWineD3DDevice::CaptureStateBlock for more details
5600  *
5601  *****************************************************************************/
5602 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5603 {
5604     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5605     struct wined3d_stateblock *wined3d_sb;
5606
5607     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5608
5609     wined3d_mutex_lock();
5610     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5611     if (!wined3d_sb)
5612     {
5613         WARN("Invalid stateblock handle.\n");
5614         wined3d_mutex_unlock();
5615         return D3DERR_INVALIDSTATEBLOCK;
5616     }
5617
5618     wined3d_stateblock_capture(wined3d_sb);
5619     wined3d_mutex_unlock();
5620
5621     return D3D_OK;
5622 }
5623
5624 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5625 {
5626     return d3d_device7_CaptureStateBlock(iface, stateblock);
5627 }
5628
5629 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5630 {
5631     HRESULT hr;
5632     WORD old_fpucw;
5633
5634     old_fpucw = d3d_fpu_setup();
5635     hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5636     set_fpu_control_word(old_fpucw);
5637
5638     return hr;
5639 }
5640
5641 /*****************************************************************************
5642  * IDirect3DDevice7::DeleteStateBlock
5643  *
5644  * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5645  *
5646  * Version 7
5647  *
5648  * Params:
5649  *  BlockHandle: Stateblock handle to delete
5650  *
5651  * Returns:
5652  *  D3D_OK on success
5653  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5654  *
5655  *****************************************************************************/
5656 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5657 {
5658     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5659     struct wined3d_stateblock *wined3d_sb;
5660     ULONG ref;
5661
5662     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5663
5664     wined3d_mutex_lock();
5665
5666     wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5667     if (!wined3d_sb)
5668     {
5669         WARN("Invalid stateblock handle.\n");
5670         wined3d_mutex_unlock();
5671         return D3DERR_INVALIDSTATEBLOCK;
5672     }
5673
5674     if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5675     {
5676         ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5677     }
5678
5679     wined3d_mutex_unlock();
5680
5681     return D3D_OK;
5682 }
5683
5684 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5685 {
5686     return d3d_device7_DeleteStateBlock(iface, stateblock);
5687 }
5688
5689 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5690 {
5691     HRESULT hr;
5692     WORD old_fpucw;
5693
5694     old_fpucw = d3d_fpu_setup();
5695     hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5696     set_fpu_control_word(old_fpucw);
5697
5698     return hr;
5699 }
5700
5701 /*****************************************************************************
5702  * IDirect3DDevice7::CreateStateBlock
5703  *
5704  * Creates a new state block handle.
5705  *
5706  * Version 7
5707  *
5708  * Params:
5709  *  Type: The state block type
5710  *  BlockHandle: Address to write the created handle to
5711  *
5712  * Returns:
5713  *   D3D_OK on success
5714  *   DDERR_INVALIDPARAMS if BlockHandle is NULL
5715  *
5716  *****************************************************************************/
5717 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
5718         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5719 {
5720     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5721     struct wined3d_stateblock *wined3d_sb;
5722     HRESULT hr;
5723     DWORD h;
5724
5725     TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
5726
5727     if (!stateblock)
5728         return DDERR_INVALIDPARAMS;
5729
5730     if (type != D3DSBT_ALL
5731             && type != D3DSBT_PIXELSTATE
5732             && type != D3DSBT_VERTEXSTATE)
5733     {
5734         WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5735         return DDERR_INVALIDPARAMS;
5736     }
5737
5738     wined3d_mutex_lock();
5739
5740     /* The D3DSTATEBLOCKTYPE enum is fine here. */
5741     hr = wined3d_stateblock_create(device->wined3d_device, type, &wined3d_sb);
5742     if (FAILED(hr))
5743     {
5744         WARN("Failed to create stateblock, hr %#x.\n", hr);
5745         wined3d_mutex_unlock();
5746         return hr_ddraw_from_wined3d(hr);
5747     }
5748
5749     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5750     if (h == DDRAW_INVALID_HANDLE)
5751     {
5752         ERR("Failed to allocate stateblock handle.\n");
5753         wined3d_stateblock_decref(wined3d_sb);
5754         wined3d_mutex_unlock();
5755         return DDERR_OUTOFMEMORY;
5756     }
5757
5758     *stateblock = h + 1;
5759     wined3d_mutex_unlock();
5760
5761     return hr_ddraw_from_wined3d(hr);
5762 }
5763
5764 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5765         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5766 {
5767     return d3d_device7_CreateStateBlock(iface, type, stateblock);
5768 }
5769
5770 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5771         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5772 {
5773     HRESULT hr;
5774     WORD old_fpucw;
5775
5776     old_fpucw = d3d_fpu_setup();
5777     hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
5778     set_fpu_control_word(old_fpucw);
5779
5780     return hr;
5781 }
5782
5783 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
5784 {
5785     struct ddraw_surface *src_level, *dest_level;
5786     IDirectDrawSurface7 *temp;
5787     DDSURFACEDESC2 ddsd;
5788     BOOL levelFound; /* at least one suitable sublevel in dest found */
5789
5790     /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
5791      * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
5792      * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
5793      */
5794     levelFound = FALSE;
5795
5796     src_level = src;
5797     dest_level = dest;
5798
5799     for (;src_level && dest_level;)
5800     {
5801         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5802             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5803         {
5804             levelFound = TRUE;
5805
5806             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5807             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5808             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5809
5810             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5811
5812             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5813         }
5814
5815         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5816         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5817         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5818
5819         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5820
5821         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5822     }
5823
5824     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5825     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5826
5827     return !dest_level && levelFound;
5828 }
5829
5830 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dest,
5831         struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
5832 {
5833     struct ddraw_surface *src_level, *dest_level;
5834     IDirectDrawSurface7 *temp;
5835     DDSURFACEDESC2 ddsd;
5836     POINT point;
5837     RECT src_rect;
5838     HRESULT hr;
5839     IDirectDrawPalette *pal = NULL, *pal_src = NULL;
5840     DWORD ckeyflag;
5841     DDCOLORKEY ddckey;
5842
5843     /* Copy palette, if possible. */
5844     IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
5845     IDirectDrawSurface7_GetPalette(&dest->IDirectDrawSurface7_iface, &pal);
5846
5847     if (pal_src != NULL && pal != NULL)
5848     {
5849         PALETTEENTRY palent[256];
5850
5851         IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
5852         IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
5853     }
5854
5855     if (pal) IDirectDrawPalette_Release(pal);
5856     if (pal_src) IDirectDrawPalette_Release(pal_src);
5857
5858     /* Copy colorkeys, if present. */
5859     for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
5860     {
5861         hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5862
5863         if (SUCCEEDED(hr))
5864         {
5865             IDirectDrawSurface7_SetColorKey(&dest->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5866         }
5867     }
5868
5869     src_level = src;
5870     dest_level = dest;
5871
5872     point = *DestPoint;
5873     src_rect = *SrcRect;
5874
5875     for (;src_level && dest_level;)
5876     {
5877         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5878             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5879         {
5880             UINT src_w = src_rect.right - src_rect.left;
5881             UINT src_h = src_rect.bottom - src_rect.top;
5882             RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
5883
5884             if (FAILED(hr = wined3d_surface_blt(dest_level->wined3d_surface, &dst_rect,
5885                     src_level->wined3d_surface, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
5886                 ERR("Blit failed, hr %#x.\n", hr);
5887
5888             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5889             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5890             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5891
5892             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5893
5894             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5895         }
5896
5897         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5898         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5899         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5900
5901         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5902
5903         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5904
5905         point.x /= 2;
5906         point.y /= 2;
5907
5908         src_rect.top /= 2;
5909         src_rect.left /= 2;
5910         src_rect.right = (src_rect.right + 1) / 2;
5911         src_rect.bottom = (src_rect.bottom + 1) / 2;
5912     }
5913
5914     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5915     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5916 }
5917
5918 /*****************************************************************************
5919  * IDirect3DDevice7::Load
5920  *
5921  * Loads a rectangular area from the source into the destination texture.
5922  * It can also copy the source to the faces of a cubic environment map
5923  *
5924  * Version 7
5925  *
5926  * Params:
5927  *  DestTex: Destination texture
5928  *  DestPoint: Point in the destination where the source image should be
5929  *             written to
5930  *  SrcTex: Source texture
5931  *  SrcRect: Source rectangle
5932  *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
5933  *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
5934  *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
5935  *
5936  * Returns:
5937  *  D3D_OK on success
5938  *  DDERR_INVALIDPARAMS if DestTex or SrcTex are NULL, broken coordinates or anything unexpected.
5939  *
5940  *
5941  *****************************************************************************/
5942 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
5943         IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
5944 {
5945     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5946     struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
5947     struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
5948     POINT destpoint;
5949     RECT srcrect;
5950
5951     TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
5952             iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
5953
5954     if( (!src) || (!dest) )
5955         return DDERR_INVALIDPARAMS;
5956
5957     wined3d_mutex_lock();
5958
5959     if (!src_rect)
5960     {
5961         srcrect.left = srcrect.top = 0;
5962         srcrect.right = src->surface_desc.dwWidth;
5963         srcrect.bottom = src->surface_desc.dwHeight;
5964     }
5965     else
5966         srcrect = *src_rect;
5967
5968     if (!dst_pos)
5969         destpoint.x = destpoint.y = 0;
5970     else
5971         destpoint = *dst_pos;
5972
5973     /* Check bad dimensions. dst_pos is validated against src, not dest, because
5974      * destination can be a subset of mip levels, in which case actual coordinates used
5975      * for it may be divided. If any dimension of dest is larger than source, it can't be
5976      * mip level subset, so an error can be returned early.
5977      */
5978     if (srcrect.left >= srcrect.right || srcrect.top >= srcrect.bottom ||
5979         srcrect.right > src->surface_desc.dwWidth ||
5980         srcrect.bottom > src->surface_desc.dwHeight ||
5981         destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
5982         destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
5983         dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
5984         dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
5985     {
5986         wined3d_mutex_unlock();
5987         return DDERR_INVALIDPARAMS;
5988     }
5989
5990     /* Must be top level surfaces. */
5991     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
5992         dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
5993     {
5994         wined3d_mutex_unlock();
5995         return DDERR_INVALIDPARAMS;
5996     }
5997
5998     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
5999     {
6000         struct ddraw_surface *src_face, *dest_face;
6001         DWORD src_face_flag, dest_face_flag;
6002         IDirectDrawSurface7 *temp;
6003         DDSURFACEDESC2 ddsd;
6004         int i;
6005
6006         if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6007         {
6008             wined3d_mutex_unlock();
6009             return DDERR_INVALIDPARAMS;
6010         }
6011
6012         /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6013          * time it's actual surface loading. */
6014         for (i = 0; i < 2; i++)
6015         {
6016             dest_face = dest;
6017             src_face = src;
6018
6019             for (;dest_face && src_face;)
6020             {
6021                 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6022                 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6023
6024                 if (src_face_flag == dest_face_flag)
6025                 {
6026                     if (i == 0)
6027                     {
6028                         /* Destination mip levels must be subset of source mip levels. */
6029                         if (!is_mip_level_subset(dest_face, src_face))
6030                         {
6031                             wined3d_mutex_unlock();
6032                             return DDERR_INVALIDPARAMS;
6033                         }
6034                     }
6035                     else if (flags & dest_face_flag)
6036                     {
6037                         copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
6038                     }
6039
6040                     if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6041                     {
6042                         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6043                         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6044                         IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6045
6046                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6047
6048                         src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6049                     }
6050                     else
6051                     {
6052                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6053
6054                         src_face = NULL;
6055                     }
6056                 }
6057
6058                 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6059                 {
6060                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6061                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6062                     IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6063
6064                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6065
6066                     dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6067                 }
6068                 else
6069                 {
6070                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6071
6072                     dest_face = NULL;
6073                 }
6074             }
6075
6076             if (i == 0)
6077             {
6078                 /* Native returns error if src faces are not subset of dest faces. */
6079                 if (src_face)
6080                 {
6081                     wined3d_mutex_unlock();
6082                     return DDERR_INVALIDPARAMS;
6083                 }
6084             }
6085         }
6086
6087         wined3d_mutex_unlock();
6088         return D3D_OK;
6089     }
6090     else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6091     {
6092         wined3d_mutex_unlock();
6093         return DDERR_INVALIDPARAMS;
6094     }
6095
6096     /* Handle non cube map textures. */
6097
6098     /* Destination mip levels must be subset of source mip levels. */
6099     if (!is_mip_level_subset(dest, src))
6100     {
6101         wined3d_mutex_unlock();
6102         return DDERR_INVALIDPARAMS;
6103     }
6104
6105     copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
6106
6107     wined3d_mutex_unlock();
6108
6109     return D3D_OK;
6110 }
6111
6112 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6113         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6114 {
6115     return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6116 }
6117
6118 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6119         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6120 {
6121     HRESULT hr;
6122     WORD old_fpucw;
6123
6124     old_fpucw = d3d_fpu_setup();
6125     hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6126     set_fpu_control_word(old_fpucw);
6127
6128     return hr;
6129 }
6130
6131 /*****************************************************************************
6132  * IDirect3DDevice7::LightEnable
6133  *
6134  * Enables or disables a light
6135  *
6136  * Version 7, IDirect3DLight uses this method too.
6137  *
6138  * Params:
6139  *  LightIndex: The index of the light to enable / disable
6140  *  Enable: Enable or disable the light
6141  *
6142  * Returns:
6143  *  D3D_OK on success
6144  *  For more details, see IWineD3DDevice::SetLightEnable
6145  *
6146  *****************************************************************************/
6147 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6148 {
6149     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6150     HRESULT hr;
6151
6152     TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
6153
6154     wined3d_mutex_lock();
6155     hr = wined3d_device_set_light_enable(device->wined3d_device, light_idx, enabled);
6156     wined3d_mutex_unlock();
6157
6158     return hr_ddraw_from_wined3d(hr);
6159 }
6160
6161 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6162 {
6163     return d3d_device7_LightEnable(iface, light_idx, enabled);
6164 }
6165
6166 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6167 {
6168     HRESULT hr;
6169     WORD old_fpucw;
6170
6171     old_fpucw = d3d_fpu_setup();
6172     hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6173     set_fpu_control_word(old_fpucw);
6174
6175     return hr;
6176 }
6177
6178 /*****************************************************************************
6179  * IDirect3DDevice7::GetLightEnable
6180  *
6181  * Retrieves if the light with the given index is enabled or not
6182  *
6183  * Version 7
6184  *
6185  * Params:
6186  *  LightIndex: Index of desired light
6187  *  Enable: Pointer to a BOOL which contains the result
6188  *
6189  * Returns:
6190  *  D3D_OK on success
6191  *  DDERR_INVALIDPARAMS if Enable is NULL
6192  *  See IWineD3DDevice::GetLightEnable for more details
6193  *
6194  *****************************************************************************/
6195 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6196 {
6197     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6198     HRESULT hr;
6199
6200     TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6201
6202     if (!enabled)
6203         return DDERR_INVALIDPARAMS;
6204
6205     wined3d_mutex_lock();
6206     hr = wined3d_device_get_light_enable(device->wined3d_device, light_idx, enabled);
6207     wined3d_mutex_unlock();
6208
6209     return hr_ddraw_from_wined3d(hr);
6210 }
6211
6212 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6213 {
6214     return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6215 }
6216
6217 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6218 {
6219     HRESULT hr;
6220     WORD old_fpucw;
6221
6222     old_fpucw = d3d_fpu_setup();
6223     hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6224     set_fpu_control_word(old_fpucw);
6225
6226     return hr;
6227 }
6228
6229 /*****************************************************************************
6230  * IDirect3DDevice7::SetClipPlane
6231  *
6232  * Sets custom clipping plane
6233  *
6234  * Version 7
6235  *
6236  * Params:
6237  *  Index: The index of the clipping plane
6238  *  PlaneEquation: An equation defining the clipping plane
6239  *
6240  * Returns:
6241  *  D3D_OK on success
6242  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6243  *  See IWineD3DDevice::SetClipPlane for more details
6244  *
6245  *****************************************************************************/
6246 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6247 {
6248     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6249     HRESULT hr;
6250
6251     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6252
6253     if (!plane)
6254         return DDERR_INVALIDPARAMS;
6255
6256     wined3d_mutex_lock();
6257     hr = wined3d_device_set_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6258     wined3d_mutex_unlock();
6259
6260     return hr;
6261 }
6262
6263 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6264 {
6265     return d3d_device7_SetClipPlane(iface, idx, plane);
6266 }
6267
6268 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6269 {
6270     HRESULT hr;
6271     WORD old_fpucw;
6272
6273     old_fpucw = d3d_fpu_setup();
6274     hr = d3d_device7_SetClipPlane(iface, idx, plane);
6275     set_fpu_control_word(old_fpucw);
6276
6277     return hr;
6278 }
6279
6280 /*****************************************************************************
6281  * IDirect3DDevice7::GetClipPlane
6282  *
6283  * Returns the clipping plane with a specific index
6284  *
6285  * Params:
6286  *  Index: The index of the desired plane
6287  *  PlaneEquation: Address to store the plane equation to
6288  *
6289  * Returns:
6290  *  D3D_OK on success
6291  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6292  *  See IWineD3DDevice::GetClipPlane for more details
6293  *
6294  *****************************************************************************/
6295 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6296 {
6297     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6298     HRESULT hr;
6299
6300     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6301
6302     if (!plane)
6303         return DDERR_INVALIDPARAMS;
6304
6305     wined3d_mutex_lock();
6306     hr = wined3d_device_get_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6307     wined3d_mutex_unlock();
6308
6309     return hr;
6310 }
6311
6312 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6313 {
6314     return d3d_device7_GetClipPlane(iface, idx, plane);
6315 }
6316
6317 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6318 {
6319     HRESULT hr;
6320     WORD old_fpucw;
6321
6322     old_fpucw = d3d_fpu_setup();
6323     hr = d3d_device7_GetClipPlane(iface, idx, plane);
6324     set_fpu_control_word(old_fpucw);
6325
6326     return hr;
6327 }
6328
6329 /*****************************************************************************
6330  * IDirect3DDevice7::GetInfo
6331  *
6332  * Retrieves some information about the device. The DirectX sdk says that
6333  * this version returns S_FALSE for all retail builds of DirectX, that's what
6334  * this implementation does.
6335  *
6336  * Params:
6337  *  DevInfoID: Information type requested
6338  *  DevInfoStruct: Pointer to a structure to store the info to
6339  *  Size: Size of the structure
6340  *
6341  * Returns:
6342  *  S_FALSE, because it's a non-debug driver
6343  *
6344  *****************************************************************************/
6345 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6346 {
6347     TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6348             iface, info_id, info, info_size);
6349
6350     if (TRACE_ON(ddraw))
6351     {
6352         TRACE(" info requested : ");
6353         switch (info_id)
6354         {
6355             case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6356             case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6357             case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6358             default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6359         }
6360     }
6361
6362     return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6363 }
6364
6365 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6366  * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6367  * are not duplicated.
6368
6369  * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6370  * has already been setup for optimal d3d operation.
6371
6372  * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6373  * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6374  * by Sacrifice (game). */
6375 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6376 {
6377     /*** IUnknown Methods ***/
6378     d3d_device7_QueryInterface,
6379     d3d_device7_AddRef,
6380     d3d_device7_Release,
6381     /*** IDirect3DDevice7 ***/
6382     d3d_device7_GetCaps_FPUSetup,
6383     d3d_device7_EnumTextureFormats_FPUSetup,
6384     d3d_device7_BeginScene_FPUSetup,
6385     d3d_device7_EndScene_FPUSetup,
6386     d3d_device7_GetDirect3D,
6387     d3d_device7_SetRenderTarget_FPUSetup,
6388     d3d_device7_GetRenderTarget,
6389     d3d_device7_Clear_FPUSetup,
6390     d3d_device7_SetTransform_FPUSetup,
6391     d3d_device7_GetTransform_FPUSetup,
6392     d3d_device7_SetViewport_FPUSetup,
6393     d3d_device7_MultiplyTransform_FPUSetup,
6394     d3d_device7_GetViewport_FPUSetup,
6395     d3d_device7_SetMaterial_FPUSetup,
6396     d3d_device7_GetMaterial_FPUSetup,
6397     d3d_device7_SetLight_FPUSetup,
6398     d3d_device7_GetLight_FPUSetup,
6399     d3d_device7_SetRenderState_FPUSetup,
6400     d3d_device7_GetRenderState_FPUSetup,
6401     d3d_device7_BeginStateBlock_FPUSetup,
6402     d3d_device7_EndStateBlock_FPUSetup,
6403     d3d_device7_PreLoad_FPUSetup,
6404     d3d_device7_DrawPrimitive_FPUSetup,
6405     d3d_device7_DrawIndexedPrimitive_FPUSetup,
6406     d3d_device7_SetClipStatus,
6407     d3d_device7_GetClipStatus,
6408     d3d_device7_DrawPrimitiveStrided_FPUSetup,
6409     d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6410     d3d_device7_DrawPrimitiveVB_FPUSetup,
6411     d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6412     d3d_device7_ComputeSphereVisibility,
6413     d3d_device7_GetTexture_FPUSetup,
6414     d3d_device7_SetTexture_FPUSetup,
6415     d3d_device7_GetTextureStageState_FPUSetup,
6416     d3d_device7_SetTextureStageState_FPUSetup,
6417     d3d_device7_ValidateDevice_FPUSetup,
6418     d3d_device7_ApplyStateBlock_FPUSetup,
6419     d3d_device7_CaptureStateBlock_FPUSetup,
6420     d3d_device7_DeleteStateBlock_FPUSetup,
6421     d3d_device7_CreateStateBlock_FPUSetup,
6422     d3d_device7_Load_FPUSetup,
6423     d3d_device7_LightEnable_FPUSetup,
6424     d3d_device7_GetLightEnable_FPUSetup,
6425     d3d_device7_SetClipPlane_FPUSetup,
6426     d3d_device7_GetClipPlane_FPUSetup,
6427     d3d_device7_GetInfo
6428 };
6429
6430 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6431 {
6432     /*** IUnknown Methods ***/
6433     d3d_device7_QueryInterface,
6434     d3d_device7_AddRef,
6435     d3d_device7_Release,
6436     /*** IDirect3DDevice7 ***/
6437     d3d_device7_GetCaps_FPUPreserve,
6438     d3d_device7_EnumTextureFormats_FPUPreserve,
6439     d3d_device7_BeginScene_FPUPreserve,
6440     d3d_device7_EndScene_FPUPreserve,
6441     d3d_device7_GetDirect3D,
6442     d3d_device7_SetRenderTarget_FPUPreserve,
6443     d3d_device7_GetRenderTarget,
6444     d3d_device7_Clear_FPUPreserve,
6445     d3d_device7_SetTransform_FPUPreserve,
6446     d3d_device7_GetTransform_FPUPreserve,
6447     d3d_device7_SetViewport_FPUPreserve,
6448     d3d_device7_MultiplyTransform_FPUPreserve,
6449     d3d_device7_GetViewport_FPUPreserve,
6450     d3d_device7_SetMaterial_FPUPreserve,
6451     d3d_device7_GetMaterial_FPUPreserve,
6452     d3d_device7_SetLight_FPUPreserve,
6453     d3d_device7_GetLight_FPUPreserve,
6454     d3d_device7_SetRenderState_FPUPreserve,
6455     d3d_device7_GetRenderState_FPUPreserve,
6456     d3d_device7_BeginStateBlock_FPUPreserve,
6457     d3d_device7_EndStateBlock_FPUPreserve,
6458     d3d_device7_PreLoad_FPUPreserve,
6459     d3d_device7_DrawPrimitive_FPUPreserve,
6460     d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6461     d3d_device7_SetClipStatus,
6462     d3d_device7_GetClipStatus,
6463     d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6464     d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6465     d3d_device7_DrawPrimitiveVB_FPUPreserve,
6466     d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6467     d3d_device7_ComputeSphereVisibility,
6468     d3d_device7_GetTexture_FPUPreserve,
6469     d3d_device7_SetTexture_FPUPreserve,
6470     d3d_device7_GetTextureStageState_FPUPreserve,
6471     d3d_device7_SetTextureStageState_FPUPreserve,
6472     d3d_device7_ValidateDevice_FPUPreserve,
6473     d3d_device7_ApplyStateBlock_FPUPreserve,
6474     d3d_device7_CaptureStateBlock_FPUPreserve,
6475     d3d_device7_DeleteStateBlock_FPUPreserve,
6476     d3d_device7_CreateStateBlock_FPUPreserve,
6477     d3d_device7_Load_FPUPreserve,
6478     d3d_device7_LightEnable_FPUPreserve,
6479     d3d_device7_GetLightEnable_FPUPreserve,
6480     d3d_device7_SetClipPlane_FPUPreserve,
6481     d3d_device7_GetClipPlane_FPUPreserve,
6482     d3d_device7_GetInfo
6483 };
6484
6485 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6486 {
6487     /*** IUnknown Methods ***/
6488     d3d_device3_QueryInterface,
6489     d3d_device3_AddRef,
6490     d3d_device3_Release,
6491     /*** IDirect3DDevice3 ***/
6492     d3d_device3_GetCaps,
6493     d3d_device3_GetStats,
6494     d3d_device3_AddViewport,
6495     d3d_device3_DeleteViewport,
6496     d3d_device3_NextViewport,
6497     d3d_device3_EnumTextureFormats,
6498     d3d_device3_BeginScene,
6499     d3d_device3_EndScene,
6500     d3d_device3_GetDirect3D,
6501     d3d_device3_SetCurrentViewport,
6502     d3d_device3_GetCurrentViewport,
6503     d3d_device3_SetRenderTarget,
6504     d3d_device3_GetRenderTarget,
6505     d3d_device3_Begin,
6506     d3d_device3_BeginIndexed,
6507     d3d_device3_Vertex,
6508     d3d_device3_Index,
6509     d3d_device3_End,
6510     d3d_device3_GetRenderState,
6511     d3d_device3_SetRenderState,
6512     d3d_device3_GetLightState,
6513     d3d_device3_SetLightState,
6514     d3d_device3_SetTransform,
6515     d3d_device3_GetTransform,
6516     d3d_device3_MultiplyTransform,
6517     d3d_device3_DrawPrimitive,
6518     d3d_device3_DrawIndexedPrimitive,
6519     d3d_device3_SetClipStatus,
6520     d3d_device3_GetClipStatus,
6521     d3d_device3_DrawPrimitiveStrided,
6522     d3d_device3_DrawIndexedPrimitiveStrided,
6523     d3d_device3_DrawPrimitiveVB,
6524     d3d_device3_DrawIndexedPrimitiveVB,
6525     d3d_device3_ComputeSphereVisibility,
6526     d3d_device3_GetTexture,
6527     d3d_device3_SetTexture,
6528     d3d_device3_GetTextureStageState,
6529     d3d_device3_SetTextureStageState,
6530     d3d_device3_ValidateDevice
6531 };
6532
6533 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6534 {
6535     /*** IUnknown Methods ***/
6536     d3d_device2_QueryInterface,
6537     d3d_device2_AddRef,
6538     d3d_device2_Release,
6539     /*** IDirect3DDevice2 ***/
6540     d3d_device2_GetCaps,
6541     d3d_device2_SwapTextureHandles,
6542     d3d_device2_GetStats,
6543     d3d_device2_AddViewport,
6544     d3d_device2_DeleteViewport,
6545     d3d_device2_NextViewport,
6546     d3d_device2_EnumTextureFormats,
6547     d3d_device2_BeginScene,
6548     d3d_device2_EndScene,
6549     d3d_device2_GetDirect3D,
6550     d3d_device2_SetCurrentViewport,
6551     d3d_device2_GetCurrentViewport,
6552     d3d_device2_SetRenderTarget,
6553     d3d_device2_GetRenderTarget,
6554     d3d_device2_Begin,
6555     d3d_device2_BeginIndexed,
6556     d3d_device2_Vertex,
6557     d3d_device2_Index,
6558     d3d_device2_End,
6559     d3d_device2_GetRenderState,
6560     d3d_device2_SetRenderState,
6561     d3d_device2_GetLightState,
6562     d3d_device2_SetLightState,
6563     d3d_device2_SetTransform,
6564     d3d_device2_GetTransform,
6565     d3d_device2_MultiplyTransform,
6566     d3d_device2_DrawPrimitive,
6567     d3d_device2_DrawIndexedPrimitive,
6568     d3d_device2_SetClipStatus,
6569     d3d_device2_GetClipStatus
6570 };
6571
6572 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6573 {
6574     /*** IUnknown Methods ***/
6575     d3d_device1_QueryInterface,
6576     d3d_device1_AddRef,
6577     d3d_device1_Release,
6578     /*** IDirect3DDevice1 ***/
6579     d3d_device1_Initialize,
6580     d3d_device1_GetCaps,
6581     d3d_device1_SwapTextureHandles,
6582     d3d_device1_CreateExecuteBuffer,
6583     d3d_device1_GetStats,
6584     d3d_device1_Execute,
6585     d3d_device1_AddViewport,
6586     d3d_device1_DeleteViewport,
6587     d3d_device1_NextViewport,
6588     d3d_device1_Pick,
6589     d3d_device1_GetPickRecords,
6590     d3d_device1_EnumTextureFormats,
6591     d3d_device1_CreateMatrix,
6592     d3d_device1_SetMatrix,
6593     d3d_device1_GetMatrix,
6594     d3d_device1_DeleteMatrix,
6595     d3d_device1_BeginScene,
6596     d3d_device1_EndScene,
6597     d3d_device1_GetDirect3D
6598 };
6599
6600 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6601 {
6602     d3d_device_inner_QueryInterface,
6603     d3d_device_inner_AddRef,
6604     d3d_device_inner_Release,
6605 };
6606
6607 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6608 {
6609     if (!iface) return NULL;
6610     assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6611     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6612 }
6613
6614 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6615 {
6616     if (!iface) return NULL;
6617     assert(iface->lpVtbl == &d3d_device3_vtbl);
6618     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6619 }
6620
6621 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6622 {
6623     if (!iface) return NULL;
6624     assert(iface->lpVtbl == &d3d_device2_vtbl);
6625     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6626 }
6627
6628 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6629 {
6630     if (!iface) return NULL;
6631     assert(iface->lpVtbl == &d3d_device1_vtbl);
6632     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6633 }
6634
6635 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6636 {
6637     IDirectDrawSurface7 *depthStencil = NULL;
6638     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
6639     struct ddraw_surface *dsi;
6640
6641     IDirectDrawSurface7_GetAttachedSurface(&device->target->IDirectDrawSurface7_iface, &depthcaps, &depthStencil);
6642     if (!depthStencil)
6643     {
6644         TRACE("Setting wined3d depth stencil to NULL\n");
6645         wined3d_device_set_depth_stencil(device->wined3d_device, NULL);
6646         return WINED3D_ZB_FALSE;
6647     }
6648
6649     dsi = impl_from_IDirectDrawSurface7(depthStencil);
6650     TRACE("Setting wined3d depth stencil to %p (wined3d %p)\n", dsi, dsi->wined3d_surface);
6651     wined3d_device_set_depth_stencil(device->wined3d_device, dsi->wined3d_surface);
6652
6653     IDirectDrawSurface7_Release(depthStencil);
6654     return WINED3D_ZB_TRUE;
6655 }
6656
6657 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
6658         struct ddraw_surface *target, UINT version, IUnknown *outer_unknown)
6659 {
6660     static const D3DMATRIX ident =
6661     {
6662         1.0f, 0.0f, 0.0f, 0.0f,
6663         0.0f, 1.0f, 0.0f, 0.0f,
6664         0.0f, 0.0f, 1.0f, 0.0f,
6665         0.0f, 0.0f, 0.0f, 1.0f,
6666     };
6667     HRESULT hr;
6668
6669     if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6670         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6671     else
6672         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6673
6674     device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6675     device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6676     device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6677     device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
6678     device->ref = 1;
6679     device->version = version;
6680
6681     if (outer_unknown)
6682         device->outer_unknown = outer_unknown;
6683     else
6684         device->outer_unknown = &device->IUnknown_inner;
6685
6686     device->ddraw = ddraw;
6687     device->target = target;
6688     list_init(&device->viewport_list);
6689
6690     if (!ddraw_handle_table_init(&device->handle_table, 64))
6691     {
6692         ERR("Failed to initialize handle table.\n");
6693         return DDERR_OUTOFMEMORY;
6694     }
6695
6696     device->legacyTextureBlending = FALSE;
6697     device->legacy_projection = ident;
6698     device->legacy_clipspace = ident;
6699
6700     /* This is for convenience. */
6701     device->wined3d_device = ddraw->wined3d_device;
6702     wined3d_device_incref(ddraw->wined3d_device);
6703
6704     /* Render to the back buffer */
6705     hr = wined3d_device_set_render_target(ddraw->wined3d_device, 0, target->wined3d_surface, TRUE);
6706     if (FAILED(hr))
6707     {
6708         ERR("Failed to set render target, hr %#x.\n", hr);
6709         ddraw_handle_table_destroy(&device->handle_table);
6710         return hr;
6711     }
6712
6713     /* FIXME: This is broken. The target AddRef() makes some sense, because
6714      * we store a pointer during initialization, but then that's also where
6715      * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */
6716     /* AddRef the render target. Also AddRef the render target from ddraw,
6717      * because if it is released before the app releases the D3D device, the
6718      * D3D capabilities of wined3d will be uninitialized, which has bad effects.
6719      *
6720      * In most cases, those surfaces are the same anyway, but this will simply
6721      * add another ref which is released when the device is destroyed. */
6722     if (version != 1)
6723         IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
6724
6725     ddraw->d3ddevice = device;
6726
6727     wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_ZENABLE,
6728             d3d_device_update_depth_stencil(device));
6729     if (version == 1) /* Color keying is initially enabled for version 1 devices. */
6730         wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_COLORKEYENABLE, TRUE);
6731
6732     return D3D_OK;
6733 }
6734
6735 HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
6736         UINT version, struct d3d_device **device, IUnknown *outer_unknown)
6737 {
6738     struct d3d_device *object;
6739     HRESULT hr;
6740
6741     TRACE("ddraw %p, target %p, version %u, device %p, outer_unknown %p.\n",
6742             ddraw, target, version, device, outer_unknown);
6743
6744     if (DefaultSurfaceType != DDRAW_SURFACE_TYPE_OPENGL)
6745     {
6746         ERR_(winediag)("The application wants to create a Direct3D device, "
6747                 "but the current DirectDrawRenderer does not support this.\n");
6748
6749         return DDERR_NO3D;
6750     }
6751
6752     if (ddraw->d3ddevice)
6753     {
6754         FIXME("Only one Direct3D device per DirectDraw object supported.\n");
6755         return DDERR_INVALIDPARAMS;
6756     }
6757
6758     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
6759     if (!object)
6760     {
6761         ERR("Failed to allocate device memory.\n");
6762         return DDERR_OUTOFMEMORY;
6763     }
6764
6765     hr = d3d_device_init(object, ddraw, target, version, outer_unknown);
6766     if (FAILED(hr))
6767     {
6768         WARN("Failed to initialize device, hr %#x.\n", hr);
6769         HeapFree(GetProcessHeap(), 0, object);
6770         return hr;
6771     }
6772
6773     TRACE("Created device %p.\n", object);
6774     *device = object;
6775
6776     return D3D_OK;
6777 }