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