wined3d: wined3d_device_set_texture_stage_state() never fails.
[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         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     HRESULT hr;
2365
2366     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2367
2368     switch (state)
2369     {
2370         case D3DRENDERSTATE_TEXTUREHANDLE:
2371         {
2372             /* This state is wrapped to SetTexture in SetRenderState, so
2373              * it has to be wrapped to GetTexture here. */
2374             struct wined3d_texture *tex = NULL;
2375             *value = 0;
2376
2377             wined3d_mutex_lock();
2378             hr = wined3d_device_get_texture(device->wined3d_device, 0, &tex);
2379             if (SUCCEEDED(hr) && tex)
2380             {
2381                 /* The parent of the texture is the IDirectDrawSurface7
2382                  * interface of the ddraw surface. */
2383                 struct ddraw_surface *parent = wined3d_texture_get_parent(tex);
2384                 if (parent)
2385                     *value = parent->Handle;
2386                 wined3d_texture_decref(tex);
2387             }
2388             wined3d_mutex_unlock();
2389
2390             return hr;
2391         }
2392
2393         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2394         {
2395             /* D3DRENDERSTATE_TEXTUREMAPBLEND is mapped to texture state stages in SetRenderState; reverse
2396                the mapping to get the value. */
2397             DWORD colorop, colorarg1, colorarg2;
2398             DWORD alphaop, alphaarg1, alphaarg2;
2399
2400             wined3d_mutex_lock();
2401
2402             device->legacyTextureBlending = TRUE;
2403
2404             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_OP, &colorop);
2405             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG1, &colorarg1);
2406             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_COLOR_ARG2, &colorarg2);
2407             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_OP, &alphaop);
2408             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG1, &alphaarg1);
2409             wined3d_device_get_texture_stage_state(device->wined3d_device, 0, WINED3D_TSS_ALPHA_ARG2, &alphaarg2);
2410
2411             if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
2412                     && alphaop == WINED3D_TOP_SELECT_ARG1 && alphaarg1 == WINED3DTA_TEXTURE)
2413                 *value = D3DTBLEND_DECAL;
2414             else if (colorop == WINED3D_TOP_SELECT_ARG1 && colorarg1 == WINED3DTA_TEXTURE
2415                     && alphaop == WINED3D_TOP_MODULATE
2416                     && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2417                 *value = D3DTBLEND_DECALALPHA;
2418             else if (colorop == WINED3D_TOP_MODULATE
2419                     && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
2420                     && alphaop == WINED3D_TOP_MODULATE
2421                     && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT)
2422                 *value = D3DTBLEND_MODULATEALPHA;
2423             else
2424             {
2425                 struct wined3d_texture *tex = NULL;
2426                 HRESULT hr;
2427                 BOOL tex_alpha = FALSE;
2428                 DDPIXELFORMAT ddfmt;
2429
2430                 hr = wined3d_device_get_texture(device->wined3d_device, 0, &tex);
2431
2432                 if(hr == WINED3D_OK && tex)
2433                 {
2434                     struct wined3d_resource *sub_resource;
2435
2436                     if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2437                     {
2438                         struct wined3d_resource_desc desc;
2439
2440                         wined3d_resource_get_desc(sub_resource, &desc);
2441                         ddfmt.dwSize = sizeof(ddfmt);
2442                         PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2443                         if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2444                     }
2445
2446                     wined3d_texture_decref(tex);
2447                 }
2448
2449                 if (!(colorop == WINED3D_TOP_MODULATE
2450                         && colorarg1 == WINED3DTA_TEXTURE && colorarg2 == WINED3DTA_CURRENT
2451                         && alphaop == (tex_alpha ? WINED3D_TOP_SELECT_ARG1 : WINED3D_TOP_SELECT_ARG2)
2452                         && alphaarg1 == WINED3DTA_TEXTURE && alphaarg2 == WINED3DTA_CURRENT))
2453                     ERR("Unexpected texture stage state setup, returning D3DTBLEND_MODULATE - likely erroneous.\n");
2454
2455                 *value = D3DTBLEND_MODULATE;
2456             }
2457
2458             wined3d_mutex_unlock();
2459
2460             return D3D_OK;
2461         }
2462
2463         default:
2464             return IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, state, value);
2465     }
2466 }
2467
2468 static HRESULT WINAPI d3d_device2_GetRenderState(IDirect3DDevice2 *iface,
2469         D3DRENDERSTATETYPE state, DWORD *value)
2470 {
2471     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2472
2473     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2474
2475     return IDirect3DDevice3_GetRenderState(&device->IDirect3DDevice3_iface, state, value);
2476 }
2477
2478 /*****************************************************************************
2479  * IDirect3DDevice7::SetRenderState
2480  *
2481  * Sets a render state. The possible render states are defined in
2482  * include/d3dtypes.h
2483  *
2484  * Version 2, 3 and 7
2485  *
2486  * Params:
2487  *  RenderStateType: State to set
2488  *  Value: Value to assign to that state
2489  *
2490  * Returns:
2491  *  D3D_OK on success,
2492  *  for details see IWineD3DDevice::SetRenderState
2493  *
2494  *****************************************************************************/
2495 static HRESULT d3d_device7_SetRenderState(IDirect3DDevice7 *iface,
2496         D3DRENDERSTATETYPE state, DWORD value)
2497 {
2498     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
2499     HRESULT hr = D3D_OK;
2500
2501     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2502
2503     wined3d_mutex_lock();
2504     /* Some render states need special care */
2505     switch (state)
2506     {
2507         /*
2508          * The ddraw texture filter mapping works like this:
2509          *     D3DFILTER_NEAREST            Point min/mag, no mip
2510          *     D3DFILTER_MIPNEAREST         Point min/mag, point mip
2511          *     D3DFILTER_LINEARMIPNEAREST:  Point min/mag, linear mip
2512          *
2513          *     D3DFILTER_LINEAR             Linear min/mag, no mip
2514          *     D3DFILTER_MIPLINEAR          Linear min/mag, point mip
2515          *     D3DFILTER_LINEARMIPLINEAR    Linear min/mag, linear mip
2516          *
2517          * This is the opposite of the GL naming convention,
2518          * D3DFILTER_LINEARMIPNEAREST corresponds to GL_NEAREST_MIPMAP_LINEAR.
2519          */
2520         case D3DRENDERSTATE_TEXTUREMAG:
2521         {
2522             enum wined3d_texture_filter_type tex_mag;
2523
2524             switch (value)
2525             {
2526                 case D3DFILTER_NEAREST:
2527                 case D3DFILTER_MIPNEAREST:
2528                 case D3DFILTER_LINEARMIPNEAREST:
2529                     tex_mag = WINED3D_TEXF_POINT;
2530                     break;
2531                 case D3DFILTER_LINEAR:
2532                 case D3DFILTER_MIPLINEAR:
2533                 case D3DFILTER_LINEARMIPLINEAR:
2534                     tex_mag = WINED3D_TEXF_LINEAR;
2535                     break;
2536                 default:
2537                     tex_mag = WINED3D_TEXF_POINT;
2538                     FIXME("Unhandled texture mag %#x.\n", value);
2539                     break;
2540             }
2541
2542             wined3d_device_set_sampler_state(device->wined3d_device, 0, WINED3D_SAMP_MAG_FILTER, tex_mag);
2543             break;
2544         }
2545
2546         case D3DRENDERSTATE_TEXTUREMIN:
2547         {
2548             enum wined3d_texture_filter_type tex_min;
2549             enum wined3d_texture_filter_type tex_mip;
2550
2551             switch (value)
2552             {
2553                 case D3DFILTER_NEAREST:
2554                     tex_min = WINED3D_TEXF_POINT;
2555                     tex_mip = WINED3D_TEXF_NONE;
2556                     break;
2557                 case D3DFILTER_LINEAR:
2558                     tex_min = WINED3D_TEXF_LINEAR;
2559                     tex_mip = WINED3D_TEXF_NONE;
2560                     break;
2561                 case D3DFILTER_MIPNEAREST:
2562                     tex_min = WINED3D_TEXF_POINT;
2563                     tex_mip = WINED3D_TEXF_POINT;
2564                     break;
2565                 case D3DFILTER_MIPLINEAR:
2566                     tex_min = WINED3D_TEXF_LINEAR;
2567                     tex_mip = WINED3D_TEXF_POINT;
2568                     break;
2569                 case D3DFILTER_LINEARMIPNEAREST:
2570                     tex_min = WINED3D_TEXF_POINT;
2571                     tex_mip = WINED3D_TEXF_LINEAR;
2572                     break;
2573                 case D3DFILTER_LINEARMIPLINEAR:
2574                     tex_min = WINED3D_TEXF_LINEAR;
2575                     tex_mip = WINED3D_TEXF_LINEAR;
2576                     break;
2577
2578                 default:
2579                     FIXME("Unhandled texture min %#x.\n",value);
2580                     tex_min = WINED3D_TEXF_POINT;
2581                     tex_mip = WINED3D_TEXF_NONE;
2582                     break;
2583             }
2584
2585             wined3d_device_set_sampler_state(device->wined3d_device,
2586                     0, WINED3D_SAMP_MIP_FILTER, tex_mip);
2587             wined3d_device_set_sampler_state(device->wined3d_device,
2588                     0, WINED3D_SAMP_MIN_FILTER, tex_min);
2589             break;
2590         }
2591
2592         case D3DRENDERSTATE_TEXTUREADDRESS:
2593             wined3d_device_set_sampler_state(device->wined3d_device,
2594                     0, WINED3D_SAMP_ADDRESS_V, value);
2595             /* Drop through */
2596         case D3DRENDERSTATE_TEXTUREADDRESSU:
2597             wined3d_device_set_sampler_state(device->wined3d_device,
2598                     0, WINED3D_SAMP_ADDRESS_U, value);
2599             break;
2600         case D3DRENDERSTATE_TEXTUREADDRESSV:
2601             wined3d_device_set_sampler_state(device->wined3d_device,
2602                     0, WINED3D_SAMP_ADDRESS_V, value);
2603             break;
2604
2605         case D3DRENDERSTATE_BORDERCOLOR:
2606             /* This should probably just forward to the corresponding sampler
2607              * state. Needs tests. */
2608             FIXME("Unhandled render state D3DRENDERSTATE_BORDERCOLOR.\n");
2609             hr = E_NOTIMPL;
2610             break;
2611
2612         case D3DRENDERSTATE_TEXTUREHANDLE:
2613         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2614             WARN("Render state %#x is invalid in d3d7.\n", state);
2615             hr = DDERR_INVALIDPARAMS;
2616             break;
2617
2618         case D3DRENDERSTATE_ZBIAS:
2619             wined3d_device_set_render_state(device->wined3d_device, WINED3D_RS_DEPTHBIAS, value);
2620             break;
2621
2622         default:
2623             if (state >= D3DRENDERSTATE_STIPPLEPATTERN00
2624                     && state <= D3DRENDERSTATE_STIPPLEPATTERN31)
2625             {
2626                 FIXME("Unhandled stipple pattern render state (%#x).\n", state);
2627                 hr = E_NOTIMPL;
2628                 break;
2629             }
2630
2631             wined3d_device_set_render_state(device->wined3d_device, state, value);
2632             break;
2633     }
2634     wined3d_mutex_unlock();
2635
2636     return hr;
2637 }
2638
2639 static HRESULT WINAPI d3d_device7_SetRenderState_FPUSetup(IDirect3DDevice7 *iface,
2640         D3DRENDERSTATETYPE state, DWORD value)
2641 {
2642     return d3d_device7_SetRenderState(iface, state, value);
2643 }
2644
2645 static HRESULT WINAPI d3d_device7_SetRenderState_FPUPreserve(IDirect3DDevice7 *iface,
2646         D3DRENDERSTATETYPE state, DWORD value)
2647 {
2648     HRESULT hr;
2649     WORD old_fpucw;
2650
2651     old_fpucw = d3d_fpu_setup();
2652     hr = d3d_device7_SetRenderState(iface, state, value);
2653     set_fpu_control_word(old_fpucw);
2654
2655     return hr;
2656 }
2657
2658 static HRESULT WINAPI d3d_device3_SetRenderState(IDirect3DDevice3 *iface,
2659         D3DRENDERSTATETYPE state, DWORD value)
2660 {
2661     /* Note about D3DRENDERSTATE_TEXTUREMAPBLEND implementation: most of values
2662     for this state can be directly mapped to texture stage colorop and alphaop, but
2663     D3DTBLEND_MODULATE is tricky: it uses alpha from texture when available and alpha
2664     from diffuse otherwise. So changing the texture must be monitored in SetTexture to modify
2665     alphaarg when needed.
2666
2667     Aliens vs Predator 1 depends on accurate D3DTBLEND_MODULATE emulation
2668
2669     Legacy texture blending (TEXTUREMAPBLEND) and texture stage states: directx6 docs state that
2670     TEXTUREMAPBLEND is deprecated, yet can still be used. Games must not use both or results
2671     are undefined. D3DTBLEND_MODULATE mode in particular is dependent on texture pixel format and
2672     requires fixup of stage 0 texture states when texture changes, but this fixup can interfere
2673     with games not using this deprecated state. So a flag 'legacyTextureBlending' has to be kept
2674     in device - TRUE if the app is using TEXTUREMAPBLEND.
2675
2676     Tests show that setting TEXTUREMAPBLEND on native doesn't seem to change values returned by
2677     GetTextureStageState and vice versa. Not so on Wine, but it is 'undefined' anyway so, probably, ok,
2678     unless some broken game will be found that cares. */
2679
2680     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2681     HRESULT hr;
2682
2683     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2684
2685     wined3d_mutex_lock();
2686
2687     switch (state)
2688     {
2689         case D3DRENDERSTATE_TEXTUREHANDLE:
2690         {
2691             struct ddraw_surface *surf;
2692
2693             if (value == 0)
2694             {
2695                 hr = wined3d_device_set_texture(device->wined3d_device, 0, NULL);
2696                 break;
2697             }
2698
2699             surf = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_SURFACE);
2700             if (!surf)
2701             {
2702                 WARN("Invalid texture handle.\n");
2703                 hr = DDERR_INVALIDPARAMS;
2704                 break;
2705             }
2706
2707             hr = IDirect3DDevice3_SetTexture(iface, 0, &surf->IDirect3DTexture2_iface);
2708             break;
2709         }
2710
2711         case D3DRENDERSTATE_TEXTUREMAPBLEND:
2712         {
2713             device->legacyTextureBlending = TRUE;
2714
2715             switch (value)
2716             {
2717                 case D3DTBLEND_MODULATE:
2718                 {
2719                     struct wined3d_texture *tex = NULL;
2720                     BOOL tex_alpha = FALSE;
2721                     DDPIXELFORMAT ddfmt;
2722
2723                     hr = wined3d_device_get_texture(device->wined3d_device, 0, &tex);
2724
2725                     if(hr == WINED3D_OK && tex)
2726                     {
2727                         struct wined3d_resource *sub_resource;
2728
2729                         if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
2730                         {
2731                             struct wined3d_resource_desc desc;
2732
2733                             wined3d_resource_get_desc(sub_resource, &desc);
2734                             ddfmt.dwSize = sizeof(ddfmt);
2735                             PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
2736                             if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
2737                         }
2738
2739                         wined3d_texture_decref(tex);
2740                     }
2741
2742                     if (tex_alpha)
2743                         wined3d_device_set_texture_stage_state(device->wined3d_device,
2744                                 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2745                     else
2746                         wined3d_device_set_texture_stage_state(device->wined3d_device,
2747                                 0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2748                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2749                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2750                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2751                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
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_COLOR_OP, WINED3D_TOP_MODULATE);
2758                     break;
2759                 }
2760
2761                 case D3DTBLEND_ADD:
2762                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2763                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_ADD);
2764                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2765                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2766                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2767                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2768                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2769                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2770                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2771                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2772                     break;
2773
2774                 case D3DTBLEND_MODULATEALPHA:
2775                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2776                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2777                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2778                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2779                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2780                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2781                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2782                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2783                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2784                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_MODULATE);
2785                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2786                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_MODULATE);
2787                     break;
2788
2789                 case D3DTBLEND_COPY:
2790                 case D3DTBLEND_DECAL:
2791                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2792                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2793                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2794                             0, WINED3D_TSS_ALPHA_ARG1, WINED3DTA_TEXTURE);
2795                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2796                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_SELECT_ARG1);
2797                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2798                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
2799                     break;
2800
2801                 case D3DTBLEND_DECALALPHA:
2802                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2803                             0, WINED3D_TSS_COLOR_OP, WINED3D_TOP_BLEND_TEXTURE_ALPHA);
2804                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2805                             0, WINED3D_TSS_COLOR_ARG1, WINED3DTA_TEXTURE);
2806                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2807                             0, WINED3D_TSS_COLOR_ARG2, WINED3DTA_CURRENT);
2808                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2809                             0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
2810                     wined3d_device_set_texture_stage_state(device->wined3d_device,
2811                             0, WINED3D_TSS_ALPHA_ARG2, WINED3DTA_CURRENT);
2812                     break;
2813
2814                 default:
2815                     FIXME("Unhandled texture environment %#x.\n", value);
2816             }
2817
2818             hr = D3D_OK;
2819             break;
2820         }
2821
2822         default:
2823             hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, state, value);
2824             break;
2825     }
2826     wined3d_mutex_unlock();
2827
2828     return hr;
2829 }
2830
2831 static HRESULT WINAPI d3d_device2_SetRenderState(IDirect3DDevice2 *iface,
2832         D3DRENDERSTATETYPE state, DWORD value)
2833 {
2834     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2835
2836     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2837
2838     return IDirect3DDevice3_SetRenderState(&device->IDirect3DDevice3_iface, state, value);
2839 }
2840
2841 /*****************************************************************************
2842  * Direct3DDevice3::SetLightState
2843  *
2844  * Sets a light state for Direct3DDevice3 and Direct3DDevice2. The
2845  * light states are forwarded to Direct3DDevice7 render states
2846  *
2847  * Version 2 and 3
2848  *
2849  * Params:
2850  *  LightStateType: The light state to change
2851  *  Value: The value to assign to that light state
2852  *
2853  * Returns:
2854  *  D3D_OK on success
2855  *  DDERR_INVALIDPARAMS if the parameters were incorrect
2856  *  Also check IDirect3DDevice7::SetRenderState
2857  *
2858  *****************************************************************************/
2859 static HRESULT WINAPI d3d_device3_SetLightState(IDirect3DDevice3 *iface,
2860         D3DLIGHTSTATETYPE state, DWORD value)
2861 {
2862     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2863     HRESULT hr;
2864
2865     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2866
2867     if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2868     {
2869         TRACE("Unexpected Light State Type\n");
2870         return DDERR_INVALIDPARAMS;
2871     }
2872
2873     wined3d_mutex_lock();
2874     if (state == D3DLIGHTSTATE_MATERIAL)
2875     {
2876         struct d3d_material *m = ddraw_get_object(&device->handle_table, value - 1, DDRAW_HANDLE_MATERIAL);
2877         if (!m)
2878         {
2879             WARN("Invalid material handle.\n");
2880             wined3d_mutex_unlock();
2881             return DDERR_INVALIDPARAMS;
2882         }
2883
2884         TRACE(" activating material %p.\n", m);
2885         material_activate(m);
2886
2887         device->material = value;
2888     }
2889     else if (state == D3DLIGHTSTATE_COLORMODEL)
2890     {
2891         switch (value)
2892         {
2893             case D3DCOLOR_MONO:
2894                 ERR("DDCOLOR_MONO should not happen!\n");
2895                 break;
2896             case D3DCOLOR_RGB:
2897                 /* We are already in this mode */
2898                 TRACE("Setting color model to RGB (no-op).\n");
2899                 break;
2900             default:
2901                 ERR("Unknown color model!\n");
2902                 wined3d_mutex_unlock();
2903                 return DDERR_INVALIDPARAMS;
2904         }
2905     }
2906     else
2907     {
2908         D3DRENDERSTATETYPE rs;
2909         switch (state)
2910         {
2911             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
2912                 rs = D3DRENDERSTATE_AMBIENT;
2913                 break;
2914             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
2915                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
2916                 break;
2917             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
2918                 rs = D3DRENDERSTATE_FOGSTART;
2919                 break;
2920             case D3DLIGHTSTATE_FOGEND:        /* 6 */
2921                 rs = D3DRENDERSTATE_FOGEND;
2922                 break;
2923             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
2924                 rs = D3DRENDERSTATE_FOGDENSITY;
2925                 break;
2926             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
2927                 rs = D3DRENDERSTATE_COLORVERTEX;
2928                 break;
2929             default:
2930                 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
2931                 wined3d_mutex_unlock();
2932                 return DDERR_INVALIDPARAMS;
2933         }
2934
2935         hr = IDirect3DDevice7_SetRenderState(&device->IDirect3DDevice7_iface, rs, value);
2936         wined3d_mutex_unlock();
2937         return hr;
2938     }
2939     wined3d_mutex_unlock();
2940
2941     return D3D_OK;
2942 }
2943
2944 static HRESULT WINAPI d3d_device2_SetLightState(IDirect3DDevice2 *iface,
2945         D3DLIGHTSTATETYPE state, DWORD value)
2946 {
2947     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
2948
2949     TRACE("iface %p, state %#x, value %#x.\n", iface, state, value);
2950
2951     return d3d_device3_SetLightState(&device->IDirect3DDevice3_iface, state, value);
2952 }
2953
2954 /*****************************************************************************
2955  * IDirect3DDevice3::GetLightState
2956  *
2957  * Returns the current setting of a light state. The state is read from
2958  * the Direct3DDevice7 render state.
2959  *
2960  * Version 2 and 3
2961  *
2962  * Params:
2963  *  LightStateType: The light state to return
2964  *  Value: The address to store the light state setting at
2965  *
2966  * Returns:
2967  *  D3D_OK on success
2968  *  DDDERR_INVALIDPARAMS if the parameters were incorrect
2969  *  Also see IDirect3DDevice7::GetRenderState
2970  *
2971  *****************************************************************************/
2972 static HRESULT WINAPI d3d_device3_GetLightState(IDirect3DDevice3 *iface,
2973         D3DLIGHTSTATETYPE state, DWORD *value)
2974 {
2975     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
2976     HRESULT hr;
2977
2978     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
2979
2980     if (!state || (state > D3DLIGHTSTATE_COLORVERTEX))
2981     {
2982         TRACE("Unexpected Light State Type\n");
2983         return DDERR_INVALIDPARAMS;
2984     }
2985
2986     if (!value)
2987         return DDERR_INVALIDPARAMS;
2988
2989     wined3d_mutex_lock();
2990     if (state == D3DLIGHTSTATE_MATERIAL)
2991     {
2992         *value = device->material;
2993     }
2994     else if (state == D3DLIGHTSTATE_COLORMODEL)
2995     {
2996         *value = D3DCOLOR_RGB;
2997     }
2998     else
2999     {
3000         D3DRENDERSTATETYPE rs;
3001         switch (state)
3002         {
3003             case D3DLIGHTSTATE_AMBIENT:       /* 2 */
3004                 rs = D3DRENDERSTATE_AMBIENT;
3005                 break;
3006             case D3DLIGHTSTATE_FOGMODE:       /* 4 */
3007                 rs = D3DRENDERSTATE_FOGVERTEXMODE;
3008                 break;
3009             case D3DLIGHTSTATE_FOGSTART:      /* 5 */
3010                 rs = D3DRENDERSTATE_FOGSTART;
3011                 break;
3012             case D3DLIGHTSTATE_FOGEND:        /* 6 */
3013                 rs = D3DRENDERSTATE_FOGEND;
3014                 break;
3015             case D3DLIGHTSTATE_FOGDENSITY:    /* 7 */
3016                 rs = D3DRENDERSTATE_FOGDENSITY;
3017                 break;
3018             case D3DLIGHTSTATE_COLORVERTEX:   /* 8 */
3019                 rs = D3DRENDERSTATE_COLORVERTEX;
3020                 break;
3021             default:
3022                 FIXME("Unhandled D3DLIGHTSTATETYPE %#x.\n", state);
3023                 wined3d_mutex_unlock();
3024                 return DDERR_INVALIDPARAMS;
3025         }
3026
3027         hr = IDirect3DDevice7_GetRenderState(&device->IDirect3DDevice7_iface, rs, value);
3028         wined3d_mutex_unlock();
3029         return hr;
3030     }
3031     wined3d_mutex_unlock();
3032
3033     return D3D_OK;
3034 }
3035
3036 static HRESULT WINAPI d3d_device2_GetLightState(IDirect3DDevice2 *iface,
3037         D3DLIGHTSTATETYPE state, DWORD *value)
3038 {
3039     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3040
3041     TRACE("iface %p, state %#x, value %p.\n", iface, state, value);
3042
3043     return d3d_device3_GetLightState(&device->IDirect3DDevice3_iface, state, value);
3044 }
3045
3046 /*****************************************************************************
3047  * IDirect3DDevice7::SetTransform
3048  *
3049  * Assigns a D3DMATRIX to a transform type. The transform types are defined
3050  * in include/d3dtypes.h.
3051  * The D3DTRANSFORMSTATE_WORLD (=1) is translated to D3DTS_WORLDMATRIX(0)
3052  * (=255) for wined3d, because the 1 transform state was removed in d3d8
3053  * and WineD3D already understands the replacement D3DTS_WORLDMATRIX(0)
3054  *
3055  * Version 2, 3 and 7
3056  *
3057  * Params:
3058  *  TransformStateType: transform state to set
3059  *  Matrix: Matrix to assign to the state
3060  *
3061  * Returns:
3062  *  D3D_OK on success
3063  *  DDERR_INVALIDPARAMS if Matrix == NULL
3064  *  For details see IWineD3DDevice::SetTransform
3065  *
3066  *****************************************************************************/
3067 static HRESULT d3d_device7_SetTransform(IDirect3DDevice7 *iface,
3068         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3069 {
3070     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3071     enum wined3d_transform_state wined3d_state;
3072
3073     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3074
3075     switch (state)
3076     {
3077         case D3DTRANSFORMSTATE_WORLD:
3078             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3079             break;
3080         case D3DTRANSFORMSTATE_WORLD1:
3081             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3082             break;
3083         case D3DTRANSFORMSTATE_WORLD2:
3084             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3085             break;
3086         case D3DTRANSFORMSTATE_WORLD3:
3087             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3088             break;
3089         default:
3090             wined3d_state = state;
3091     }
3092
3093     if (!matrix)
3094         return DDERR_INVALIDPARAMS;
3095
3096     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3097     wined3d_mutex_lock();
3098     wined3d_device_set_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3099     wined3d_mutex_unlock();
3100
3101     return D3D_OK;
3102 }
3103
3104 static HRESULT WINAPI d3d_device7_SetTransform_FPUSetup(IDirect3DDevice7 *iface,
3105         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3106 {
3107     return d3d_device7_SetTransform(iface, state, matrix);
3108 }
3109
3110 static HRESULT WINAPI d3d_device7_SetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3111         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3112 {
3113     HRESULT hr;
3114     WORD old_fpucw;
3115
3116     old_fpucw = d3d_fpu_setup();
3117     hr = d3d_device7_SetTransform(iface, state, matrix);
3118     set_fpu_control_word(old_fpucw);
3119
3120     return hr;
3121 }
3122
3123 static HRESULT WINAPI d3d_device3_SetTransform(IDirect3DDevice3 *iface,
3124         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3125 {
3126     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3127
3128     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3129
3130     if (!matrix)
3131         return DDERR_INVALIDPARAMS;
3132
3133     if (state == D3DTRANSFORMSTATE_PROJECTION)
3134     {
3135         D3DMATRIX projection;
3136
3137         wined3d_mutex_lock();
3138         multiply_matrix(&projection, &device->legacy_clipspace, matrix);
3139         wined3d_device_set_transform(device->wined3d_device,
3140                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3141         device->legacy_projection = *matrix;
3142         wined3d_mutex_unlock();
3143
3144         return D3D_OK;
3145     }
3146
3147     return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3148 }
3149
3150 static HRESULT WINAPI d3d_device2_SetTransform(IDirect3DDevice2 *iface,
3151         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3152 {
3153     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3154
3155     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3156
3157     return IDirect3DDevice7_SetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3158 }
3159
3160 /*****************************************************************************
3161  * IDirect3DDevice7::GetTransform
3162  *
3163  * Returns the matrix assigned to a transform state
3164  * D3DTRANSFORMSTATE_WORLD is translated to D3DTS_WORLDMATRIX(0), see
3165  * SetTransform
3166  *
3167  * Params:
3168  *  TransformStateType: State to read the matrix from
3169  *  Matrix: Address to store the matrix at
3170  *
3171  * Returns:
3172  *  D3D_OK on success
3173  *  DDERR_INVALIDPARAMS if Matrix == NULL
3174  *  For details, see IWineD3DDevice::GetTransform
3175  *
3176  *****************************************************************************/
3177 static HRESULT d3d_device7_GetTransform(IDirect3DDevice7 *iface,
3178         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3179 {
3180     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3181     enum wined3d_transform_state wined3d_state;
3182
3183     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3184
3185     switch (state)
3186     {
3187         case D3DTRANSFORMSTATE_WORLD:
3188             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3189             break;
3190         case D3DTRANSFORMSTATE_WORLD1:
3191             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3192             break;
3193         case D3DTRANSFORMSTATE_WORLD2:
3194             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3195             break;
3196         case D3DTRANSFORMSTATE_WORLD3:
3197             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3198             break;
3199         default:
3200             wined3d_state = state;
3201     }
3202
3203     if (!matrix)
3204         return DDERR_INVALIDPARAMS;
3205
3206     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3207     wined3d_mutex_lock();
3208     wined3d_device_get_transform(device->wined3d_device, wined3d_state, (struct wined3d_matrix *)matrix);
3209     wined3d_mutex_unlock();
3210
3211     return D3D_OK;
3212 }
3213
3214 static HRESULT WINAPI d3d_device7_GetTransform_FPUSetup(IDirect3DDevice7 *iface,
3215         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3216 {
3217     return d3d_device7_GetTransform(iface, state, matrix);
3218 }
3219
3220 static HRESULT WINAPI d3d_device7_GetTransform_FPUPreserve(IDirect3DDevice7 *iface,
3221         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3222 {
3223     HRESULT hr;
3224     WORD old_fpucw;
3225
3226     old_fpucw = d3d_fpu_setup();
3227     hr = d3d_device7_GetTransform(iface, state, matrix);
3228     set_fpu_control_word(old_fpucw);
3229
3230     return hr;
3231 }
3232
3233 static HRESULT WINAPI d3d_device3_GetTransform(IDirect3DDevice3 *iface,
3234         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3235 {
3236     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3237
3238     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3239
3240     if (!matrix)
3241         return DDERR_INVALIDPARAMS;
3242
3243     if (state == D3DTRANSFORMSTATE_PROJECTION)
3244     {
3245         wined3d_mutex_lock();
3246         *matrix = device->legacy_projection;
3247         wined3d_mutex_unlock();
3248         return DD_OK;
3249     }
3250
3251     return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3252 }
3253
3254 static HRESULT WINAPI d3d_device2_GetTransform(IDirect3DDevice2 *iface,
3255         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3256 {
3257     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3258
3259     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3260
3261     return IDirect3DDevice7_GetTransform(&device->IDirect3DDevice7_iface, state, matrix);
3262 }
3263
3264 /*****************************************************************************
3265  * IDirect3DDevice7::MultiplyTransform
3266  *
3267  * Multiplies the already-set transform matrix of a transform state
3268  * with another matrix. For the world matrix, see SetTransform
3269  *
3270  * Version 2, 3 and 7
3271  *
3272  * Params:
3273  *  TransformStateType: Transform state to multiply
3274  *  D3DMatrix Matrix to multiply with.
3275  *
3276  * Returns
3277  *  D3D_OK on success
3278  *  DDERR_INVALIDPARAMS if D3DMatrix is NULL
3279  *  For details, see IWineD3DDevice::MultiplyTransform
3280  *
3281  *****************************************************************************/
3282 static HRESULT d3d_device7_MultiplyTransform(IDirect3DDevice7 *iface,
3283         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3284 {
3285     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3286     enum wined3d_transform_state wined3d_state;
3287
3288     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3289
3290     switch (state)
3291     {
3292         case D3DTRANSFORMSTATE_WORLD:
3293             wined3d_state = WINED3D_TS_WORLD_MATRIX(0);
3294             break;
3295         case D3DTRANSFORMSTATE_WORLD1:
3296             wined3d_state = WINED3D_TS_WORLD_MATRIX(1);
3297             break;
3298         case D3DTRANSFORMSTATE_WORLD2:
3299             wined3d_state = WINED3D_TS_WORLD_MATRIX(2);
3300             break;
3301         case D3DTRANSFORMSTATE_WORLD3:
3302             wined3d_state = WINED3D_TS_WORLD_MATRIX(3);
3303             break;
3304         default:
3305             wined3d_state = state;
3306     }
3307
3308     /* Note: D3DMATRIX is compatible with struct wined3d_matrix. */
3309     wined3d_mutex_lock();
3310     wined3d_device_multiply_transform(device->wined3d_device,
3311             wined3d_state, (struct wined3d_matrix *)matrix);
3312     wined3d_mutex_unlock();
3313
3314     return D3D_OK;
3315 }
3316
3317 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUSetup(IDirect3DDevice7 *iface,
3318         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3319 {
3320     return d3d_device7_MultiplyTransform(iface, state, matrix);
3321 }
3322
3323 static HRESULT WINAPI d3d_device7_MultiplyTransform_FPUPreserve(IDirect3DDevice7 *iface,
3324         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3325 {
3326     HRESULT hr;
3327     WORD old_fpucw;
3328
3329     old_fpucw = d3d_fpu_setup();
3330     hr = d3d_device7_MultiplyTransform(iface, state, matrix);
3331     set_fpu_control_word(old_fpucw);
3332
3333     return hr;
3334 }
3335
3336 static HRESULT WINAPI d3d_device3_MultiplyTransform(IDirect3DDevice3 *iface,
3337         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3338 {
3339     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3340
3341     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3342
3343     if (state == D3DTRANSFORMSTATE_PROJECTION)
3344     {
3345         D3DMATRIX projection, tmp;
3346
3347         wined3d_mutex_lock();
3348         multiply_matrix(&tmp, &device->legacy_projection, matrix);
3349         multiply_matrix(&projection, &device->legacy_clipspace, &tmp);
3350         wined3d_device_set_transform(device->wined3d_device,
3351                 WINED3D_TS_PROJECTION, (struct wined3d_matrix *)&projection);
3352         device->legacy_projection = tmp;
3353         wined3d_mutex_unlock();
3354
3355         return D3D_OK;
3356     }
3357
3358     return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3359 }
3360
3361 static HRESULT WINAPI d3d_device2_MultiplyTransform(IDirect3DDevice2 *iface,
3362         D3DTRANSFORMSTATETYPE state, D3DMATRIX *matrix)
3363 {
3364     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3365
3366     TRACE("iface %p, state %#x, matrix %p.\n", iface, state, matrix);
3367
3368     return IDirect3DDevice7_MultiplyTransform(&device->IDirect3DDevice7_iface, state, matrix);
3369 }
3370
3371 /*****************************************************************************
3372  * IDirect3DDevice7::DrawPrimitive
3373  *
3374  * Draws primitives based on vertices in an application-provided pointer
3375  *
3376  * Version 2, 3 and 7. The IDirect3DDevice2 thunk converts the fixed vertex type into
3377  * an FVF format for D3D7
3378  *
3379  * Params:
3380  *  PrimitiveType: The type of the primitives to draw
3381  *  Vertex type: Flexible vertex format vertex description
3382  *  Vertices: Pointer to the vertex array
3383  *  VertexCount: The number of vertices to draw
3384  *  Flags: As usual a few flags
3385  *
3386  * Returns:
3387  *  D3D_OK on success
3388  *  DDERR_INVALIDPARAMS if Vertices is NULL
3389  *  For details, see IWineD3DDevice::DrawPrimitiveUP
3390  *
3391  *****************************************************************************/
3392 static HRESULT d3d_device7_DrawPrimitive(IDirect3DDevice7 *iface,
3393         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3394         DWORD vertex_count, DWORD flags)
3395 {
3396     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3397     UINT stride;
3398     HRESULT hr;
3399
3400     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3401             iface, primitive_type, fvf, vertices, vertex_count, flags);
3402
3403     if (!vertices)
3404         return DDERR_INVALIDPARAMS;
3405
3406     /* Get the stride */
3407     stride = get_flexible_vertex_size(fvf);
3408
3409     wined3d_mutex_lock();
3410     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3411     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
3412     hr = wined3d_device_draw_primitive_up(device->wined3d_device, vertex_count, vertices, stride);
3413     wined3d_mutex_unlock();
3414
3415     return hr;
3416 }
3417
3418 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3419         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3420         DWORD vertex_count, DWORD flags)
3421 {
3422     return d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3423 }
3424
3425 static HRESULT WINAPI d3d_device7_DrawPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3426         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices,
3427         DWORD vertex_count, DWORD flags)
3428 {
3429     HRESULT hr;
3430     WORD old_fpucw;
3431
3432     old_fpucw = d3d_fpu_setup();
3433     hr = d3d_device7_DrawPrimitive(iface, primitive_type, fvf, vertices, vertex_count, flags);
3434     set_fpu_control_word(old_fpucw);
3435
3436     return hr;
3437 }
3438
3439 static HRESULT WINAPI d3d_device3_DrawPrimitive(IDirect3DDevice3 *iface,
3440         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3441         DWORD flags)
3442 {
3443     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3444
3445     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, flags %#x.\n",
3446             iface, primitive_type, fvf, vertices, vertex_count, flags);
3447
3448     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3449             primitive_type, fvf, vertices, vertex_count, flags);
3450 }
3451
3452 static HRESULT WINAPI d3d_device2_DrawPrimitive(IDirect3DDevice2 *iface,
3453         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3454         DWORD vertex_count, DWORD flags)
3455 {
3456     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3457     DWORD fvf;
3458
3459     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, flags %#x.\n",
3460             iface, primitive_type, vertex_type, vertices, vertex_count, flags);
3461
3462     switch (vertex_type)
3463     {
3464         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3465         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3466         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3467         default:
3468             FIXME("Unhandled vertex type %#x.\n", vertex_type);
3469             return DDERR_INVALIDPARAMS;  /* Should never happen */
3470     }
3471
3472     return IDirect3DDevice7_DrawPrimitive(&device->IDirect3DDevice7_iface,
3473             primitive_type, fvf, vertices, vertex_count, flags);
3474 }
3475
3476 /*****************************************************************************
3477  * IDirect3DDevice7::DrawIndexedPrimitive
3478  *
3479  * Draws vertices from an application-provided pointer, based on the index
3480  * numbers in a WORD array.
3481  *
3482  * Version 2, 3 and 7. The version 7 thunk translates the vertex type into
3483  * an FVF format for D3D7
3484  *
3485  * Params:
3486  *  PrimitiveType: The primitive type to draw
3487  *  VertexType: The FVF vertex description
3488  *  Vertices: Pointer to the vertex array
3489  *  VertexCount: ?
3490  *  Indices: Pointer to the index array
3491  *  IndexCount: Number of indices = Number of vertices to draw
3492  *  Flags: As usual, some flags
3493  *
3494  * Returns:
3495  *  D3D_OK on success
3496  *  DDERR_INVALIDPARAMS if Vertices or Indices is NULL
3497  *  For details, see IWineD3DDevice::DrawIndexedPrimitiveUP
3498  *
3499  *****************************************************************************/
3500 static HRESULT d3d_device7_DrawIndexedPrimitive(IDirect3DDevice7 *iface,
3501         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3502         WORD *indices, DWORD index_count, DWORD flags)
3503 {
3504     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3505     HRESULT hr;
3506
3507     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3508             "indices %p, index_count %u, flags %#x.\n",
3509             iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3510
3511     /* Set the D3DDevice's FVF */
3512     wined3d_mutex_lock();
3513     wined3d_device_set_vertex_declaration(device->wined3d_device, ddraw_find_decl(device->ddraw, fvf));
3514     wined3d_device_set_primitive_type(device->wined3d_device, primitive_type);
3515     hr = wined3d_device_draw_indexed_primitive_up(device->wined3d_device, index_count, indices,
3516             WINED3DFMT_R16_UINT, vertices, get_flexible_vertex_size(fvf));
3517     wined3d_mutex_unlock();
3518
3519     return hr;
3520 }
3521
3522 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUSetup(IDirect3DDevice7 *iface,
3523         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3524         WORD *indices, DWORD index_count, DWORD flags)
3525 {
3526     return d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3527             vertices, vertex_count, indices, index_count, flags);
3528 }
3529
3530 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitive_FPUPreserve(IDirect3DDevice7 *iface,
3531         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3532         WORD *indices, DWORD index_count, DWORD flags)
3533 {
3534     HRESULT hr;
3535     WORD old_fpucw;
3536
3537     old_fpucw = d3d_fpu_setup();
3538     hr = d3d_device7_DrawIndexedPrimitive(iface, primitive_type, fvf,
3539             vertices, vertex_count, indices, index_count, flags);
3540     set_fpu_control_word(old_fpucw);
3541
3542     return hr;
3543 }
3544
3545 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitive(IDirect3DDevice3 *iface,
3546         D3DPRIMITIVETYPE primitive_type, DWORD fvf, void *vertices, DWORD vertex_count,
3547         WORD *indices, DWORD index_count, DWORD flags)
3548 {
3549     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3550
3551     TRACE("iface %p, primitive_type %#x, fvf %#x, vertices %p, vertex_count %u, "
3552             "indices %p, index_count %u, flags %#x.\n",
3553             iface, primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3554
3555     return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3556             primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3557 }
3558
3559 static HRESULT WINAPI d3d_device2_DrawIndexedPrimitive(IDirect3DDevice2 *iface,
3560         D3DPRIMITIVETYPE primitive_type, D3DVERTEXTYPE vertex_type, void *vertices,
3561         DWORD vertex_count, WORD *indices, DWORD index_count, DWORD flags)
3562 {
3563     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3564     DWORD fvf;
3565
3566     TRACE("iface %p, primitive_type %#x, vertex_type %#x, vertices %p, vertex_count %u, "
3567             "indices %p, index_count %u, flags %#x.\n",
3568             iface, primitive_type, vertex_type, vertices, vertex_count, indices, index_count, flags);
3569
3570     switch (vertex_type)
3571     {
3572         case D3DVT_VERTEX: fvf = D3DFVF_VERTEX; break;
3573         case D3DVT_LVERTEX: fvf = D3DFVF_LVERTEX; break;
3574         case D3DVT_TLVERTEX: fvf = D3DFVF_TLVERTEX; break;
3575         default:
3576             ERR("Unhandled vertex type %#x.\n", vertex_type);
3577             return DDERR_INVALIDPARAMS;  /* Should never happen */
3578     }
3579
3580     return IDirect3DDevice7_DrawIndexedPrimitive(&device->IDirect3DDevice7_iface,
3581             primitive_type, fvf, vertices, vertex_count, indices, index_count, flags);
3582 }
3583
3584 /*****************************************************************************
3585  * IDirect3DDevice7::SetClipStatus
3586  *
3587  * Sets the clip status. This defines things as clipping conditions and
3588  * the extents of the clipping region.
3589  *
3590  * Version 2, 3 and 7
3591  *
3592  * Params:
3593  *  ClipStatus:
3594  *
3595  * Returns:
3596  *  D3D_OK because it's a stub
3597  *  (DDERR_INVALIDPARAMS if ClipStatus == NULL)
3598  *
3599  *****************************************************************************/
3600 static HRESULT WINAPI d3d_device7_SetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3601 {
3602     FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3603
3604     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them
3605      * Perhaps this needs a new data type and an additional IWineD3DDevice method
3606      */
3607     /* return IWineD3DDevice_SetClipStatus(This->wineD3DDevice, ClipStatus);*/
3608     return D3D_OK;
3609 }
3610
3611 static HRESULT WINAPI d3d_device3_SetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3612 {
3613     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3614
3615     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3616
3617     return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3618 }
3619
3620 static HRESULT WINAPI d3d_device2_SetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3621 {
3622     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3623
3624     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3625
3626     return IDirect3DDevice7_SetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3627 }
3628
3629 /*****************************************************************************
3630  * IDirect3DDevice7::GetClipStatus
3631  *
3632  * Returns the clip status
3633  *
3634  * Params:
3635  *  ClipStatus: Address to write the clip status to
3636  *
3637  * Returns:
3638  *  D3D_OK because it's a stub
3639  *
3640  *****************************************************************************/
3641 static HRESULT WINAPI d3d_device7_GetClipStatus(IDirect3DDevice7 *iface, D3DCLIPSTATUS *clip_status)
3642 {
3643     FIXME("iface %p, clip_status %p stub!\n", iface, clip_status);
3644
3645     /* D3DCLIPSTATUS and WINED3DCLIPSTATUS are different. I don't know how to convert them */
3646     /* return IWineD3DDevice_GetClipStatus(This->wineD3DDevice, ClipStatus);*/
3647     return D3D_OK;
3648 }
3649
3650 static HRESULT WINAPI d3d_device3_GetClipStatus(IDirect3DDevice3 *iface, D3DCLIPSTATUS *clip_status)
3651 {
3652     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3653
3654     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3655
3656     return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3657 }
3658
3659 static HRESULT WINAPI d3d_device2_GetClipStatus(IDirect3DDevice2 *iface, D3DCLIPSTATUS *clip_status)
3660 {
3661     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
3662
3663     TRACE("iface %p, clip_status %p.\n", iface, clip_status);
3664
3665     return IDirect3DDevice7_GetClipStatus(&device->IDirect3DDevice7_iface, clip_status);
3666 }
3667
3668 /*****************************************************************************
3669  * IDirect3DDevice::DrawPrimitiveStrided
3670  *
3671  * Draws vertices described by a D3DDRAWPRIMITIVESTRIDEDDATA structure.
3672  *
3673  * Version 3 and 7
3674  *
3675  * Params:
3676  *  PrimitiveType: The primitive type to draw
3677  *  VertexType: The FVF description of the vertices to draw (for the stride??)
3678  *  D3DDrawPrimStrideData: A D3DDRAWPRIMITIVESTRIDEDDATA structure describing
3679  *                         the vertex data locations
3680  *  VertexCount: The number of vertices to draw
3681  *  Flags: Some flags
3682  *
3683  * Returns:
3684  *  D3D_OK, because it's a stub
3685  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3686  *  (For details, see IWineD3DDevice::DrawPrimitiveStrided)
3687  *
3688  *****************************************************************************/
3689 static HRESULT d3d_device7_DrawPrimitiveStrided(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
3690         DWORD VertexType, D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3691 {
3692     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3693     struct wined3d_strided_data wined3d_strided;
3694     DWORD i;
3695     HRESULT hr;
3696
3697     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3698             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3699
3700     memset(&wined3d_strided, 0, sizeof(wined3d_strided));
3701     /* Get the strided data right. the wined3d structure is a bit bigger
3702      * Watch out: The contents of the strided data are determined by the fvf,
3703      * not by the members set in D3DDrawPrimStrideData. So it's valid
3704      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3705      * not set in the fvf.
3706      */
3707     if(VertexType & D3DFVF_POSITION_MASK)
3708     {
3709         wined3d_strided.position.format = WINED3DFMT_R32G32B32_FLOAT;
3710         wined3d_strided.position.data = D3DDrawPrimStrideData->position.lpvData;
3711         wined3d_strided.position.stride = D3DDrawPrimStrideData->position.dwStride;
3712         if (VertexType & D3DFVF_XYZRHW)
3713         {
3714             wined3d_strided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
3715             wined3d_strided.position_transformed = TRUE;
3716         }
3717         else
3718         {
3719             wined3d_strided.position_transformed = FALSE;
3720         }
3721     }
3722
3723     if (VertexType & D3DFVF_NORMAL)
3724     {
3725         wined3d_strided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
3726         wined3d_strided.normal.data = D3DDrawPrimStrideData->normal.lpvData;
3727         wined3d_strided.normal.stride = D3DDrawPrimStrideData->normal.dwStride;
3728     }
3729
3730     if (VertexType & D3DFVF_DIFFUSE)
3731     {
3732         wined3d_strided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
3733         wined3d_strided.diffuse.data = D3DDrawPrimStrideData->diffuse.lpvData;
3734         wined3d_strided.diffuse.stride = D3DDrawPrimStrideData->diffuse.dwStride;
3735     }
3736
3737     if (VertexType & D3DFVF_SPECULAR)
3738     {
3739         wined3d_strided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
3740         wined3d_strided.specular.data = D3DDrawPrimStrideData->specular.lpvData;
3741         wined3d_strided.specular.stride = D3DDrawPrimStrideData->specular.dwStride;
3742     }
3743
3744     for (i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); ++i)
3745     {
3746         switch (GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
3747         {
3748             case 1: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32_FLOAT; break;
3749             case 2: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32_FLOAT; break;
3750             case 3: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
3751             case 4: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
3752             default: ERR("Unexpected texture coordinate size %d\n",
3753                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
3754         }
3755         wined3d_strided.tex_coords[i].data = D3DDrawPrimStrideData->textureCoords[i].lpvData;
3756         wined3d_strided.tex_coords[i].stride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
3757     }
3758
3759     /* WineD3D doesn't need the FVF here */
3760     wined3d_mutex_lock();
3761     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
3762     hr = wined3d_device_draw_primitive_strided(device->wined3d_device, VertexCount, &wined3d_strided);
3763     wined3d_mutex_unlock();
3764
3765     return hr;
3766 }
3767
3768 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3769         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3770         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3771 {
3772     return d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3773             VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3774 }
3775
3776 static HRESULT WINAPI d3d_device7_DrawPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3777         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3778         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3779 {
3780     HRESULT hr;
3781     WORD old_fpucw;
3782
3783     old_fpucw = d3d_fpu_setup();
3784     hr = d3d_device7_DrawPrimitiveStrided(iface, PrimitiveType,
3785             VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3786     set_fpu_control_word(old_fpucw);
3787
3788     return hr;
3789 }
3790
3791 static HRESULT WINAPI d3d_device3_DrawPrimitiveStrided(IDirect3DDevice3 *iface,
3792         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3793         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, DWORD Flags)
3794 {
3795     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3796
3797     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, flags %#x.\n",
3798             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3799
3800     return IDirect3DDevice7_DrawPrimitiveStrided(&device->IDirect3DDevice7_iface,
3801             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Flags);
3802 }
3803
3804 /*****************************************************************************
3805  * IDirect3DDevice7::DrawIndexedPrimitiveStrided
3806  *
3807  * Draws primitives specified by strided data locations based on indices
3808  *
3809  * Version 3 and 7
3810  *
3811  * Params:
3812  *  PrimitiveType:
3813  *
3814  * Returns:
3815  *  D3D_OK, because it's a stub
3816  *  (DDERR_INVALIDPARAMS if D3DDrawPrimStrideData is NULL)
3817  *  (DDERR_INVALIDPARAMS if Indices is NULL)
3818  *  (For more details, see IWineD3DDevice::DrawIndexedPrimitiveStrided)
3819  *
3820  *****************************************************************************/
3821 static HRESULT d3d_device7_DrawIndexedPrimitiveStrided(IDirect3DDevice7 *iface,
3822         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3823         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
3824         WORD *Indices, DWORD IndexCount, DWORD Flags)
3825 {
3826     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3827     struct wined3d_strided_data wined3d_strided;
3828     DWORD i;
3829     HRESULT hr;
3830
3831     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3832             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3833
3834     memset(&wined3d_strided, 0, sizeof(wined3d_strided));
3835     /* Get the strided data right. the wined3d structure is a bit bigger
3836      * Watch out: The contents of the strided data are determined by the fvf,
3837      * not by the members set in D3DDrawPrimStrideData. So it's valid
3838      * to have diffuse.lpvData set to 0xdeadbeef if the diffuse flag is
3839      * not set in the fvf. */
3840     if (VertexType & D3DFVF_POSITION_MASK)
3841     {
3842         wined3d_strided.position.format = WINED3DFMT_R32G32B32_FLOAT;
3843         wined3d_strided.position.data = D3DDrawPrimStrideData->position.lpvData;
3844         wined3d_strided.position.stride = D3DDrawPrimStrideData->position.dwStride;
3845         if (VertexType & D3DFVF_XYZRHW)
3846         {
3847             wined3d_strided.position.format = WINED3DFMT_R32G32B32A32_FLOAT;
3848             wined3d_strided.position_transformed = TRUE;
3849         }
3850         else
3851         {
3852             wined3d_strided.position_transformed = FALSE;
3853         }
3854     }
3855
3856     if (VertexType & D3DFVF_NORMAL)
3857     {
3858         wined3d_strided.normal.format = WINED3DFMT_R32G32B32_FLOAT;
3859         wined3d_strided.normal.data = D3DDrawPrimStrideData->normal.lpvData;
3860         wined3d_strided.normal.stride = D3DDrawPrimStrideData->normal.dwStride;
3861     }
3862
3863     if (VertexType & D3DFVF_DIFFUSE)
3864     {
3865         wined3d_strided.diffuse.format = WINED3DFMT_B8G8R8A8_UNORM;
3866         wined3d_strided.diffuse.data = D3DDrawPrimStrideData->diffuse.lpvData;
3867         wined3d_strided.diffuse.stride = D3DDrawPrimStrideData->diffuse.dwStride;
3868     }
3869
3870     if (VertexType & D3DFVF_SPECULAR)
3871     {
3872         wined3d_strided.specular.format = WINED3DFMT_B8G8R8A8_UNORM;
3873         wined3d_strided.specular.data = D3DDrawPrimStrideData->specular.lpvData;
3874         wined3d_strided.specular.stride = D3DDrawPrimStrideData->specular.dwStride;
3875     }
3876
3877     for (i = 0; i < GET_TEXCOUNT_FROM_FVF(VertexType); ++i)
3878     {
3879         switch (GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i))
3880         {
3881             case 1: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32_FLOAT; break;
3882             case 2: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32_FLOAT; break;
3883             case 3: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32_FLOAT; break;
3884             case 4: wined3d_strided.tex_coords[i].format = WINED3DFMT_R32G32B32A32_FLOAT; break;
3885             default: ERR("Unexpected texture coordinate size %d\n",
3886                          GET_TEXCOORD_SIZE_FROM_FVF(VertexType, i));
3887         }
3888         wined3d_strided.tex_coords[i].data = D3DDrawPrimStrideData->textureCoords[i].lpvData;
3889         wined3d_strided.tex_coords[i].stride = D3DDrawPrimStrideData->textureCoords[i].dwStride;
3890     }
3891
3892     /* WineD3D doesn't need the FVF here */
3893     wined3d_mutex_lock();
3894     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
3895     hr = wined3d_device_draw_indexed_primitive_strided(device->wined3d_device,
3896             IndexCount, &wined3d_strided, VertexCount, Indices, WINED3DFMT_R16_UINT);
3897     wined3d_mutex_unlock();
3898
3899     return hr;
3900 }
3901
3902 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup(IDirect3DDevice7 *iface,
3903         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3904         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
3905         WORD *Indices, DWORD IndexCount, DWORD Flags)
3906 {
3907     return d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
3908             D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3909 }
3910
3911 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve(IDirect3DDevice7 *iface,
3912         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3913         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount,
3914         WORD *Indices, DWORD IndexCount, DWORD Flags)
3915 {
3916     HRESULT hr;
3917     WORD old_fpucw;
3918
3919     old_fpucw = d3d_fpu_setup();
3920     hr = d3d_device7_DrawIndexedPrimitiveStrided(iface, PrimitiveType, VertexType,
3921             D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3922     set_fpu_control_word(old_fpucw);
3923
3924     return hr;
3925 }
3926
3927 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveStrided(IDirect3DDevice3 *iface,
3928         D3DPRIMITIVETYPE PrimitiveType, DWORD VertexType,
3929         D3DDRAWPRIMITIVESTRIDEDDATA *D3DDrawPrimStrideData, DWORD VertexCount, WORD *Indices,
3930         DWORD IndexCount, DWORD Flags)
3931 {
3932     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
3933
3934     TRACE("iface %p, primitive_type %#x, FVF %#x, strided_data %p, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
3935             iface, PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3936
3937     return IDirect3DDevice7_DrawIndexedPrimitiveStrided(&device->IDirect3DDevice7_iface,
3938             PrimitiveType, VertexType, D3DDrawPrimStrideData, VertexCount, Indices, IndexCount, Flags);
3939 }
3940
3941 /*****************************************************************************
3942  * IDirect3DDevice7::DrawPrimitiveVB
3943  *
3944  * Draws primitives from a vertex buffer to the screen.
3945  *
3946  * Version 3 and 7
3947  *
3948  * Params:
3949  *  PrimitiveType: Type of primitive to be rendered.
3950  *  D3DVertexBuf: Source Vertex Buffer
3951  *  StartVertex: Index of the first vertex from the buffer to be rendered
3952  *  NumVertices: Number of vertices to be rendered
3953  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
3954  *
3955  * Return values
3956  *  D3D_OK on success
3957  *  DDERR_INVALIDPARAMS if D3DVertexBuf is NULL
3958  *
3959  *****************************************************************************/
3960 static HRESULT d3d_device7_DrawPrimitiveVB(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
3961         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
3962 {
3963     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
3964     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
3965     HRESULT hr;
3966     DWORD stride;
3967
3968     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
3969             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
3970
3971     /* Sanity checks */
3972     if (!vb)
3973     {
3974         WARN("No Vertex buffer specified.\n");
3975         return DDERR_INVALIDPARAMS;
3976     }
3977     stride = get_flexible_vertex_size(vb->fvf);
3978
3979     wined3d_mutex_lock();
3980     wined3d_device_set_vertex_declaration(device->wined3d_device, vb->wineD3DVertexDeclaration);
3981     hr = wined3d_device_set_stream_source(device->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
3982     if (FAILED(hr))
3983     {
3984         WARN("Failed to set stream source, hr %#x.\n", hr);
3985         wined3d_mutex_unlock();
3986         return hr;
3987     }
3988
3989     /* Now draw the primitives */
3990     wined3d_device_set_primitive_type(device->wined3d_device, PrimitiveType);
3991     hr = wined3d_device_draw_primitive(device->wined3d_device, StartVertex, NumVertices);
3992     wined3d_mutex_unlock();
3993
3994     return hr;
3995 }
3996
3997 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
3998         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
3999 {
4000     return d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4001 }
4002
4003 static HRESULT WINAPI d3d_device7_DrawPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface, D3DPRIMITIVETYPE PrimitiveType,
4004         IDirect3DVertexBuffer7 *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4005 {
4006     HRESULT hr;
4007     WORD old_fpucw;
4008
4009     old_fpucw = d3d_fpu_setup();
4010     hr = d3d_device7_DrawPrimitiveVB(iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4011     set_fpu_control_word(old_fpucw);
4012
4013     return hr;
4014 }
4015
4016 static HRESULT WINAPI d3d_device3_DrawPrimitiveVB(IDirect3DDevice3 *iface, D3DPRIMITIVETYPE PrimitiveType,
4017         IDirect3DVertexBuffer *D3DVertexBuf, DWORD StartVertex, DWORD NumVertices, DWORD Flags)
4018 {
4019     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4020     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4021
4022     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, flags %#x.\n",
4023             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Flags);
4024
4025     return IDirect3DDevice7_DrawPrimitiveVB(&device->IDirect3DDevice7_iface,
4026             PrimitiveType, &vb->IDirect3DVertexBuffer7_iface, StartVertex, NumVertices, Flags);
4027 }
4028
4029
4030 /*****************************************************************************
4031  * IDirect3DDevice7::DrawIndexedPrimitiveVB
4032  *
4033  * Draws primitives from a vertex buffer to the screen
4034  *
4035  * Params:
4036  *  PrimitiveType: Type of primitive to be rendered.
4037  *  D3DVertexBuf: Source Vertex Buffer
4038  *  StartVertex: Index of the first vertex from the buffer to be rendered
4039  *  NumVertices: Number of vertices to be rendered
4040  *  Indices: Array of DWORDs used to index into the Vertices
4041  *  IndexCount: Number of indices in Indices
4042  *  Flags: Can be D3DDP_WAIT to wait until rendering has finished
4043  *
4044  * Return values
4045  *
4046  *****************************************************************************/
4047 static HRESULT d3d_device7_DrawIndexedPrimitiveVB(IDirect3DDevice7 *iface,
4048         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4049         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4050 {
4051     struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
4052     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer7(D3DVertexBuf);
4053     DWORD stride = get_flexible_vertex_size(vb->fvf);
4054     struct wined3d_resource *wined3d_resource;
4055     struct wined3d_resource_desc desc;
4056     WORD *LockedIndices;
4057     HRESULT hr;
4058
4059     TRACE("iface %p, primitive_type %#x, vb %p, start_vertex %u, vertex_count %u, indices %p, index_count %u, flags %#x.\n",
4060             iface, PrimitiveType, D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4061
4062     /* Steps:
4063      * 1) Upload the Indices to the index buffer
4064      * 2) Set the index source
4065      * 3) Set the Vertex Buffer as the Stream source
4066      * 4) Call IWineD3DDevice::DrawIndexedPrimitive
4067      */
4068
4069     wined3d_mutex_lock();
4070
4071     wined3d_device_set_vertex_declaration(This->wined3d_device, vb->wineD3DVertexDeclaration);
4072
4073     /* check that the buffer is large enough to hold the indices,
4074      * reallocate if necessary. */
4075     wined3d_resource = wined3d_buffer_get_resource(This->indexbuffer);
4076     wined3d_resource_get_desc(wined3d_resource, &desc);
4077     if (desc.size < IndexCount * sizeof(WORD))
4078     {
4079         UINT size = max(desc.size * 2, IndexCount * sizeof(WORD));
4080         struct wined3d_buffer *buffer;
4081
4082         TRACE("Growing index buffer to %u bytes\n", size);
4083
4084         hr = wined3d_buffer_create_ib(This->wined3d_device, size, WINED3DUSAGE_DYNAMIC /* Usage */,
4085                 WINED3D_POOL_DEFAULT, NULL, &ddraw_null_wined3d_parent_ops, &buffer);
4086         if (FAILED(hr))
4087         {
4088             ERR("(%p) IWineD3DDevice::CreateIndexBuffer failed with hr = %08x\n", This, hr);
4089             wined3d_mutex_unlock();
4090             return hr;
4091         }
4092
4093         wined3d_buffer_decref(This->indexbuffer);
4094         This->indexbuffer = buffer;
4095     }
4096
4097     /* Copy the index stream into the index buffer. A new IWineD3DDevice
4098      * method could be created which takes an user pointer containing the
4099      * indices or a SetData-Method for the index buffer, which overrides the
4100      * index buffer data with our pointer. */
4101     hr = wined3d_buffer_map(This->indexbuffer, 0, IndexCount * sizeof(WORD),
4102             (BYTE **)&LockedIndices, 0);
4103     if (FAILED(hr))
4104     {
4105         ERR("Failed to map buffer, hr %#x.\n", hr);
4106         wined3d_mutex_unlock();
4107         return hr;
4108     }
4109     memcpy(LockedIndices, Indices, IndexCount * sizeof(WORD));
4110     wined3d_buffer_unmap(This->indexbuffer);
4111
4112     /* Set the index stream */
4113     wined3d_device_set_base_vertex_index(This->wined3d_device, StartVertex);
4114     wined3d_device_set_index_buffer(This->wined3d_device, This->indexbuffer, WINED3DFMT_R16_UINT);
4115
4116     /* Set the vertex stream source */
4117     hr = wined3d_device_set_stream_source(This->wined3d_device, 0, vb->wineD3DVertexBuffer, 0, stride);
4118     if (FAILED(hr))
4119     {
4120         ERR("(%p) IDirect3DDevice::SetStreamSource failed with hr = %08x\n", This, hr);
4121         wined3d_mutex_unlock();
4122         return hr;
4123     }
4124
4125
4126     wined3d_device_set_primitive_type(This->wined3d_device, PrimitiveType);
4127     hr = wined3d_device_draw_indexed_primitive(This->wined3d_device, 0, IndexCount);
4128
4129     wined3d_mutex_unlock();
4130
4131     return hr;
4132 }
4133
4134 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUSetup(IDirect3DDevice7 *iface,
4135         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4136         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4137 {
4138     return d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4139             D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4140 }
4141
4142 static HRESULT WINAPI d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve(IDirect3DDevice7 *iface,
4143         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer7 *D3DVertexBuf,
4144         DWORD StartVertex, DWORD NumVertices, WORD *Indices, DWORD IndexCount, DWORD Flags)
4145 {
4146     HRESULT hr;
4147     WORD old_fpucw;
4148
4149     old_fpucw = d3d_fpu_setup();
4150     hr = d3d_device7_DrawIndexedPrimitiveVB(iface, PrimitiveType,
4151             D3DVertexBuf, StartVertex, NumVertices, Indices, IndexCount, Flags);
4152     set_fpu_control_word(old_fpucw);
4153
4154     return hr;
4155 }
4156
4157 static HRESULT WINAPI d3d_device3_DrawIndexedPrimitiveVB(IDirect3DDevice3 *iface,
4158         D3DPRIMITIVETYPE PrimitiveType, IDirect3DVertexBuffer *D3DVertexBuf, WORD *Indices,
4159         DWORD IndexCount, DWORD Flags)
4160 {
4161     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4162     struct d3d_vertex_buffer *vb = unsafe_impl_from_IDirect3DVertexBuffer(D3DVertexBuf);
4163
4164     TRACE("iface %p, primitive_type %#x, vb %p, indices %p, index_count %u, flags %#x.\n",
4165             iface, PrimitiveType, D3DVertexBuf, Indices, IndexCount, Flags);
4166
4167     return IDirect3DDevice7_DrawIndexedPrimitiveVB(&device->IDirect3DDevice7_iface, PrimitiveType,
4168             &vb->IDirect3DVertexBuffer7_iface, 0, IndexCount, Indices, IndexCount, Flags);
4169 }
4170
4171 /*****************************************************************************
4172  * IDirect3DDevice7::ComputeSphereVisibility
4173  *
4174  * Calculates the visibility of spheres in the current viewport. The spheres
4175  * are passed in the Centers and Radii arrays, the results are passed back
4176  * in the ReturnValues array. Return values are either completely visible,
4177  * partially visible or completely invisible.
4178  * The return value consist of a combination of D3DCLIP_* flags, or it's
4179  * 0 if the sphere is completely visible(according to the SDK, not checked)
4180  *
4181  * Version 3 and 7
4182  *
4183  * Params:
4184  *  Centers: Array containing the sphere centers
4185  *  Radii: Array containing the sphere radii
4186  *  NumSpheres: The number of centers and radii in the arrays
4187  *  Flags: Some flags
4188  *  ReturnValues: Array to write the results to
4189  *
4190  * Returns:
4191  *  D3D_OK
4192  *  (DDERR_INVALIDPARAMS if Centers, Radii or ReturnValues are NULL)
4193  *  (D3DERR_INVALIDMATRIX if the combined world, view and proj matrix
4194  *  is singular)
4195  *
4196  *****************************************************************************/
4197
4198 static DWORD in_plane(UINT plane, D3DVECTOR normal, D3DVALUE origin_plane, D3DVECTOR center, D3DVALUE radius)
4199 {
4200     float distance, norm;
4201
4202     norm = sqrt( normal.u1.x * normal.u1.x + normal.u2.y * normal.u2.y + normal.u3.z * normal.u3.z );
4203     distance = ( origin_plane + normal.u1.x * center.u1.x + normal.u2.y * center.u2.y + normal.u3.z * center.u3.z ) / norm;
4204
4205     if ( fabs( distance ) < radius ) return D3DSTATUS_CLIPUNIONLEFT << plane;
4206     if ( distance < -radius ) return (D3DSTATUS_CLIPUNIONLEFT  | D3DSTATUS_CLIPINTERSECTIONLEFT) << plane;
4207     return 0;
4208 }
4209
4210 static HRESULT WINAPI d3d_device7_ComputeSphereVisibility(IDirect3DDevice7 *iface,
4211         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4212 {
4213     D3DMATRIX m, temp;
4214     D3DVALUE origin_plane[6];
4215     D3DVECTOR vec[6];
4216     HRESULT hr;
4217     UINT i, j;
4218
4219     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4220             iface, centers, radii, sphere_count, flags, return_values);
4221
4222     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_WORLD, &m);
4223     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4224     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_VIEW, &temp);
4225     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4226     multiply_matrix(&m, &temp, &m);
4227
4228     hr = d3d_device7_GetTransform(iface, D3DTRANSFORMSTATE_PROJECTION, &temp);
4229     if ( hr != DD_OK ) return DDERR_INVALIDPARAMS;
4230     multiply_matrix(&m, &temp, &m);
4231
4232 /* Left plane */
4233     vec[0].u1.x = m._14 + m._11;
4234     vec[0].u2.y = m._24 + m._21;
4235     vec[0].u3.z = m._34 + m._31;
4236     origin_plane[0] = m._44 + m._41;
4237
4238 /* Right plane */
4239     vec[1].u1.x = m._14 - m._11;
4240     vec[1].u2.y = m._24 - m._21;
4241     vec[1].u3.z = m._34 - m._31;
4242     origin_plane[1] = m._44 - m._41;
4243
4244 /* Top plane */
4245     vec[2].u1.x = m._14 - m._12;
4246     vec[2].u2.y = m._24 - m._22;
4247     vec[2].u3.z = m._34 - m._32;
4248     origin_plane[2] = m._44 - m._42;
4249
4250 /* Bottom plane */
4251     vec[3].u1.x = m._14 + m._12;
4252     vec[3].u2.y = m._24 + m._22;
4253     vec[3].u3.z = m._34 + m._32;
4254     origin_plane[3] = m._44 + m._42;
4255
4256 /* Front plane */
4257     vec[4].u1.x = m._13;
4258     vec[4].u2.y = m._23;
4259     vec[4].u3.z = m._33;
4260     origin_plane[4] = m._43;
4261
4262 /* Back plane*/
4263     vec[5].u1.x = m._14 - m._13;
4264     vec[5].u2.y = m._24 - m._23;
4265     vec[5].u3.z = m._34 - m._33;
4266     origin_plane[5] = m._44 - m._43;
4267
4268     for (i = 0; i < sphere_count; ++i)
4269     {
4270         return_values[i] = 0;
4271         for (j = 0; j < 6; ++j)
4272             return_values[i] |= in_plane(j, vec[j], origin_plane[j], centers[i], radii[i]);
4273     }
4274
4275     return D3D_OK;
4276 }
4277
4278 static HRESULT WINAPI d3d_device3_ComputeSphereVisibility(IDirect3DDevice3 *iface,
4279         D3DVECTOR *centers, D3DVALUE *radii, DWORD sphere_count, DWORD flags, DWORD *return_values)
4280 {
4281     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4282
4283     TRACE("iface %p, centers %p, radii %p, sphere_count %u, flags %#x, return_values %p.\n",
4284             iface, centers, radii, sphere_count, flags, return_values);
4285
4286     return IDirect3DDevice7_ComputeSphereVisibility(&device->IDirect3DDevice7_iface,
4287             centers, radii, sphere_count, flags, return_values);
4288 }
4289
4290 /*****************************************************************************
4291  * IDirect3DDevice7::GetTexture
4292  *
4293  * Returns the texture interface handle assigned to a texture stage.
4294  * The returned texture is AddRefed. This is taken from old ddraw,
4295  * not checked in Windows.
4296  *
4297  * Version 3 and 7
4298  *
4299  * Params:
4300  *  Stage: Texture stage to read the texture from
4301  *  Texture: Address to store the interface pointer at
4302  *
4303  * Returns:
4304  *  D3D_OK on success
4305  *  DDERR_INVALIDPARAMS if Texture is NULL
4306  *  For details, see IWineD3DDevice::GetTexture
4307  *
4308  *****************************************************************************/
4309 static HRESULT d3d_device7_GetTexture(IDirect3DDevice7 *iface,
4310         DWORD stage, IDirectDrawSurface7 **texture)
4311 {
4312     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4313     struct wined3d_texture *wined3d_texture;
4314     struct ddraw_surface *surface;
4315     HRESULT hr;
4316
4317     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4318
4319     if (!texture)
4320         return DDERR_INVALIDPARAMS;
4321
4322     wined3d_mutex_lock();
4323     hr = wined3d_device_get_texture(device->wined3d_device, stage, &wined3d_texture);
4324     if (FAILED(hr) || !wined3d_texture)
4325     {
4326         *texture = NULL;
4327         wined3d_mutex_unlock();
4328         return hr;
4329     }
4330
4331     surface = wined3d_texture_get_parent(wined3d_texture);
4332     *texture = &surface->IDirectDrawSurface7_iface;
4333     IDirectDrawSurface7_AddRef(*texture);
4334     wined3d_texture_decref(wined3d_texture);
4335     wined3d_mutex_unlock();
4336
4337     return hr;
4338 }
4339
4340 static HRESULT WINAPI d3d_device7_GetTexture_FPUSetup(IDirect3DDevice7 *iface,
4341         DWORD stage, IDirectDrawSurface7 **Texture)
4342 {
4343     return d3d_device7_GetTexture(iface, stage, Texture);
4344 }
4345
4346 static HRESULT WINAPI d3d_device7_GetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4347         DWORD stage, IDirectDrawSurface7 **Texture)
4348 {
4349     HRESULT hr;
4350     WORD old_fpucw;
4351
4352     old_fpucw = d3d_fpu_setup();
4353     hr = d3d_device7_GetTexture(iface, stage, Texture);
4354     set_fpu_control_word(old_fpucw);
4355
4356     return hr;
4357 }
4358
4359 static HRESULT WINAPI d3d_device3_GetTexture(IDirect3DDevice3 *iface, DWORD stage, IDirect3DTexture2 **Texture2)
4360 {
4361     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4362     struct ddraw_surface *ret_val_impl;
4363     HRESULT ret;
4364     IDirectDrawSurface7 *ret_val;
4365
4366     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, Texture2);
4367
4368     ret = IDirect3DDevice7_GetTexture(&device->IDirect3DDevice7_iface, stage, &ret_val);
4369
4370     ret_val_impl = unsafe_impl_from_IDirectDrawSurface7(ret_val);
4371     *Texture2 = ret_val_impl ? &ret_val_impl->IDirect3DTexture2_iface : NULL;
4372
4373     TRACE("Returning texture %p.\n", *Texture2);
4374
4375     return ret;
4376 }
4377
4378 /*****************************************************************************
4379  * IDirect3DDevice7::SetTexture
4380  *
4381  * Assigns a texture to a texture stage. Is the texture AddRef-ed?
4382  *
4383  * Version 3 and 7
4384  *
4385  * Params:
4386  *  Stage: The stage to assign the texture to
4387  *  Texture: Interface pointer to the texture surface
4388  *
4389  * Returns
4390  * D3D_OK on success
4391  * For details, see IWineD3DDevice::SetTexture
4392  *
4393  *****************************************************************************/
4394 static HRESULT d3d_device7_SetTexture(IDirect3DDevice7 *iface,
4395         DWORD stage, IDirectDrawSurface7 *texture)
4396 {
4397     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4398     struct ddraw_surface *surf = unsafe_impl_from_IDirectDrawSurface7(texture);
4399     HRESULT hr;
4400
4401     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4402
4403     /* Texture may be NULL here */
4404     wined3d_mutex_lock();
4405     hr = wined3d_device_set_texture(device->wined3d_device,
4406             stage, surf ? surf->wined3d_texture : NULL);
4407     wined3d_mutex_unlock();
4408
4409     return hr;
4410 }
4411
4412 static HRESULT WINAPI d3d_device7_SetTexture_FPUSetup(IDirect3DDevice7 *iface,
4413         DWORD stage, IDirectDrawSurface7 *texture)
4414 {
4415     return d3d_device7_SetTexture(iface, stage, texture);
4416 }
4417
4418 static HRESULT WINAPI d3d_device7_SetTexture_FPUPreserve(IDirect3DDevice7 *iface,
4419         DWORD stage, IDirectDrawSurface7 *texture)
4420 {
4421     HRESULT hr;
4422     WORD old_fpucw;
4423
4424     old_fpucw = d3d_fpu_setup();
4425     hr = d3d_device7_SetTexture(iface, stage, texture);
4426     set_fpu_control_word(old_fpucw);
4427
4428     return hr;
4429 }
4430
4431 static HRESULT WINAPI d3d_device3_SetTexture(IDirect3DDevice3 *iface,
4432         DWORD stage, IDirect3DTexture2 *texture)
4433 {
4434     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4435     struct ddraw_surface *tex = unsafe_impl_from_IDirect3DTexture2(texture);
4436     DWORD texmapblend;
4437     HRESULT hr;
4438
4439     TRACE("iface %p, stage %u, texture %p.\n", iface, stage, texture);
4440
4441     wined3d_mutex_lock();
4442
4443     if (device->legacyTextureBlending)
4444         IDirect3DDevice3_GetRenderState(iface, D3DRENDERSTATE_TEXTUREMAPBLEND, &texmapblend);
4445
4446     hr = IDirect3DDevice7_SetTexture(&device->IDirect3DDevice7_iface, stage, &tex->IDirectDrawSurface7_iface);
4447
4448     if (device->legacyTextureBlending && texmapblend == D3DTBLEND_MODULATE)
4449     {
4450         /* This fixup is required by the way D3DTBLEND_MODULATE maps to texture stage states.
4451            See d3d_device3_SetRenderState() for details. */
4452         struct wined3d_texture *tex = NULL;
4453         BOOL tex_alpha = FALSE;
4454         DDPIXELFORMAT ddfmt;
4455         HRESULT result;
4456
4457         result = wined3d_device_get_texture(device->wined3d_device, 0, &tex);
4458         if (result == WINED3D_OK && tex)
4459         {
4460             struct wined3d_resource *sub_resource;
4461
4462             if ((sub_resource = wined3d_texture_get_sub_resource(tex, 0)))
4463             {
4464                 struct wined3d_resource_desc desc;
4465
4466                 wined3d_resource_get_desc(sub_resource, &desc);
4467                 ddfmt.dwSize = sizeof(ddfmt);
4468                 PixelFormat_WineD3DtoDD(&ddfmt, desc.format);
4469                 if (ddfmt.u5.dwRGBAlphaBitMask) tex_alpha = TRUE;
4470             }
4471
4472             wined3d_texture_decref(tex);
4473         }
4474
4475         /* Arg 1/2 are already set to WINED3DTA_TEXTURE/WINED3DTA_CURRENT in case of D3DTBLEND_MODULATE */
4476         if (tex_alpha)
4477             wined3d_device_set_texture_stage_state(device->wined3d_device,
4478                     0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG1);
4479         else
4480             wined3d_device_set_texture_stage_state(device->wined3d_device,
4481                     0, WINED3D_TSS_ALPHA_OP, WINED3D_TOP_SELECT_ARG2);
4482     }
4483
4484     wined3d_mutex_unlock();
4485
4486     return hr;
4487 }
4488
4489 static const struct tss_lookup
4490 {
4491     BOOL sampler_state;
4492     enum wined3d_texture_stage_state state;
4493 }
4494 tss_lookup[] =
4495 {
4496     {FALSE, WINED3D_TSS_INVALID},                   /*  0, unused */
4497     {FALSE, WINED3D_TSS_COLOR_OP},                  /*  1, D3DTSS_COLOROP */
4498     {FALSE, WINED3D_TSS_COLOR_ARG1},                /*  2, D3DTSS_COLORARG1 */
4499     {FALSE, WINED3D_TSS_COLOR_ARG2},                /*  3, D3DTSS_COLORARG2 */
4500     {FALSE, WINED3D_TSS_ALPHA_OP},                  /*  4, D3DTSS_ALPHAOP */
4501     {FALSE, WINED3D_TSS_ALPHA_ARG1},                /*  5, D3DTSS_ALPHAARG1 */
4502     {FALSE, WINED3D_TSS_ALPHA_ARG2},                /*  6, D3DTSS_ALPHAARG2 */
4503     {FALSE, WINED3D_TSS_BUMPENV_MAT00},             /*  7, D3DTSS_BUMPENVMAT00 */
4504     {FALSE, WINED3D_TSS_BUMPENV_MAT01},             /*  8, D3DTSS_BUMPENVMAT01 */
4505     {FALSE, WINED3D_TSS_BUMPENV_MAT10},             /*  9, D3DTSS_BUMPENVMAT10 */
4506     {FALSE, WINED3D_TSS_BUMPENV_MAT11},             /* 10, D3DTSS_BUMPENVMAT11 */
4507     {FALSE, WINED3D_TSS_TEXCOORD_INDEX},            /* 11, D3DTSS_TEXCOORDINDEX */
4508     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 12, D3DTSS_ADDRESS */
4509     {TRUE,  WINED3D_SAMP_ADDRESS_U},                /* 13, D3DTSS_ADDRESSU */
4510     {TRUE,  WINED3D_SAMP_ADDRESS_V},                /* 14, D3DTSS_ADDRESSV */
4511     {TRUE,  WINED3D_SAMP_BORDER_COLOR},             /* 15, D3DTSS_BORDERCOLOR */
4512     {TRUE,  WINED3D_SAMP_MAG_FILTER},               /* 16, D3DTSS_MAGFILTER */
4513     {TRUE,  WINED3D_SAMP_MIN_FILTER},               /* 17, D3DTSS_MINFILTER */
4514     {TRUE,  WINED3D_SAMP_MIP_FILTER},               /* 18, D3DTSS_MIPFILTER */
4515     {TRUE,  WINED3D_SAMP_MIPMAP_LOD_BIAS},          /* 19, D3DTSS_MIPMAPLODBIAS */
4516     {TRUE,  WINED3D_SAMP_MAX_MIP_LEVEL},            /* 20, D3DTSS_MAXMIPLEVEL */
4517     {TRUE,  WINED3D_SAMP_MAX_ANISOTROPY},           /* 21, D3DTSS_MAXANISOTROPY */
4518     {FALSE, WINED3D_TSS_BUMPENV_LSCALE},            /* 22, D3DTSS_BUMPENVLSCALE */
4519     {FALSE, WINED3D_TSS_BUMPENV_LOFFSET},           /* 23, D3DTSS_BUMPENVLOFFSET */
4520     {FALSE, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS},   /* 24, D3DTSS_TEXTURETRANSFORMFLAGS */
4521 };
4522
4523 /*****************************************************************************
4524  * IDirect3DDevice7::GetTextureStageState
4525  *
4526  * Retrieves a state from a texture stage.
4527  *
4528  * Version 3 and 7
4529  *
4530  * Params:
4531  *  Stage: The stage to retrieve the state from
4532  *  TexStageStateType: The state type to retrieve
4533  *  State: Address to store the state's value at
4534  *
4535  * Returns:
4536  *  D3D_OK on success
4537  *  DDERR_INVALIDPARAMS if State is NULL
4538  *  For details, see IWineD3DDevice::GetTextureStageState
4539  *
4540  *****************************************************************************/
4541 static HRESULT d3d_device7_GetTextureStageState(IDirect3DDevice7 *iface,
4542         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4543 {
4544     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4545     const struct tss_lookup *l;
4546     HRESULT hr = D3D_OK;
4547
4548     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4549             iface, stage, state, value);
4550
4551     if (!value)
4552         return DDERR_INVALIDPARAMS;
4553
4554     if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4555     {
4556         WARN("Invalid state %#x passed.\n", state);
4557         return DD_OK;
4558     }
4559
4560     l = &tss_lookup[state];
4561
4562     wined3d_mutex_lock();
4563
4564     if (l->sampler_state)
4565     {
4566         *value = wined3d_device_get_sampler_state(device->wined3d_device, stage, l->state);
4567
4568         switch (state)
4569         {
4570             /* Mipfilter is a sampler state with different values */
4571             case D3DTSS_MIPFILTER:
4572             {
4573                 switch (*value)
4574                 {
4575                     case WINED3D_TEXF_NONE:
4576                         *value = D3DTFP_NONE;
4577                         break;
4578                     case WINED3D_TEXF_POINT:
4579                         *value = D3DTFP_POINT;
4580                         break;
4581                     case WINED3D_TEXF_LINEAR:
4582                         *value = D3DTFP_LINEAR;
4583                         break;
4584                     default:
4585                         ERR("Unexpected mipfilter value %#x.\n", *value);
4586                         *value = D3DTFP_NONE;
4587                         break;
4588                 }
4589                 break;
4590             }
4591
4592             /* Magfilter has slightly different values */
4593             case D3DTSS_MAGFILTER:
4594             {
4595                 switch (*value)
4596                 {
4597                     case WINED3D_TEXF_POINT:
4598                             *value = D3DTFG_POINT;
4599                             break;
4600                     case WINED3D_TEXF_LINEAR:
4601                             *value = D3DTFG_LINEAR;
4602                             break;
4603                     case WINED3D_TEXF_ANISOTROPIC:
4604                             *value = D3DTFG_ANISOTROPIC;
4605                             break;
4606                     case WINED3D_TEXF_FLAT_CUBIC:
4607                             *value = D3DTFG_FLATCUBIC;
4608                             break;
4609                     case WINED3D_TEXF_GAUSSIAN_CUBIC:
4610                             *value = D3DTFG_GAUSSIANCUBIC;
4611                             break;
4612                     default:
4613                         ERR("Unexpected wined3d mag filter value %#x.\n", *value);
4614                         *value = D3DTFG_POINT;
4615                         break;
4616                 }
4617                 break;
4618             }
4619
4620             default:
4621                 break;
4622         }
4623     }
4624     else
4625     {
4626         hr = wined3d_device_get_texture_stage_state(device->wined3d_device, stage, l->state, value);
4627     }
4628
4629     wined3d_mutex_unlock();
4630
4631     return hr;
4632 }
4633
4634 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4635         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4636 {
4637     return d3d_device7_GetTextureStageState(iface, stage, state, value);
4638 }
4639
4640 static HRESULT WINAPI d3d_device7_GetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4641         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4642 {
4643     HRESULT hr;
4644     WORD old_fpucw;
4645
4646     old_fpucw = d3d_fpu_setup();
4647     hr = d3d_device7_GetTextureStageState(iface, stage, state, value);
4648     set_fpu_control_word(old_fpucw);
4649
4650     return hr;
4651 }
4652
4653 static HRESULT WINAPI d3d_device3_GetTextureStageState(IDirect3DDevice3 *iface,
4654         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD *value)
4655 {
4656     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4657
4658     TRACE("iface %p, stage %u, state %#x, value %p.\n",
4659             iface, stage, state, value);
4660
4661     return IDirect3DDevice7_GetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4662 }
4663
4664 /*****************************************************************************
4665  * IDirect3DDevice7::SetTextureStageState
4666  *
4667  * Sets a texture stage state. Some stage types need to be handled specially,
4668  * because they do not exist in WineD3D and were moved to another place
4669  *
4670  * Version 3 and 7
4671  *
4672  * Params:
4673  *  Stage: The stage to modify
4674  *  TexStageStateType: The state to change
4675  *  State: The new value for the state
4676  *
4677  * Returns:
4678  *  D3D_OK on success
4679  *  For details, see IWineD3DDevice::SetTextureStageState
4680  *
4681  *****************************************************************************/
4682 static HRESULT d3d_device7_SetTextureStageState(IDirect3DDevice7 *iface,
4683         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4684 {
4685     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4686     const struct tss_lookup *l;
4687
4688     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4689             iface, stage, state, value);
4690
4691     if (state > D3DTSS_TEXTURETRANSFORMFLAGS)
4692     {
4693         WARN("Invalid state %#x passed.\n", state);
4694         return DD_OK;
4695     }
4696
4697     l = &tss_lookup[state];
4698
4699     wined3d_mutex_lock();
4700
4701     if (l->sampler_state)
4702     {
4703         switch (state)
4704         {
4705             /* Mipfilter is a sampler state with different values */
4706             case D3DTSS_MIPFILTER:
4707             {
4708                 switch (value)
4709                 {
4710                     case D3DTFP_NONE:
4711                         value = WINED3D_TEXF_NONE;
4712                         break;
4713                     case D3DTFP_POINT:
4714                         value = WINED3D_TEXF_POINT;
4715                         break;
4716                     case 0: /* Unchecked */
4717                     case D3DTFP_LINEAR:
4718                         value = WINED3D_TEXF_LINEAR;
4719                         break;
4720                     default:
4721                         ERR("Unexpected mipfilter value %#x.\n", value);
4722                         value = WINED3D_TEXF_NONE;
4723                         break;
4724                 }
4725                 break;
4726             }
4727
4728             /* Magfilter has slightly different values */
4729             case D3DTSS_MAGFILTER:
4730             {
4731                 switch (value)
4732                 {
4733                     case D3DTFG_POINT:
4734                         value = WINED3D_TEXF_POINT;
4735                         break;
4736                     case D3DTFG_LINEAR:
4737                         value = WINED3D_TEXF_LINEAR;
4738                         break;
4739                     case D3DTFG_FLATCUBIC:
4740                         value = WINED3D_TEXF_FLAT_CUBIC;
4741                         break;
4742                     case D3DTFG_GAUSSIANCUBIC:
4743                         value = WINED3D_TEXF_GAUSSIAN_CUBIC;
4744                         break;
4745                     case D3DTFG_ANISOTROPIC:
4746                         value = WINED3D_TEXF_ANISOTROPIC;
4747                         break;
4748                     default:
4749                         ERR("Unexpected d3d7 mag filter value %#x.\n", value);
4750                         value = WINED3D_TEXF_POINT;
4751                         break;
4752                 }
4753                 break;
4754             }
4755
4756             case D3DTSS_ADDRESS:
4757                 wined3d_device_set_sampler_state(device->wined3d_device, stage, WINED3D_SAMP_ADDRESS_V, value);
4758                 break;
4759
4760             default:
4761                 break;
4762         }
4763
4764         wined3d_device_set_sampler_state(device->wined3d_device, stage, l->state, value);
4765     }
4766     else
4767     {
4768         wined3d_device_set_texture_stage_state(device->wined3d_device, stage, l->state, value);
4769     }
4770
4771     wined3d_mutex_unlock();
4772
4773     return D3D_OK;
4774 }
4775
4776 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUSetup(IDirect3DDevice7 *iface,
4777         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4778 {
4779     return d3d_device7_SetTextureStageState(iface, stage, state, value);
4780 }
4781
4782 static HRESULT WINAPI d3d_device7_SetTextureStageState_FPUPreserve(IDirect3DDevice7 *iface,
4783         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4784 {
4785     HRESULT hr;
4786     WORD old_fpucw;
4787
4788     old_fpucw = d3d_fpu_setup();
4789     hr = d3d_device7_SetTextureStageState(iface, stage, state, value);
4790     set_fpu_control_word(old_fpucw);
4791
4792     return hr;
4793 }
4794
4795 static HRESULT WINAPI d3d_device3_SetTextureStageState(IDirect3DDevice3 *iface,
4796         DWORD stage, D3DTEXTURESTAGESTATETYPE state, DWORD value)
4797 {
4798     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4799
4800     TRACE("iface %p, stage %u, state %#x, value %#x.\n",
4801             iface, stage, state, value);
4802
4803     return IDirect3DDevice7_SetTextureStageState(&device->IDirect3DDevice7_iface, stage, state, value);
4804 }
4805
4806 /*****************************************************************************
4807  * IDirect3DDevice7::ValidateDevice
4808  *
4809  * SDK: "Reports the device's ability to render the currently set
4810  * texture-blending operations in a single pass". Whatever that means
4811  * exactly...
4812  *
4813  * Version 3 and 7
4814  *
4815  * Params:
4816  *  NumPasses: Address to write the number of necessary passes for the
4817  *             desired effect to.
4818  *
4819  * Returns:
4820  *  D3D_OK on success
4821  *  See IWineD3DDevice::ValidateDevice for more details
4822  *
4823  *****************************************************************************/
4824 static HRESULT d3d_device7_ValidateDevice(IDirect3DDevice7 *iface, DWORD *pass_count)
4825 {
4826     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4827     HRESULT hr;
4828
4829     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4830
4831     wined3d_mutex_lock();
4832     hr = wined3d_device_validate_device(device->wined3d_device, pass_count);
4833     wined3d_mutex_unlock();
4834
4835     return hr;
4836 }
4837
4838 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUSetup(IDirect3DDevice7 *iface, DWORD *pass_count)
4839 {
4840     return d3d_device7_ValidateDevice(iface, pass_count);
4841 }
4842
4843 static HRESULT WINAPI d3d_device7_ValidateDevice_FPUPreserve(IDirect3DDevice7 *iface, DWORD *pass_count)
4844 {
4845     HRESULT hr;
4846     WORD old_fpucw;
4847
4848     old_fpucw = d3d_fpu_setup();
4849     hr = d3d_device7_ValidateDevice(iface, pass_count);
4850     set_fpu_control_word(old_fpucw);
4851
4852     return hr;
4853 }
4854
4855 static HRESULT WINAPI d3d_device3_ValidateDevice(IDirect3DDevice3 *iface, DWORD *pass_count)
4856 {
4857     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
4858
4859     TRACE("iface %p, pass_count %p.\n", iface, pass_count);
4860
4861     return IDirect3DDevice7_ValidateDevice(&device->IDirect3DDevice7_iface, pass_count);
4862 }
4863
4864 /*****************************************************************************
4865  * IDirect3DDevice7::Clear
4866  *
4867  * Fills the render target, the z buffer and the stencil buffer with a
4868  * clear color / value
4869  *
4870  * Version 7 only
4871  *
4872  * Params:
4873  *  Count: Number of rectangles in Rects must be 0 if Rects is NULL
4874  *  Rects: Rectangles to clear. If NULL, the whole surface is cleared
4875  *  Flags: Some flags, as usual
4876  *  Color: Clear color for the render target
4877  *  Z: Clear value for the Z buffer
4878  *  Stencil: Clear value to store in each stencil buffer entry
4879  *
4880  * Returns:
4881  *  D3D_OK on success
4882  *  For details, see IWineD3DDevice::Clear
4883  *
4884  *****************************************************************************/
4885 static HRESULT d3d_device7_Clear(IDirect3DDevice7 *iface, DWORD count,
4886         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4887 {
4888     const struct wined3d_color c =
4889     {
4890         ((color >> 16) & 0xff) / 255.0f,
4891         ((color >>  8) & 0xff) / 255.0f,
4892         (color & 0xff) / 255.0f,
4893         ((color >> 24) & 0xff) / 255.0f,
4894     };
4895     struct d3d_device *This = impl_from_IDirect3DDevice7(iface);
4896     HRESULT hr;
4897
4898     TRACE("iface %p, count %u, rects %p, flags %#x, color 0x%08x, z %.8e, stencil %#x.\n",
4899             iface, count, rects, flags, color, z, stencil);
4900
4901     wined3d_mutex_lock();
4902     hr = wined3d_device_clear(This->wined3d_device, count, (RECT *)rects, flags, &c, z, stencil);
4903     wined3d_mutex_unlock();
4904
4905     return hr;
4906 }
4907
4908 static HRESULT WINAPI d3d_device7_Clear_FPUSetup(IDirect3DDevice7 *iface, DWORD count,
4909         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4910 {
4911     return d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
4912 }
4913
4914 static HRESULT WINAPI d3d_device7_Clear_FPUPreserve(IDirect3DDevice7 *iface, DWORD count,
4915         D3DRECT *rects, DWORD flags, D3DCOLOR color, D3DVALUE z, DWORD stencil)
4916 {
4917     HRESULT hr;
4918     WORD old_fpucw;
4919
4920     old_fpucw = d3d_fpu_setup();
4921     hr = d3d_device7_Clear(iface, count, rects, flags, color, z, stencil);
4922     set_fpu_control_word(old_fpucw);
4923
4924     return hr;
4925 }
4926
4927 /*****************************************************************************
4928  * IDirect3DDevice7::SetViewport
4929  *
4930  * Sets the current viewport.
4931  *
4932  * Version 7 only, but IDirect3DViewport uses this call for older
4933  * versions
4934  *
4935  * Params:
4936  *  Data: The new viewport to set
4937  *
4938  * Returns:
4939  *  D3D_OK on success
4940  *  DDERR_INVALIDPARAMS if Data is NULL
4941  *  For more details, see IWineDDDevice::SetViewport
4942  *
4943  *****************************************************************************/
4944 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4945 {
4946     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4947
4948     TRACE("iface %p, viewport %p.\n", iface, viewport);
4949
4950     if (!viewport)
4951         return DDERR_INVALIDPARAMS;
4952
4953     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
4954     wined3d_mutex_lock();
4955     wined3d_device_set_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
4956     wined3d_mutex_unlock();
4957
4958     return D3D_OK;
4959 }
4960
4961 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4962 {
4963     return d3d_device7_SetViewport(iface, viewport);
4964 }
4965
4966 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4967 {
4968     HRESULT hr;
4969     WORD old_fpucw;
4970
4971     old_fpucw = d3d_fpu_setup();
4972     hr = d3d_device7_SetViewport(iface, viewport);
4973     set_fpu_control_word(old_fpucw);
4974
4975     return hr;
4976 }
4977
4978 /*****************************************************************************
4979  * IDirect3DDevice::GetViewport
4980  *
4981  * Returns the current viewport
4982  *
4983  * Version 7
4984  *
4985  * Params:
4986  *  Data: D3D7Viewport structure to write the viewport information to
4987  *
4988  * Returns:
4989  *  D3D_OK on success
4990  *  DDERR_INVALIDPARAMS if Data is NULL
4991  *  For more details, see IWineD3DDevice::GetViewport
4992  *
4993  *****************************************************************************/
4994 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
4995 {
4996     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
4997
4998     TRACE("iface %p, viewport %p.\n", iface, viewport);
4999
5000     if (!viewport)
5001         return DDERR_INVALIDPARAMS;
5002
5003     /* Note: D3DVIEWPORT7 is compatible with struct wined3d_viewport. */
5004     wined3d_mutex_lock();
5005     wined3d_device_get_viewport(device->wined3d_device, (struct wined3d_viewport *)viewport);
5006     wined3d_mutex_unlock();
5007
5008     return D3D_OK;
5009 }
5010
5011 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5012 {
5013     return d3d_device7_GetViewport(iface, viewport);
5014 }
5015
5016 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5017 {
5018     HRESULT hr;
5019     WORD old_fpucw;
5020
5021     old_fpucw = d3d_fpu_setup();
5022     hr = d3d_device7_GetViewport(iface, viewport);
5023     set_fpu_control_word(old_fpucw);
5024
5025     return hr;
5026 }
5027
5028 /*****************************************************************************
5029  * IDirect3DDevice7::SetMaterial
5030  *
5031  * Sets the Material
5032  *
5033  * Version 7
5034  *
5035  * Params:
5036  *  Mat: The material to set
5037  *
5038  * Returns:
5039  *  D3D_OK on success
5040  *  DDERR_INVALIDPARAMS if Mat is NULL.
5041  *  For more details, see IWineD3DDevice::SetMaterial
5042  *
5043  *****************************************************************************/
5044 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5045 {
5046     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5047
5048     TRACE("iface %p, material %p.\n", iface, material);
5049
5050     if (!material)
5051         return DDERR_INVALIDPARAMS;
5052
5053     wined3d_mutex_lock();
5054     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5055     wined3d_device_set_material(device->wined3d_device, (struct wined3d_material *)material);
5056     wined3d_mutex_unlock();
5057
5058     return D3D_OK;
5059 }
5060
5061 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5062 {
5063     return d3d_device7_SetMaterial(iface, material);
5064 }
5065
5066 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5067 {
5068     HRESULT hr;
5069     WORD old_fpucw;
5070
5071     old_fpucw = d3d_fpu_setup();
5072     hr = d3d_device7_SetMaterial(iface, material);
5073     set_fpu_control_word(old_fpucw);
5074
5075     return hr;
5076 }
5077
5078 /*****************************************************************************
5079  * IDirect3DDevice7::GetMaterial
5080  *
5081  * Returns the current material
5082  *
5083  * Version 7
5084  *
5085  * Params:
5086  *  Mat: D3DMATERIAL7 structure to write the material parameters to
5087  *
5088  * Returns:
5089  *  D3D_OK on success
5090  *  DDERR_INVALIDPARAMS if Mat is NULL
5091  *  For more details, see IWineD3DDevice::GetMaterial
5092  *
5093  *****************************************************************************/
5094 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5095 {
5096     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5097
5098     TRACE("iface %p, material %p.\n", iface, material);
5099
5100     wined3d_mutex_lock();
5101     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5102     wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
5103     wined3d_mutex_unlock();
5104
5105     return D3D_OK;
5106 }
5107
5108 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5109 {
5110     return d3d_device7_GetMaterial(iface, material);
5111 }
5112
5113 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5114 {
5115     HRESULT hr;
5116     WORD old_fpucw;
5117
5118     old_fpucw = d3d_fpu_setup();
5119     hr = d3d_device7_GetMaterial(iface, material);
5120     set_fpu_control_word(old_fpucw);
5121
5122     return hr;
5123 }
5124
5125 /*****************************************************************************
5126  * IDirect3DDevice7::SetLight
5127  *
5128  * Assigns a light to a light index, but doesn't activate it yet.
5129  *
5130  * Version 7, IDirect3DLight uses this method for older versions
5131  *
5132  * Params:
5133  *  LightIndex: The index of the new light
5134  *  Light: A D3DLIGHT7 structure describing the light
5135  *
5136  * Returns:
5137  *  D3D_OK on success
5138  *  For more details, see IWineD3DDevice::SetLight
5139  *
5140  *****************************************************************************/
5141 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5142 {
5143     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5144     HRESULT hr;
5145
5146     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5147
5148     wined3d_mutex_lock();
5149     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5150     hr = wined3d_device_set_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5151     wined3d_mutex_unlock();
5152
5153     return hr_ddraw_from_wined3d(hr);
5154 }
5155
5156 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5157 {
5158     return d3d_device7_SetLight(iface, light_idx, light);
5159 }
5160
5161 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5162 {
5163     HRESULT hr;
5164     WORD old_fpucw;
5165
5166     old_fpucw = d3d_fpu_setup();
5167     hr = d3d_device7_SetLight(iface, light_idx, light);
5168     set_fpu_control_word(old_fpucw);
5169
5170     return hr;
5171 }
5172
5173 /*****************************************************************************
5174  * IDirect3DDevice7::GetLight
5175  *
5176  * Returns the light assigned to a light index
5177  *
5178  * Params:
5179  *  Light: Structure to write the light information to
5180  *
5181  * Returns:
5182  *  D3D_OK on success
5183  *  DDERR_INVALIDPARAMS if Light is NULL
5184  *  For details, see IWineD3DDevice::GetLight
5185  *
5186  *****************************************************************************/
5187 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5188 {
5189     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5190     HRESULT rc;
5191
5192     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5193
5194     wined3d_mutex_lock();
5195     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5196     rc =  wined3d_device_get_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5197     wined3d_mutex_unlock();
5198
5199     /* Translate the result. WineD3D returns other values than D3D7 */
5200     return hr_ddraw_from_wined3d(rc);
5201 }
5202
5203 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5204 {
5205     return d3d_device7_GetLight(iface, light_idx, light);
5206 }
5207
5208 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5209 {
5210     HRESULT hr;
5211     WORD old_fpucw;
5212
5213     old_fpucw = d3d_fpu_setup();
5214     hr = d3d_device7_GetLight(iface, light_idx, light);
5215     set_fpu_control_word(old_fpucw);
5216
5217     return hr;
5218 }
5219
5220 /*****************************************************************************
5221  * IDirect3DDevice7::BeginStateBlock
5222  *
5223  * Begins recording to a stateblock
5224  *
5225  * Version 7
5226  *
5227  * Returns:
5228  *  D3D_OK on success
5229  *  For details see IWineD3DDevice::BeginStateBlock
5230  *
5231  *****************************************************************************/
5232 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5233 {
5234     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5235     HRESULT hr;
5236
5237     TRACE("iface %p.\n", iface);
5238
5239     wined3d_mutex_lock();
5240     hr = wined3d_device_begin_stateblock(device->wined3d_device);
5241     wined3d_mutex_unlock();
5242
5243     return hr_ddraw_from_wined3d(hr);
5244 }
5245
5246 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5247 {
5248     return d3d_device7_BeginStateBlock(iface);
5249 }
5250
5251 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5252 {
5253     HRESULT hr;
5254     WORD old_fpucw;
5255
5256     old_fpucw = d3d_fpu_setup();
5257     hr = d3d_device7_BeginStateBlock(iface);
5258     set_fpu_control_word(old_fpucw);
5259
5260     return hr;
5261 }
5262
5263 /*****************************************************************************
5264  * IDirect3DDevice7::EndStateBlock
5265  *
5266  * Stops recording to a state block and returns the created stateblock
5267  * handle.
5268  *
5269  * Version 7
5270  *
5271  * Params:
5272  *  BlockHandle: Address to store the stateblock's handle to
5273  *
5274  * Returns:
5275  *  D3D_OK on success
5276  *  DDERR_INVALIDPARAMS if BlockHandle is NULL
5277  *  See IWineD3DDevice::EndStateBlock for more details
5278  *
5279  *****************************************************************************/
5280 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5281 {
5282     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5283     struct wined3d_stateblock *wined3d_sb;
5284     HRESULT hr;
5285     DWORD h;
5286
5287     TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5288
5289     if (!stateblock)
5290         return DDERR_INVALIDPARAMS;
5291
5292     wined3d_mutex_lock();
5293
5294     hr = wined3d_device_end_stateblock(device->wined3d_device, &wined3d_sb);
5295     if (FAILED(hr))
5296     {
5297         WARN("Failed to end stateblock, hr %#x.\n", hr);
5298         wined3d_mutex_unlock();
5299         *stateblock = 0;
5300         return hr_ddraw_from_wined3d(hr);
5301     }
5302
5303     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5304     if (h == DDRAW_INVALID_HANDLE)
5305     {
5306         ERR("Failed to allocate a stateblock handle.\n");
5307         wined3d_stateblock_decref(wined3d_sb);
5308         wined3d_mutex_unlock();
5309         *stateblock = 0;
5310         return DDERR_OUTOFMEMORY;
5311     }
5312
5313     wined3d_mutex_unlock();
5314     *stateblock = h + 1;
5315
5316     return hr_ddraw_from_wined3d(hr);
5317 }
5318
5319 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5320 {
5321     return d3d_device7_EndStateBlock(iface, stateblock);
5322 }
5323
5324 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5325 {
5326     HRESULT hr;
5327     WORD old_fpucw;
5328
5329     old_fpucw = d3d_fpu_setup();
5330     hr = d3d_device7_EndStateBlock(iface, stateblock);
5331     set_fpu_control_word(old_fpucw);
5332
5333     return hr;
5334 }
5335
5336 /*****************************************************************************
5337  * IDirect3DDevice7::PreLoad
5338  *
5339  * Allows the app to signal that a texture will be used soon, to allow
5340  * the Direct3DDevice to load it to the video card in the meantime.
5341  *
5342  * Version 7
5343  *
5344  * Params:
5345  *  Texture: The texture to preload
5346  *
5347  * Returns:
5348  *  D3D_OK on success
5349  *  DDERR_INVALIDPARAMS if Texture is NULL
5350  *  See IWineD3DSurface::PreLoad for details
5351  *
5352  *****************************************************************************/
5353 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5354 {
5355     struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5356
5357     TRACE("iface %p, texture %p.\n", iface, texture);
5358
5359     if (!texture)
5360         return DDERR_INVALIDPARAMS;
5361
5362     wined3d_mutex_lock();
5363     wined3d_surface_preload(surface->wined3d_surface);
5364     wined3d_mutex_unlock();
5365
5366     return D3D_OK;
5367 }
5368
5369 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5370 {
5371     return d3d_device7_PreLoad(iface, texture);
5372 }
5373
5374 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5375 {
5376     HRESULT hr;
5377     WORD old_fpucw;
5378
5379     old_fpucw = d3d_fpu_setup();
5380     hr = d3d_device7_PreLoad(iface, texture);
5381     set_fpu_control_word(old_fpucw);
5382
5383     return hr;
5384 }
5385
5386 /*****************************************************************************
5387  * IDirect3DDevice7::ApplyStateBlock
5388  *
5389  * Activates the state stored in a state block handle.
5390  *
5391  * Params:
5392  *  BlockHandle: The stateblock handle to activate
5393  *
5394  * Returns:
5395  *  D3D_OK on success
5396  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5397  *
5398  *****************************************************************************/
5399 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5400 {
5401     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5402     struct wined3d_stateblock *wined3d_sb;
5403     HRESULT hr;
5404
5405     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5406
5407     wined3d_mutex_lock();
5408     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5409     if (!wined3d_sb)
5410     {
5411         WARN("Invalid stateblock handle.\n");
5412         wined3d_mutex_unlock();
5413         return D3DERR_INVALIDSTATEBLOCK;
5414     }
5415
5416     hr = wined3d_stateblock_apply(wined3d_sb);
5417     wined3d_mutex_unlock();
5418
5419     return hr_ddraw_from_wined3d(hr);
5420 }
5421
5422 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5423 {
5424     return d3d_device7_ApplyStateBlock(iface, stateblock);
5425 }
5426
5427 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5428 {
5429     HRESULT hr;
5430     WORD old_fpucw;
5431
5432     old_fpucw = d3d_fpu_setup();
5433     hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5434     set_fpu_control_word(old_fpucw);
5435
5436     return hr;
5437 }
5438
5439 /*****************************************************************************
5440  * IDirect3DDevice7::CaptureStateBlock
5441  *
5442  * Updates a stateblock's values to the values currently set for the device
5443  *
5444  * Version 7
5445  *
5446  * Params:
5447  *  BlockHandle: Stateblock to update
5448  *
5449  * Returns:
5450  *  D3D_OK on success
5451  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5452  *  See IWineD3DDevice::CaptureStateBlock for more details
5453  *
5454  *****************************************************************************/
5455 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5456 {
5457     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5458     struct wined3d_stateblock *wined3d_sb;
5459     HRESULT hr;
5460
5461     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5462
5463     wined3d_mutex_lock();
5464     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5465     if (!wined3d_sb)
5466     {
5467         WARN("Invalid stateblock handle.\n");
5468         wined3d_mutex_unlock();
5469         return D3DERR_INVALIDSTATEBLOCK;
5470     }
5471
5472     hr = wined3d_stateblock_capture(wined3d_sb);
5473     wined3d_mutex_unlock();
5474
5475     return hr_ddraw_from_wined3d(hr);
5476 }
5477
5478 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5479 {
5480     return d3d_device7_CaptureStateBlock(iface, stateblock);
5481 }
5482
5483 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5484 {
5485     HRESULT hr;
5486     WORD old_fpucw;
5487
5488     old_fpucw = d3d_fpu_setup();
5489     hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5490     set_fpu_control_word(old_fpucw);
5491
5492     return hr;
5493 }
5494
5495 /*****************************************************************************
5496  * IDirect3DDevice7::DeleteStateBlock
5497  *
5498  * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5499  *
5500  * Version 7
5501  *
5502  * Params:
5503  *  BlockHandle: Stateblock handle to delete
5504  *
5505  * Returns:
5506  *  D3D_OK on success
5507  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5508  *
5509  *****************************************************************************/
5510 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5511 {
5512     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5513     struct wined3d_stateblock *wined3d_sb;
5514     ULONG ref;
5515
5516     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5517
5518     wined3d_mutex_lock();
5519
5520     wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5521     if (!wined3d_sb)
5522     {
5523         WARN("Invalid stateblock handle.\n");
5524         wined3d_mutex_unlock();
5525         return D3DERR_INVALIDSTATEBLOCK;
5526     }
5527
5528     if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5529     {
5530         ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5531     }
5532
5533     wined3d_mutex_unlock();
5534
5535     return D3D_OK;
5536 }
5537
5538 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5539 {
5540     return d3d_device7_DeleteStateBlock(iface, stateblock);
5541 }
5542
5543 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5544 {
5545     HRESULT hr;
5546     WORD old_fpucw;
5547
5548     old_fpucw = d3d_fpu_setup();
5549     hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5550     set_fpu_control_word(old_fpucw);
5551
5552     return hr;
5553 }
5554
5555 /*****************************************************************************
5556  * IDirect3DDevice7::CreateStateBlock
5557  *
5558  * Creates a new state block handle.
5559  *
5560  * Version 7
5561  *
5562  * Params:
5563  *  Type: The state block type
5564  *  BlockHandle: Address to write the created handle to
5565  *
5566  * Returns:
5567  *   D3D_OK on success
5568  *   DDERR_INVALIDPARAMS if BlockHandle is NULL
5569  *
5570  *****************************************************************************/
5571 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
5572         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5573 {
5574     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5575     struct wined3d_stateblock *wined3d_sb;
5576     HRESULT hr;
5577     DWORD h;
5578
5579     TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
5580
5581     if (!stateblock)
5582         return DDERR_INVALIDPARAMS;
5583
5584     if (type != D3DSBT_ALL
5585             && type != D3DSBT_PIXELSTATE
5586             && type != D3DSBT_VERTEXSTATE)
5587     {
5588         WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5589         return DDERR_INVALIDPARAMS;
5590     }
5591
5592     wined3d_mutex_lock();
5593
5594     /* The D3DSTATEBLOCKTYPE enum is fine here. */
5595     hr = wined3d_stateblock_create(device->wined3d_device, type, &wined3d_sb);
5596     if (FAILED(hr))
5597     {
5598         WARN("Failed to create stateblock, hr %#x.\n", hr);
5599         wined3d_mutex_unlock();
5600         return hr_ddraw_from_wined3d(hr);
5601     }
5602
5603     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5604     if (h == DDRAW_INVALID_HANDLE)
5605     {
5606         ERR("Failed to allocate stateblock handle.\n");
5607         wined3d_stateblock_decref(wined3d_sb);
5608         wined3d_mutex_unlock();
5609         return DDERR_OUTOFMEMORY;
5610     }
5611
5612     *stateblock = h + 1;
5613     wined3d_mutex_unlock();
5614
5615     return hr_ddraw_from_wined3d(hr);
5616 }
5617
5618 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5619         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5620 {
5621     return d3d_device7_CreateStateBlock(iface, type, stateblock);
5622 }
5623
5624 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5625         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5626 {
5627     HRESULT hr;
5628     WORD old_fpucw;
5629
5630     old_fpucw = d3d_fpu_setup();
5631     hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
5632     set_fpu_control_word(old_fpucw);
5633
5634     return hr;
5635 }
5636
5637 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
5638 {
5639     struct ddraw_surface *src_level, *dest_level;
5640     IDirectDrawSurface7 *temp;
5641     DDSURFACEDESC2 ddsd;
5642     BOOL levelFound; /* at least one suitable sublevel in dest found */
5643
5644     /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
5645      * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
5646      * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
5647      */
5648     levelFound = FALSE;
5649
5650     src_level = src;
5651     dest_level = dest;
5652
5653     for (;src_level && dest_level;)
5654     {
5655         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5656             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5657         {
5658             levelFound = TRUE;
5659
5660             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5661             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5662             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5663
5664             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5665
5666             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5667         }
5668
5669         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5670         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5671         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5672
5673         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5674
5675         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5676     }
5677
5678     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5679     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5680
5681     return !dest_level && levelFound;
5682 }
5683
5684 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dest,
5685         struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
5686 {
5687     struct ddraw_surface *src_level, *dest_level;
5688     IDirectDrawSurface7 *temp;
5689     DDSURFACEDESC2 ddsd;
5690     POINT point;
5691     RECT src_rect;
5692     HRESULT hr;
5693     IDirectDrawPalette *pal = NULL, *pal_src = NULL;
5694     DWORD ckeyflag;
5695     DDCOLORKEY ddckey;
5696
5697     /* Copy palette, if possible. */
5698     IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
5699     IDirectDrawSurface7_GetPalette(&dest->IDirectDrawSurface7_iface, &pal);
5700
5701     if (pal_src != NULL && pal != NULL)
5702     {
5703         PALETTEENTRY palent[256];
5704
5705         IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
5706         IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
5707     }
5708
5709     if (pal) IDirectDrawPalette_Release(pal);
5710     if (pal_src) IDirectDrawPalette_Release(pal_src);
5711
5712     /* Copy colorkeys, if present. */
5713     for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
5714     {
5715         hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5716
5717         if (SUCCEEDED(hr))
5718         {
5719             IDirectDrawSurface7_SetColorKey(&dest->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
5720         }
5721     }
5722
5723     src_level = src;
5724     dest_level = dest;
5725
5726     point = *DestPoint;
5727     src_rect = *SrcRect;
5728
5729     for (;src_level && dest_level;)
5730     {
5731         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
5732             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
5733         {
5734             UINT src_w = src_rect.right - src_rect.left;
5735             UINT src_h = src_rect.bottom - src_rect.top;
5736             RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
5737
5738             if (FAILED(hr = wined3d_surface_blt(dest_level->wined3d_surface, &dst_rect,
5739                     src_level->wined3d_surface, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
5740                 ERR("Blit failed, hr %#x.\n", hr);
5741
5742             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5743             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5744             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5745
5746             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5747
5748             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5749         }
5750
5751         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5752         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
5753         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5754
5755         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5756
5757         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
5758
5759         point.x /= 2;
5760         point.y /= 2;
5761
5762         src_rect.top /= 2;
5763         src_rect.left /= 2;
5764         src_rect.right = (src_rect.right + 1) / 2;
5765         src_rect.bottom = (src_rect.bottom + 1) / 2;
5766     }
5767
5768     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
5769     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
5770 }
5771
5772 /*****************************************************************************
5773  * IDirect3DDevice7::Load
5774  *
5775  * Loads a rectangular area from the source into the destination texture.
5776  * It can also copy the source to the faces of a cubic environment map
5777  *
5778  * Version 7
5779  *
5780  * Params:
5781  *  DestTex: Destination texture
5782  *  DestPoint: Point in the destination where the source image should be
5783  *             written to
5784  *  SrcTex: Source texture
5785  *  SrcRect: Source rectangle
5786  *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
5787  *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
5788  *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
5789  *
5790  * Returns:
5791  *  D3D_OK on success
5792  *  DDERR_INVALIDPARAMS if DestTex or SrcTex are NULL, broken coordinates or anything unexpected.
5793  *
5794  *
5795  *****************************************************************************/
5796 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
5797         IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
5798 {
5799     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5800     struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
5801     struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
5802     POINT destpoint;
5803     RECT srcrect;
5804
5805     TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
5806             iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
5807
5808     if( (!src) || (!dest) )
5809         return DDERR_INVALIDPARAMS;
5810
5811     wined3d_mutex_lock();
5812
5813     if (!src_rect)
5814     {
5815         srcrect.left = srcrect.top = 0;
5816         srcrect.right = src->surface_desc.dwWidth;
5817         srcrect.bottom = src->surface_desc.dwHeight;
5818     }
5819     else
5820         srcrect = *src_rect;
5821
5822     if (!dst_pos)
5823         destpoint.x = destpoint.y = 0;
5824     else
5825         destpoint = *dst_pos;
5826
5827     /* Check bad dimensions. dst_pos is validated against src, not dest, because
5828      * destination can be a subset of mip levels, in which case actual coordinates used
5829      * for it may be divided. If any dimension of dest is larger than source, it can't be
5830      * mip level subset, so an error can be returned early.
5831      */
5832     if (srcrect.left >= srcrect.right || srcrect.top >= srcrect.bottom ||
5833         srcrect.right > src->surface_desc.dwWidth ||
5834         srcrect.bottom > src->surface_desc.dwHeight ||
5835         destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
5836         destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
5837         dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
5838         dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
5839     {
5840         wined3d_mutex_unlock();
5841         return DDERR_INVALIDPARAMS;
5842     }
5843
5844     /* Must be top level surfaces. */
5845     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
5846         dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
5847     {
5848         wined3d_mutex_unlock();
5849         return DDERR_INVALIDPARAMS;
5850     }
5851
5852     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
5853     {
5854         struct ddraw_surface *src_face, *dest_face;
5855         DWORD src_face_flag, dest_face_flag;
5856         IDirectDrawSurface7 *temp;
5857         DDSURFACEDESC2 ddsd;
5858         int i;
5859
5860         if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
5861         {
5862             wined3d_mutex_unlock();
5863             return DDERR_INVALIDPARAMS;
5864         }
5865
5866         /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
5867          * time it's actual surface loading. */
5868         for (i = 0; i < 2; i++)
5869         {
5870             dest_face = dest;
5871             src_face = src;
5872
5873             for (;dest_face && src_face;)
5874             {
5875                 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
5876                 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
5877
5878                 if (src_face_flag == dest_face_flag)
5879                 {
5880                     if (i == 0)
5881                     {
5882                         /* Destination mip levels must be subset of source mip levels. */
5883                         if (!is_mip_level_subset(dest_face, src_face))
5884                         {
5885                             wined3d_mutex_unlock();
5886                             return DDERR_INVALIDPARAMS;
5887                         }
5888                     }
5889                     else if (flags & dest_face_flag)
5890                     {
5891                         copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
5892                     }
5893
5894                     if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
5895                     {
5896                         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5897                         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
5898                         IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5899
5900                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
5901
5902                         src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
5903                     }
5904                     else
5905                     {
5906                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
5907
5908                         src_face = NULL;
5909                     }
5910                 }
5911
5912                 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
5913                 {
5914                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
5915                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
5916                     IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
5917
5918                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
5919
5920                     dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
5921                 }
5922                 else
5923                 {
5924                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
5925
5926                     dest_face = NULL;
5927                 }
5928             }
5929
5930             if (i == 0)
5931             {
5932                 /* Native returns error if src faces are not subset of dest faces. */
5933                 if (src_face)
5934                 {
5935                     wined3d_mutex_unlock();
5936                     return DDERR_INVALIDPARAMS;
5937                 }
5938             }
5939         }
5940
5941         wined3d_mutex_unlock();
5942         return D3D_OK;
5943     }
5944     else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
5945     {
5946         wined3d_mutex_unlock();
5947         return DDERR_INVALIDPARAMS;
5948     }
5949
5950     /* Handle non cube map textures. */
5951
5952     /* Destination mip levels must be subset of source mip levels. */
5953     if (!is_mip_level_subset(dest, src))
5954     {
5955         wined3d_mutex_unlock();
5956         return DDERR_INVALIDPARAMS;
5957     }
5958
5959     copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
5960
5961     wined3d_mutex_unlock();
5962
5963     return D3D_OK;
5964 }
5965
5966 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
5967         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
5968 {
5969     return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
5970 }
5971
5972 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
5973         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
5974 {
5975     HRESULT hr;
5976     WORD old_fpucw;
5977
5978     old_fpucw = d3d_fpu_setup();
5979     hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
5980     set_fpu_control_word(old_fpucw);
5981
5982     return hr;
5983 }
5984
5985 /*****************************************************************************
5986  * IDirect3DDevice7::LightEnable
5987  *
5988  * Enables or disables a light
5989  *
5990  * Version 7, IDirect3DLight uses this method too.
5991  *
5992  * Params:
5993  *  LightIndex: The index of the light to enable / disable
5994  *  Enable: Enable or disable the light
5995  *
5996  * Returns:
5997  *  D3D_OK on success
5998  *  For more details, see IWineD3DDevice::SetLightEnable
5999  *
6000  *****************************************************************************/
6001 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6002 {
6003     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6004     HRESULT hr;
6005
6006     TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
6007
6008     wined3d_mutex_lock();
6009     hr = wined3d_device_set_light_enable(device->wined3d_device, light_idx, enabled);
6010     wined3d_mutex_unlock();
6011
6012     return hr_ddraw_from_wined3d(hr);
6013 }
6014
6015 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6016 {
6017     return d3d_device7_LightEnable(iface, light_idx, enabled);
6018 }
6019
6020 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6021 {
6022     HRESULT hr;
6023     WORD old_fpucw;
6024
6025     old_fpucw = d3d_fpu_setup();
6026     hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6027     set_fpu_control_word(old_fpucw);
6028
6029     return hr;
6030 }
6031
6032 /*****************************************************************************
6033  * IDirect3DDevice7::GetLightEnable
6034  *
6035  * Retrieves if the light with the given index is enabled or not
6036  *
6037  * Version 7
6038  *
6039  * Params:
6040  *  LightIndex: Index of desired light
6041  *  Enable: Pointer to a BOOL which contains the result
6042  *
6043  * Returns:
6044  *  D3D_OK on success
6045  *  DDERR_INVALIDPARAMS if Enable is NULL
6046  *  See IWineD3DDevice::GetLightEnable for more details
6047  *
6048  *****************************************************************************/
6049 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6050 {
6051     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6052     HRESULT hr;
6053
6054     TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6055
6056     if (!enabled)
6057         return DDERR_INVALIDPARAMS;
6058
6059     wined3d_mutex_lock();
6060     hr = wined3d_device_get_light_enable(device->wined3d_device, light_idx, enabled);
6061     wined3d_mutex_unlock();
6062
6063     return hr_ddraw_from_wined3d(hr);
6064 }
6065
6066 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6067 {
6068     return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6069 }
6070
6071 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6072 {
6073     HRESULT hr;
6074     WORD old_fpucw;
6075
6076     old_fpucw = d3d_fpu_setup();
6077     hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6078     set_fpu_control_word(old_fpucw);
6079
6080     return hr;
6081 }
6082
6083 /*****************************************************************************
6084  * IDirect3DDevice7::SetClipPlane
6085  *
6086  * Sets custom clipping plane
6087  *
6088  * Version 7
6089  *
6090  * Params:
6091  *  Index: The index of the clipping plane
6092  *  PlaneEquation: An equation defining the clipping plane
6093  *
6094  * Returns:
6095  *  D3D_OK on success
6096  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6097  *  See IWineD3DDevice::SetClipPlane for more details
6098  *
6099  *****************************************************************************/
6100 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6101 {
6102     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6103     HRESULT hr;
6104
6105     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6106
6107     if (!plane)
6108         return DDERR_INVALIDPARAMS;
6109
6110     wined3d_mutex_lock();
6111     hr = wined3d_device_set_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6112     wined3d_mutex_unlock();
6113
6114     return hr;
6115 }
6116
6117 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6118 {
6119     return d3d_device7_SetClipPlane(iface, idx, plane);
6120 }
6121
6122 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6123 {
6124     HRESULT hr;
6125     WORD old_fpucw;
6126
6127     old_fpucw = d3d_fpu_setup();
6128     hr = d3d_device7_SetClipPlane(iface, idx, plane);
6129     set_fpu_control_word(old_fpucw);
6130
6131     return hr;
6132 }
6133
6134 /*****************************************************************************
6135  * IDirect3DDevice7::GetClipPlane
6136  *
6137  * Returns the clipping plane with a specific index
6138  *
6139  * Params:
6140  *  Index: The index of the desired plane
6141  *  PlaneEquation: Address to store the plane equation to
6142  *
6143  * Returns:
6144  *  D3D_OK on success
6145  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6146  *  See IWineD3DDevice::GetClipPlane for more details
6147  *
6148  *****************************************************************************/
6149 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6150 {
6151     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6152     HRESULT hr;
6153
6154     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6155
6156     if (!plane)
6157         return DDERR_INVALIDPARAMS;
6158
6159     wined3d_mutex_lock();
6160     hr = wined3d_device_get_clip_plane(device->wined3d_device, idx, (struct wined3d_vec4 *)plane);
6161     wined3d_mutex_unlock();
6162
6163     return hr;
6164 }
6165
6166 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6167 {
6168     return d3d_device7_GetClipPlane(iface, idx, plane);
6169 }
6170
6171 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6172 {
6173     HRESULT hr;
6174     WORD old_fpucw;
6175
6176     old_fpucw = d3d_fpu_setup();
6177     hr = d3d_device7_GetClipPlane(iface, idx, plane);
6178     set_fpu_control_word(old_fpucw);
6179
6180     return hr;
6181 }
6182
6183 /*****************************************************************************
6184  * IDirect3DDevice7::GetInfo
6185  *
6186  * Retrieves some information about the device. The DirectX sdk says that
6187  * this version returns S_FALSE for all retail builds of DirectX, that's what
6188  * this implementation does.
6189  *
6190  * Params:
6191  *  DevInfoID: Information type requested
6192  *  DevInfoStruct: Pointer to a structure to store the info to
6193  *  Size: Size of the structure
6194  *
6195  * Returns:
6196  *  S_FALSE, because it's a non-debug driver
6197  *
6198  *****************************************************************************/
6199 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6200 {
6201     TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6202             iface, info_id, info, info_size);
6203
6204     if (TRACE_ON(ddraw))
6205     {
6206         TRACE(" info requested : ");
6207         switch (info_id)
6208         {
6209             case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6210             case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6211             case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6212             default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6213         }
6214     }
6215
6216     return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6217 }
6218
6219 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6220  * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6221  * are not duplicated.
6222
6223  * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6224  * has already been setup for optimal d3d operation.
6225
6226  * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6227  * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6228  * by Sacrifice (game). */
6229 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6230 {
6231     /*** IUnknown Methods ***/
6232     d3d_device7_QueryInterface,
6233     d3d_device7_AddRef,
6234     d3d_device7_Release,
6235     /*** IDirect3DDevice7 ***/
6236     d3d_device7_GetCaps_FPUSetup,
6237     d3d_device7_EnumTextureFormats_FPUSetup,
6238     d3d_device7_BeginScene_FPUSetup,
6239     d3d_device7_EndScene_FPUSetup,
6240     d3d_device7_GetDirect3D,
6241     d3d_device7_SetRenderTarget_FPUSetup,
6242     d3d_device7_GetRenderTarget,
6243     d3d_device7_Clear_FPUSetup,
6244     d3d_device7_SetTransform_FPUSetup,
6245     d3d_device7_GetTransform_FPUSetup,
6246     d3d_device7_SetViewport_FPUSetup,
6247     d3d_device7_MultiplyTransform_FPUSetup,
6248     d3d_device7_GetViewport_FPUSetup,
6249     d3d_device7_SetMaterial_FPUSetup,
6250     d3d_device7_GetMaterial_FPUSetup,
6251     d3d_device7_SetLight_FPUSetup,
6252     d3d_device7_GetLight_FPUSetup,
6253     d3d_device7_SetRenderState_FPUSetup,
6254     d3d_device7_GetRenderState_FPUSetup,
6255     d3d_device7_BeginStateBlock_FPUSetup,
6256     d3d_device7_EndStateBlock_FPUSetup,
6257     d3d_device7_PreLoad_FPUSetup,
6258     d3d_device7_DrawPrimitive_FPUSetup,
6259     d3d_device7_DrawIndexedPrimitive_FPUSetup,
6260     d3d_device7_SetClipStatus,
6261     d3d_device7_GetClipStatus,
6262     d3d_device7_DrawPrimitiveStrided_FPUSetup,
6263     d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6264     d3d_device7_DrawPrimitiveVB_FPUSetup,
6265     d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6266     d3d_device7_ComputeSphereVisibility,
6267     d3d_device7_GetTexture_FPUSetup,
6268     d3d_device7_SetTexture_FPUSetup,
6269     d3d_device7_GetTextureStageState_FPUSetup,
6270     d3d_device7_SetTextureStageState_FPUSetup,
6271     d3d_device7_ValidateDevice_FPUSetup,
6272     d3d_device7_ApplyStateBlock_FPUSetup,
6273     d3d_device7_CaptureStateBlock_FPUSetup,
6274     d3d_device7_DeleteStateBlock_FPUSetup,
6275     d3d_device7_CreateStateBlock_FPUSetup,
6276     d3d_device7_Load_FPUSetup,
6277     d3d_device7_LightEnable_FPUSetup,
6278     d3d_device7_GetLightEnable_FPUSetup,
6279     d3d_device7_SetClipPlane_FPUSetup,
6280     d3d_device7_GetClipPlane_FPUSetup,
6281     d3d_device7_GetInfo
6282 };
6283
6284 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6285 {
6286     /*** IUnknown Methods ***/
6287     d3d_device7_QueryInterface,
6288     d3d_device7_AddRef,
6289     d3d_device7_Release,
6290     /*** IDirect3DDevice7 ***/
6291     d3d_device7_GetCaps_FPUPreserve,
6292     d3d_device7_EnumTextureFormats_FPUPreserve,
6293     d3d_device7_BeginScene_FPUPreserve,
6294     d3d_device7_EndScene_FPUPreserve,
6295     d3d_device7_GetDirect3D,
6296     d3d_device7_SetRenderTarget_FPUPreserve,
6297     d3d_device7_GetRenderTarget,
6298     d3d_device7_Clear_FPUPreserve,
6299     d3d_device7_SetTransform_FPUPreserve,
6300     d3d_device7_GetTransform_FPUPreserve,
6301     d3d_device7_SetViewport_FPUPreserve,
6302     d3d_device7_MultiplyTransform_FPUPreserve,
6303     d3d_device7_GetViewport_FPUPreserve,
6304     d3d_device7_SetMaterial_FPUPreserve,
6305     d3d_device7_GetMaterial_FPUPreserve,
6306     d3d_device7_SetLight_FPUPreserve,
6307     d3d_device7_GetLight_FPUPreserve,
6308     d3d_device7_SetRenderState_FPUPreserve,
6309     d3d_device7_GetRenderState_FPUPreserve,
6310     d3d_device7_BeginStateBlock_FPUPreserve,
6311     d3d_device7_EndStateBlock_FPUPreserve,
6312     d3d_device7_PreLoad_FPUPreserve,
6313     d3d_device7_DrawPrimitive_FPUPreserve,
6314     d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6315     d3d_device7_SetClipStatus,
6316     d3d_device7_GetClipStatus,
6317     d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6318     d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6319     d3d_device7_DrawPrimitiveVB_FPUPreserve,
6320     d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6321     d3d_device7_ComputeSphereVisibility,
6322     d3d_device7_GetTexture_FPUPreserve,
6323     d3d_device7_SetTexture_FPUPreserve,
6324     d3d_device7_GetTextureStageState_FPUPreserve,
6325     d3d_device7_SetTextureStageState_FPUPreserve,
6326     d3d_device7_ValidateDevice_FPUPreserve,
6327     d3d_device7_ApplyStateBlock_FPUPreserve,
6328     d3d_device7_CaptureStateBlock_FPUPreserve,
6329     d3d_device7_DeleteStateBlock_FPUPreserve,
6330     d3d_device7_CreateStateBlock_FPUPreserve,
6331     d3d_device7_Load_FPUPreserve,
6332     d3d_device7_LightEnable_FPUPreserve,
6333     d3d_device7_GetLightEnable_FPUPreserve,
6334     d3d_device7_SetClipPlane_FPUPreserve,
6335     d3d_device7_GetClipPlane_FPUPreserve,
6336     d3d_device7_GetInfo
6337 };
6338
6339 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6340 {
6341     /*** IUnknown Methods ***/
6342     d3d_device3_QueryInterface,
6343     d3d_device3_AddRef,
6344     d3d_device3_Release,
6345     /*** IDirect3DDevice3 ***/
6346     d3d_device3_GetCaps,
6347     d3d_device3_GetStats,
6348     d3d_device3_AddViewport,
6349     d3d_device3_DeleteViewport,
6350     d3d_device3_NextViewport,
6351     d3d_device3_EnumTextureFormats,
6352     d3d_device3_BeginScene,
6353     d3d_device3_EndScene,
6354     d3d_device3_GetDirect3D,
6355     d3d_device3_SetCurrentViewport,
6356     d3d_device3_GetCurrentViewport,
6357     d3d_device3_SetRenderTarget,
6358     d3d_device3_GetRenderTarget,
6359     d3d_device3_Begin,
6360     d3d_device3_BeginIndexed,
6361     d3d_device3_Vertex,
6362     d3d_device3_Index,
6363     d3d_device3_End,
6364     d3d_device3_GetRenderState,
6365     d3d_device3_SetRenderState,
6366     d3d_device3_GetLightState,
6367     d3d_device3_SetLightState,
6368     d3d_device3_SetTransform,
6369     d3d_device3_GetTransform,
6370     d3d_device3_MultiplyTransform,
6371     d3d_device3_DrawPrimitive,
6372     d3d_device3_DrawIndexedPrimitive,
6373     d3d_device3_SetClipStatus,
6374     d3d_device3_GetClipStatus,
6375     d3d_device3_DrawPrimitiveStrided,
6376     d3d_device3_DrawIndexedPrimitiveStrided,
6377     d3d_device3_DrawPrimitiveVB,
6378     d3d_device3_DrawIndexedPrimitiveVB,
6379     d3d_device3_ComputeSphereVisibility,
6380     d3d_device3_GetTexture,
6381     d3d_device3_SetTexture,
6382     d3d_device3_GetTextureStageState,
6383     d3d_device3_SetTextureStageState,
6384     d3d_device3_ValidateDevice
6385 };
6386
6387 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6388 {
6389     /*** IUnknown Methods ***/
6390     d3d_device2_QueryInterface,
6391     d3d_device2_AddRef,
6392     d3d_device2_Release,
6393     /*** IDirect3DDevice2 ***/
6394     d3d_device2_GetCaps,
6395     d3d_device2_SwapTextureHandles,
6396     d3d_device2_GetStats,
6397     d3d_device2_AddViewport,
6398     d3d_device2_DeleteViewport,
6399     d3d_device2_NextViewport,
6400     d3d_device2_EnumTextureFormats,
6401     d3d_device2_BeginScene,
6402     d3d_device2_EndScene,
6403     d3d_device2_GetDirect3D,
6404     d3d_device2_SetCurrentViewport,
6405     d3d_device2_GetCurrentViewport,
6406     d3d_device2_SetRenderTarget,
6407     d3d_device2_GetRenderTarget,
6408     d3d_device2_Begin,
6409     d3d_device2_BeginIndexed,
6410     d3d_device2_Vertex,
6411     d3d_device2_Index,
6412     d3d_device2_End,
6413     d3d_device2_GetRenderState,
6414     d3d_device2_SetRenderState,
6415     d3d_device2_GetLightState,
6416     d3d_device2_SetLightState,
6417     d3d_device2_SetTransform,
6418     d3d_device2_GetTransform,
6419     d3d_device2_MultiplyTransform,
6420     d3d_device2_DrawPrimitive,
6421     d3d_device2_DrawIndexedPrimitive,
6422     d3d_device2_SetClipStatus,
6423     d3d_device2_GetClipStatus
6424 };
6425
6426 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6427 {
6428     /*** IUnknown Methods ***/
6429     d3d_device1_QueryInterface,
6430     d3d_device1_AddRef,
6431     d3d_device1_Release,
6432     /*** IDirect3DDevice1 ***/
6433     d3d_device1_Initialize,
6434     d3d_device1_GetCaps,
6435     d3d_device1_SwapTextureHandles,
6436     d3d_device1_CreateExecuteBuffer,
6437     d3d_device1_GetStats,
6438     d3d_device1_Execute,
6439     d3d_device1_AddViewport,
6440     d3d_device1_DeleteViewport,
6441     d3d_device1_NextViewport,
6442     d3d_device1_Pick,
6443     d3d_device1_GetPickRecords,
6444     d3d_device1_EnumTextureFormats,
6445     d3d_device1_CreateMatrix,
6446     d3d_device1_SetMatrix,
6447     d3d_device1_GetMatrix,
6448     d3d_device1_DeleteMatrix,
6449     d3d_device1_BeginScene,
6450     d3d_device1_EndScene,
6451     d3d_device1_GetDirect3D
6452 };
6453
6454 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6455 {
6456     d3d_device_inner_QueryInterface,
6457     d3d_device_inner_AddRef,
6458     d3d_device_inner_Release,
6459 };
6460
6461 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6462 {
6463     if (!iface) return NULL;
6464     assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6465     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6466 }
6467
6468 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6469 {
6470     if (!iface) return NULL;
6471     assert(iface->lpVtbl == &d3d_device3_vtbl);
6472     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6473 }
6474
6475 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6476 {
6477     if (!iface) return NULL;
6478     assert(iface->lpVtbl == &d3d_device2_vtbl);
6479     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6480 }
6481
6482 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6483 {
6484     if (!iface) return NULL;
6485     assert(iface->lpVtbl == &d3d_device1_vtbl);
6486     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6487 }
6488
6489 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6490 {
6491     IDirectDrawSurface7 *depthStencil = NULL;
6492     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
6493     struct ddraw_surface *dsi;
6494
6495     IDirectDrawSurface7_GetAttachedSurface(&device->target->IDirectDrawSurface7_iface, &depthcaps, &depthStencil);
6496     if (!depthStencil)
6497     {
6498         TRACE("Setting wined3d depth stencil to NULL\n");
6499         wined3d_device_set_depth_stencil(device->wined3d_device, NULL);
6500         return WINED3D_ZB_FALSE;
6501     }
6502
6503     dsi = impl_from_IDirectDrawSurface7(depthStencil);
6504     TRACE("Setting wined3d depth stencil to %p (wined3d %p)\n", dsi, dsi->wined3d_surface);
6505     wined3d_device_set_depth_stencil(device->wined3d_device, dsi->wined3d_surface);
6506
6507     IDirectDrawSurface7_Release(depthStencil);
6508     return WINED3D_ZB_TRUE;
6509 }
6510
6511 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
6512         struct ddraw_surface *target, UINT version, IUnknown *outer_unknown)
6513 {
6514     static const D3DMATRIX ident =
6515     {
6516         1.0f, 0.0f, 0.0f, 0.0f,
6517         0.0f, 1.0f, 0.0f, 0.0f,
6518         0.0f, 0.0f, 1.0f, 0.0f,
6519         0.0f, 0.0f, 0.0f, 1.0f,
6520     };
6521     HRESULT hr;
6522
6523     if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6524         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6525     else
6526         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6527
6528     device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6529     device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6530     device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6531     device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
6532     device->ref = 1;
6533     device->version = version;
6534
6535     if (outer_unknown)
6536         device->outer_unknown = outer_unknown;
6537     else
6538         device->outer_unknown = &device->IUnknown_inner;
6539
6540     device->ddraw = ddraw;
6541     device->target = target;
6542     list_init(&device->viewport_list);
6543
6544     if (!ddraw_handle_table_init(&device->handle_table, 64))
6545     {
6546         ERR("Failed to initialize handle table.\n");
6547         return DDERR_OUTOFMEMORY;
6548     }
6549
6550     device->legacyTextureBlending = FALSE;
6551     device->legacy_projection = ident;
6552     device->legacy_clipspace = ident;
6553
6554     /* Create an index buffer, it's needed for indexed drawing */
6555     hr = wined3d_buffer_create_ib(ddraw->wined3d_device, 0x40000 /* Length. Don't know how long it should be */,
6556             WINED3DUSAGE_DYNAMIC /* Usage */, WINED3D_POOL_DEFAULT, NULL,
6557             &ddraw_null_wined3d_parent_ops, &device->indexbuffer);
6558     if (FAILED(hr))
6559     {
6560         ERR("Failed to create an index buffer, hr %#x.\n", hr);
6561         ddraw_handle_table_destroy(&device->handle_table);
6562         return hr;
6563     }
6564
6565     /* This is for convenience. */
6566     device->wined3d_device = ddraw->wined3d_device;
6567     wined3d_device_incref(ddraw->wined3d_device);
6568
6569     /* Render to the back buffer */
6570     hr = wined3d_device_set_render_target(ddraw->wined3d_device, 0, target->wined3d_surface, TRUE);
6571     if (FAILED(hr))
6572     {
6573         ERR("Failed to set render target, hr %#x.\n", hr);
6574         wined3d_buffer_decref(device->indexbuffer);
6575         ddraw_handle_table_destroy(&device->handle_table);
6576         return hr;
6577     }
6578
6579     /* FIXME: This is broken. The target AddRef() makes some sense, because
6580      * we store a pointer during initialization, but then that's also where
6581      * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */
6582     /* AddRef the render target. Also AddRef the render target from ddraw,
6583      * because if it is released before the app releases the D3D device, the
6584      * D3D capabilities of wined3d will be uninitialized, which has bad effects.
6585      *
6586      * In most cases, those surfaces are the same anyway, but this will simply
6587      * add another ref which is released when the device is destroyed. */
6588     if (version != 1)
6589         IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
6590
6591     ddraw->d3ddevice = device;
6592
6593     wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_ZENABLE,
6594             d3d_device_update_depth_stencil(device));
6595     if (version == 1) /* Color keying is initially enabled for version 1 devices. */
6596         wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_COLORKEYENABLE, TRUE);
6597
6598     return D3D_OK;
6599 }
6600
6601 HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
6602         UINT version, struct d3d_device **device, IUnknown *outer_unknown)
6603 {
6604     struct d3d_device *object;
6605     HRESULT hr;
6606
6607     TRACE("ddraw %p, target %p, version %u, device %p, outer_unknown %p.\n",
6608             ddraw, target, version, device, outer_unknown);
6609
6610     if (DefaultSurfaceType != WINED3D_SURFACE_TYPE_OPENGL)
6611     {
6612         ERR_(winediag)("The application wants to create a Direct3D device, "
6613                 "but the current DirectDrawRenderer does not support this.\n");
6614
6615         return DDERR_NO3D;
6616     }
6617
6618     if (ddraw->d3ddevice)
6619     {
6620         FIXME("Only one Direct3D device per DirectDraw object supported.\n");
6621         return DDERR_INVALIDPARAMS;
6622     }
6623
6624     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
6625     if (!object)
6626     {
6627         ERR("Failed to allocate device memory.\n");
6628         return DDERR_OUTOFMEMORY;
6629     }
6630
6631     hr = d3d_device_init(object, ddraw, target, version, outer_unknown);
6632     if (FAILED(hr))
6633     {
6634         WARN("Failed to initialize device, hr %#x.\n", hr);
6635         HeapFree(GetProcessHeap(), 0, object);
6636         return hr;
6637     }
6638
6639     TRACE("Created device %p.\n", object);
6640     *device = object;
6641
6642     return D3D_OK;
6643 }