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