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