xref: /reactos/dll/directx/wine/ddraw/device.c (revision cc439606)
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 static HRESULT d3d_device7_SetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5300 {
5301     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5302     struct wined3d_sub_resource_desc rt_desc;
5303     struct wined3d_rendertarget_view *rtv;
5304     struct ddraw_surface *surface;
5305     struct wined3d_viewport vp;
5306 
5307     TRACE("iface %p, viewport %p.\n", iface, viewport);
5308 
5309     if (!viewport)
5310         return DDERR_INVALIDPARAMS;
5311 
5312     wined3d_mutex_lock();
5313     if (!(rtv = wined3d_device_get_rendertarget_view(device->wined3d_device, 0)))
5314     {
5315         wined3d_mutex_unlock();
5316         return DDERR_INVALIDCAPS;
5317     }
5318     surface = wined3d_rendertarget_view_get_sub_resource_parent(rtv);
5319     wined3d_texture_get_sub_resource_desc(surface->wined3d_texture, surface->sub_resource_idx, &rt_desc);
5320 
5321     if (viewport->dwX > rt_desc.width || viewport->dwWidth > rt_desc.width - viewport->dwX
5322             || viewport->dwY > rt_desc.height || viewport->dwHeight > rt_desc.height - viewport->dwY)
5323     {
5324         WARN("Invalid viewport, returning E_INVALIDARG.\n");
5325         wined3d_mutex_unlock();
5326         return E_INVALIDARG;
5327     }
5328 
5329     vp.x = viewport->dwX;
5330     vp.y = viewport->dwY;
5331     vp.width = viewport->dwWidth;
5332     vp.height = viewport->dwHeight;
5333     vp.min_z = viewport->dvMinZ;
5334     vp.max_z = viewport->dvMaxZ;
5335 
5336     wined3d_device_set_viewports(device->wined3d_device, 1, &vp);
5337     wined3d_mutex_unlock();
5338 
5339     return D3D_OK;
5340 }
5341 
5342 static HRESULT WINAPI d3d_device7_SetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5343 {
5344     return d3d_device7_SetViewport(iface, viewport);
5345 }
5346 
5347 static HRESULT WINAPI d3d_device7_SetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5348 {
5349     HRESULT hr;
5350     WORD old_fpucw;
5351 
5352     old_fpucw = d3d_fpu_setup();
5353     hr = d3d_device7_SetViewport(iface, viewport);
5354     set_fpu_control_word(old_fpucw);
5355 
5356     return hr;
5357 }
5358 
5359 static HRESULT d3d_device7_GetViewport(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5360 {
5361     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5362     struct wined3d_viewport wined3d_viewport;
5363 
5364     TRACE("iface %p, viewport %p.\n", iface, viewport);
5365 
5366     if (!viewport)
5367         return DDERR_INVALIDPARAMS;
5368 
5369     wined3d_mutex_lock();
5370     wined3d_device_get_viewports(device->wined3d_device, NULL, &wined3d_viewport);
5371     wined3d_mutex_unlock();
5372 
5373     viewport->dwX = wined3d_viewport.x;
5374     viewport->dwY = wined3d_viewport.y;
5375     viewport->dwWidth = wined3d_viewport.width;
5376     viewport->dwHeight = wined3d_viewport.height;
5377     viewport->dvMinZ = wined3d_viewport.min_z;
5378     viewport->dvMaxZ = wined3d_viewport.max_z;
5379 
5380     return D3D_OK;
5381 }
5382 
5383 static HRESULT WINAPI d3d_device7_GetViewport_FPUSetup(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5384 {
5385     return d3d_device7_GetViewport(iface, viewport);
5386 }
5387 
5388 static HRESULT WINAPI d3d_device7_GetViewport_FPUPreserve(IDirect3DDevice7 *iface, D3DVIEWPORT7 *viewport)
5389 {
5390     HRESULT hr;
5391     WORD old_fpucw;
5392 
5393     old_fpucw = d3d_fpu_setup();
5394     hr = d3d_device7_GetViewport(iface, viewport);
5395     set_fpu_control_word(old_fpucw);
5396 
5397     return hr;
5398 }
5399 
5400 /*****************************************************************************
5401  * IDirect3DDevice7::SetMaterial
5402  *
5403  * Sets the Material
5404  *
5405  * Version 7
5406  *
5407  * Params:
5408  *  Mat: The material to set
5409  *
5410  * Returns:
5411  *  D3D_OK on success
5412  *  DDERR_INVALIDPARAMS if Mat is NULL.
5413  *
5414  *****************************************************************************/
5415 static HRESULT d3d_device7_SetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5416 {
5417     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5418 
5419     TRACE("iface %p, material %p.\n", iface, material);
5420 
5421     if (!material)
5422         return DDERR_INVALIDPARAMS;
5423 
5424     wined3d_mutex_lock();
5425     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5426     wined3d_device_set_material(device->wined3d_device, (struct wined3d_material *)material);
5427     wined3d_mutex_unlock();
5428 
5429     return D3D_OK;
5430 }
5431 
5432 static HRESULT WINAPI d3d_device7_SetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5433 {
5434     return d3d_device7_SetMaterial(iface, material);
5435 }
5436 
5437 static HRESULT WINAPI d3d_device7_SetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5438 {
5439     HRESULT hr;
5440     WORD old_fpucw;
5441 
5442     old_fpucw = d3d_fpu_setup();
5443     hr = d3d_device7_SetMaterial(iface, material);
5444     set_fpu_control_word(old_fpucw);
5445 
5446     return hr;
5447 }
5448 
5449 /*****************************************************************************
5450  * IDirect3DDevice7::GetMaterial
5451  *
5452  * Returns the current material
5453  *
5454  * Version 7
5455  *
5456  * Params:
5457  *  Mat: D3DMATERIAL7 structure to write the material parameters to
5458  *
5459  * Returns:
5460  *  D3D_OK on success
5461  *  DDERR_INVALIDPARAMS if Mat is NULL
5462  *
5463  *****************************************************************************/
5464 static HRESULT d3d_device7_GetMaterial(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5465 {
5466     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5467 
5468     TRACE("iface %p, material %p.\n", iface, material);
5469 
5470     wined3d_mutex_lock();
5471     /* Note: D3DMATERIAL7 is compatible with struct wined3d_material. */
5472     wined3d_device_get_material(device->wined3d_device, (struct wined3d_material *)material);
5473     wined3d_mutex_unlock();
5474 
5475     return D3D_OK;
5476 }
5477 
5478 static HRESULT WINAPI d3d_device7_GetMaterial_FPUSetup(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5479 {
5480     return d3d_device7_GetMaterial(iface, material);
5481 }
5482 
5483 static HRESULT WINAPI d3d_device7_GetMaterial_FPUPreserve(IDirect3DDevice7 *iface, D3DMATERIAL7 *material)
5484 {
5485     HRESULT hr;
5486     WORD old_fpucw;
5487 
5488     old_fpucw = d3d_fpu_setup();
5489     hr = d3d_device7_GetMaterial(iface, material);
5490     set_fpu_control_word(old_fpucw);
5491 
5492     return hr;
5493 }
5494 
5495 /*****************************************************************************
5496  * IDirect3DDevice7::SetLight
5497  *
5498  * Assigns a light to a light index, but doesn't activate it yet.
5499  *
5500  * Version 7, IDirect3DLight uses this method for older versions
5501  *
5502  * Params:
5503  *  LightIndex: The index of the new light
5504  *  Light: A D3DLIGHT7 structure describing the light
5505  *
5506  * Returns:
5507  *  D3D_OK on success
5508  *
5509  *****************************************************************************/
5510 static HRESULT d3d_device7_SetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5511 {
5512     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5513     HRESULT hr;
5514 
5515     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5516 
5517     wined3d_mutex_lock();
5518     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5519     hr = wined3d_device_set_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5520     wined3d_mutex_unlock();
5521 
5522     return hr_ddraw_from_wined3d(hr);
5523 }
5524 
5525 static HRESULT WINAPI d3d_device7_SetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5526 {
5527     return d3d_device7_SetLight(iface, light_idx, light);
5528 }
5529 
5530 static HRESULT WINAPI d3d_device7_SetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5531 {
5532     HRESULT hr;
5533     WORD old_fpucw;
5534 
5535     old_fpucw = d3d_fpu_setup();
5536     hr = d3d_device7_SetLight(iface, light_idx, light);
5537     set_fpu_control_word(old_fpucw);
5538 
5539     return hr;
5540 }
5541 
5542 /*****************************************************************************
5543  * IDirect3DDevice7::GetLight
5544  *
5545  * Returns the light assigned to a light index
5546  *
5547  * Params:
5548  *  Light: Structure to write the light information to
5549  *
5550  * Returns:
5551  *  D3D_OK on success
5552  *  DDERR_INVALIDPARAMS if Light is NULL
5553  *
5554  *****************************************************************************/
5555 static HRESULT d3d_device7_GetLight(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5556 {
5557     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5558     HRESULT rc;
5559 
5560     TRACE("iface %p, light_idx %u, light %p.\n", iface, light_idx, light);
5561 
5562     wined3d_mutex_lock();
5563     /* Note: D3DLIGHT7 is compatible with struct wined3d_light. */
5564     rc =  wined3d_device_get_light(device->wined3d_device, light_idx, (struct wined3d_light *)light);
5565     wined3d_mutex_unlock();
5566 
5567     /* Translate the result. WineD3D returns other values than D3D7 */
5568     return hr_ddraw_from_wined3d(rc);
5569 }
5570 
5571 static HRESULT WINAPI d3d_device7_GetLight_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5572 {
5573     return d3d_device7_GetLight(iface, light_idx, light);
5574 }
5575 
5576 static HRESULT WINAPI d3d_device7_GetLight_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, D3DLIGHT7 *light)
5577 {
5578     HRESULT hr;
5579     WORD old_fpucw;
5580 
5581     old_fpucw = d3d_fpu_setup();
5582     hr = d3d_device7_GetLight(iface, light_idx, light);
5583     set_fpu_control_word(old_fpucw);
5584 
5585     return hr;
5586 }
5587 
5588 /*****************************************************************************
5589  * IDirect3DDevice7::BeginStateBlock
5590  *
5591  * Begins recording to a stateblock
5592  *
5593  * Version 7
5594  *
5595  * Returns:
5596  *  D3D_OK on success
5597  *
5598  *****************************************************************************/
5599 static HRESULT d3d_device7_BeginStateBlock(IDirect3DDevice7 *iface)
5600 {
5601     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5602     HRESULT hr;
5603 
5604     TRACE("iface %p.\n", iface);
5605 
5606     wined3d_mutex_lock();
5607     hr = wined3d_device_begin_stateblock(device->wined3d_device);
5608     wined3d_mutex_unlock();
5609 
5610     return hr_ddraw_from_wined3d(hr);
5611 }
5612 
5613 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUSetup(IDirect3DDevice7 *iface)
5614 {
5615     return d3d_device7_BeginStateBlock(iface);
5616 }
5617 
5618 static HRESULT WINAPI d3d_device7_BeginStateBlock_FPUPreserve(IDirect3DDevice7 *iface)
5619 {
5620     HRESULT hr;
5621     WORD old_fpucw;
5622 
5623     old_fpucw = d3d_fpu_setup();
5624     hr = d3d_device7_BeginStateBlock(iface);
5625     set_fpu_control_word(old_fpucw);
5626 
5627     return hr;
5628 }
5629 
5630 /*****************************************************************************
5631  * IDirect3DDevice7::EndStateBlock
5632  *
5633  * Stops recording to a state block and returns the created stateblock
5634  * handle.
5635  *
5636  * Version 7
5637  *
5638  * Params:
5639  *  BlockHandle: Address to store the stateblock's handle to
5640  *
5641  * Returns:
5642  *  D3D_OK on success
5643  *  DDERR_INVALIDPARAMS if BlockHandle is NULL
5644  *
5645  *****************************************************************************/
5646 static HRESULT d3d_device7_EndStateBlock(IDirect3DDevice7 *iface, DWORD *stateblock)
5647 {
5648     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5649     struct wined3d_stateblock *wined3d_sb;
5650     HRESULT hr;
5651     DWORD h;
5652 
5653     TRACE("iface %p, stateblock %p.\n", iface, stateblock);
5654 
5655     if (!stateblock)
5656         return DDERR_INVALIDPARAMS;
5657 
5658     wined3d_mutex_lock();
5659 
5660     hr = wined3d_device_end_stateblock(device->wined3d_device, &wined3d_sb);
5661     if (FAILED(hr))
5662     {
5663         WARN("Failed to end stateblock, hr %#x.\n", hr);
5664         wined3d_mutex_unlock();
5665         *stateblock = 0;
5666         return hr_ddraw_from_wined3d(hr);
5667     }
5668 
5669     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5670     if (h == DDRAW_INVALID_HANDLE)
5671     {
5672         ERR("Failed to allocate a stateblock handle.\n");
5673         wined3d_stateblock_decref(wined3d_sb);
5674         wined3d_mutex_unlock();
5675         *stateblock = 0;
5676         return DDERR_OUTOFMEMORY;
5677     }
5678 
5679     wined3d_mutex_unlock();
5680     *stateblock = h + 1;
5681 
5682     return hr_ddraw_from_wined3d(hr);
5683 }
5684 
5685 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD *stateblock)
5686 {
5687     return d3d_device7_EndStateBlock(iface, stateblock);
5688 }
5689 
5690 static HRESULT WINAPI d3d_device7_EndStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD *stateblock)
5691 {
5692     HRESULT hr;
5693     WORD old_fpucw;
5694 
5695     old_fpucw = d3d_fpu_setup();
5696     hr = d3d_device7_EndStateBlock(iface, stateblock);
5697     set_fpu_control_word(old_fpucw);
5698 
5699     return hr;
5700 }
5701 
5702 /*****************************************************************************
5703  * IDirect3DDevice7::PreLoad
5704  *
5705  * Allows the app to signal that a texture will be used soon, to allow
5706  * the Direct3DDevice to load it to the video card in the meantime.
5707  *
5708  * Version 7
5709  *
5710  * Params:
5711  *  Texture: The texture to preload
5712  *
5713  * Returns:
5714  *  D3D_OK on success
5715  *  DDERR_INVALIDPARAMS if Texture is NULL
5716  *
5717  *****************************************************************************/
5718 static HRESULT d3d_device7_PreLoad(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5719 {
5720     struct ddraw_surface *surface = unsafe_impl_from_IDirectDrawSurface7(texture);
5721 
5722     TRACE("iface %p, texture %p.\n", iface, texture);
5723 
5724     if (!texture)
5725         return DDERR_INVALIDPARAMS;
5726 
5727     wined3d_mutex_lock();
5728     wined3d_resource_preload(wined3d_texture_get_resource(surface->wined3d_texture));
5729     wined3d_mutex_unlock();
5730 
5731     return D3D_OK;
5732 }
5733 
5734 static HRESULT WINAPI d3d_device7_PreLoad_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5735 {
5736     return d3d_device7_PreLoad(iface, texture);
5737 }
5738 
5739 static HRESULT WINAPI d3d_device7_PreLoad_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *texture)
5740 {
5741     HRESULT hr;
5742     WORD old_fpucw;
5743 
5744     old_fpucw = d3d_fpu_setup();
5745     hr = d3d_device7_PreLoad(iface, texture);
5746     set_fpu_control_word(old_fpucw);
5747 
5748     return hr;
5749 }
5750 
5751 /*****************************************************************************
5752  * IDirect3DDevice7::ApplyStateBlock
5753  *
5754  * Activates the state stored in a state block handle.
5755  *
5756  * Params:
5757  *  BlockHandle: The stateblock handle to activate
5758  *
5759  * Returns:
5760  *  D3D_OK on success
5761  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5762  *
5763  *****************************************************************************/
5764 static HRESULT d3d_device7_ApplyStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5765 {
5766     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5767     struct wined3d_stateblock *wined3d_sb;
5768 
5769     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5770 
5771     wined3d_mutex_lock();
5772     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5773     if (!wined3d_sb)
5774     {
5775         WARN("Invalid stateblock handle.\n");
5776         wined3d_mutex_unlock();
5777         return D3DERR_INVALIDSTATEBLOCK;
5778     }
5779 
5780     wined3d_stateblock_apply(wined3d_sb);
5781     wined3d_mutex_unlock();
5782 
5783     return D3D_OK;
5784 }
5785 
5786 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5787 {
5788     return d3d_device7_ApplyStateBlock(iface, stateblock);
5789 }
5790 
5791 static HRESULT WINAPI d3d_device7_ApplyStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5792 {
5793     HRESULT hr;
5794     WORD old_fpucw;
5795 
5796     old_fpucw = d3d_fpu_setup();
5797     hr = d3d_device7_ApplyStateBlock(iface, stateblock);
5798     set_fpu_control_word(old_fpucw);
5799 
5800     return hr;
5801 }
5802 
5803 /*****************************************************************************
5804  * IDirect3DDevice7::CaptureStateBlock
5805  *
5806  * Updates a stateblock's values to the values currently set for the device
5807  *
5808  * Version 7
5809  *
5810  * Params:
5811  *  BlockHandle: Stateblock to update
5812  *
5813  * Returns:
5814  *  D3D_OK on success
5815  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is NULL
5816  *
5817  *****************************************************************************/
5818 static HRESULT d3d_device7_CaptureStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5819 {
5820     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5821     struct wined3d_stateblock *wined3d_sb;
5822 
5823     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5824 
5825     wined3d_mutex_lock();
5826     wined3d_sb = ddraw_get_object(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5827     if (!wined3d_sb)
5828     {
5829         WARN("Invalid stateblock handle.\n");
5830         wined3d_mutex_unlock();
5831         return D3DERR_INVALIDSTATEBLOCK;
5832     }
5833 
5834     wined3d_stateblock_capture(wined3d_sb);
5835     wined3d_mutex_unlock();
5836 
5837     return D3D_OK;
5838 }
5839 
5840 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5841 {
5842     return d3d_device7_CaptureStateBlock(iface, stateblock);
5843 }
5844 
5845 static HRESULT WINAPI d3d_device7_CaptureStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5846 {
5847     HRESULT hr;
5848     WORD old_fpucw;
5849 
5850     old_fpucw = d3d_fpu_setup();
5851     hr = d3d_device7_CaptureStateBlock(iface, stateblock);
5852     set_fpu_control_word(old_fpucw);
5853 
5854     return hr;
5855 }
5856 
5857 /*****************************************************************************
5858  * IDirect3DDevice7::DeleteStateBlock
5859  *
5860  * Deletes a stateblock handle. This means releasing the WineD3DStateBlock
5861  *
5862  * Version 7
5863  *
5864  * Params:
5865  *  BlockHandle: Stateblock handle to delete
5866  *
5867  * Returns:
5868  *  D3D_OK on success
5869  *  D3DERR_INVALIDSTATEBLOCK if BlockHandle is 0
5870  *
5871  *****************************************************************************/
5872 static HRESULT d3d_device7_DeleteStateBlock(IDirect3DDevice7 *iface, DWORD stateblock)
5873 {
5874     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5875     struct wined3d_stateblock *wined3d_sb;
5876     ULONG ref;
5877 
5878     TRACE("iface %p, stateblock %#x.\n", iface, stateblock);
5879 
5880     wined3d_mutex_lock();
5881 
5882     wined3d_sb = ddraw_free_handle(&device->handle_table, stateblock - 1, DDRAW_HANDLE_STATEBLOCK);
5883     if (!wined3d_sb)
5884     {
5885         WARN("Invalid stateblock handle.\n");
5886         wined3d_mutex_unlock();
5887         return D3DERR_INVALIDSTATEBLOCK;
5888     }
5889 
5890     if ((ref = wined3d_stateblock_decref(wined3d_sb)))
5891     {
5892         ERR("Something is still holding stateblock %p (refcount %u).\n", wined3d_sb, ref);
5893     }
5894 
5895     wined3d_mutex_unlock();
5896 
5897     return D3D_OK;
5898 }
5899 
5900 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUSetup(IDirect3DDevice7 *iface, DWORD stateblock)
5901 {
5902     return d3d_device7_DeleteStateBlock(iface, stateblock);
5903 }
5904 
5905 static HRESULT WINAPI d3d_device7_DeleteStateBlock_FPUPreserve(IDirect3DDevice7 *iface, DWORD stateblock)
5906 {
5907     HRESULT hr;
5908     WORD old_fpucw;
5909 
5910     old_fpucw = d3d_fpu_setup();
5911     hr = d3d_device7_DeleteStateBlock(iface, stateblock);
5912     set_fpu_control_word(old_fpucw);
5913 
5914     return hr;
5915 }
5916 
5917 /*****************************************************************************
5918  * IDirect3DDevice7::CreateStateBlock
5919  *
5920  * Creates a new state block handle.
5921  *
5922  * Version 7
5923  *
5924  * Params:
5925  *  Type: The state block type
5926  *  BlockHandle: Address to write the created handle to
5927  *
5928  * Returns:
5929  *   D3D_OK on success
5930  *   DDERR_INVALIDPARAMS if BlockHandle is NULL
5931  *
5932  *****************************************************************************/
5933 static HRESULT d3d_device7_CreateStateBlock(IDirect3DDevice7 *iface,
5934         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5935 {
5936     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
5937     struct wined3d_stateblock *wined3d_sb;
5938     HRESULT hr;
5939     DWORD h;
5940 
5941     TRACE("iface %p, type %#x, stateblock %p.\n", iface, type, stateblock);
5942 
5943     if (!stateblock)
5944         return DDERR_INVALIDPARAMS;
5945 
5946     if (type != D3DSBT_ALL
5947             && type != D3DSBT_PIXELSTATE
5948             && type != D3DSBT_VERTEXSTATE)
5949     {
5950         WARN("Unexpected stateblock type, returning DDERR_INVALIDPARAMS\n");
5951         return DDERR_INVALIDPARAMS;
5952     }
5953 
5954     wined3d_mutex_lock();
5955 
5956     /* The D3DSTATEBLOCKTYPE enum is fine here. */
5957     hr = wined3d_stateblock_create(device->wined3d_device, type, &wined3d_sb);
5958     if (FAILED(hr))
5959     {
5960         WARN("Failed to create stateblock, hr %#x.\n", hr);
5961         wined3d_mutex_unlock();
5962         return hr_ddraw_from_wined3d(hr);
5963     }
5964 
5965     h = ddraw_allocate_handle(&device->handle_table, wined3d_sb, DDRAW_HANDLE_STATEBLOCK);
5966     if (h == DDRAW_INVALID_HANDLE)
5967     {
5968         ERR("Failed to allocate stateblock handle.\n");
5969         wined3d_stateblock_decref(wined3d_sb);
5970         wined3d_mutex_unlock();
5971         return DDERR_OUTOFMEMORY;
5972     }
5973 
5974     *stateblock = h + 1;
5975     wined3d_mutex_unlock();
5976 
5977     return hr_ddraw_from_wined3d(hr);
5978 }
5979 
5980 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUSetup(IDirect3DDevice7 *iface,
5981         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5982 {
5983     return d3d_device7_CreateStateBlock(iface, type, stateblock);
5984 }
5985 
5986 static HRESULT WINAPI d3d_device7_CreateStateBlock_FPUPreserve(IDirect3DDevice7 *iface,
5987         D3DSTATEBLOCKTYPE type, DWORD *stateblock)
5988 {
5989     HRESULT hr;
5990     WORD old_fpucw;
5991 
5992     old_fpucw = d3d_fpu_setup();
5993     hr = d3d_device7_CreateStateBlock(iface, type, stateblock);
5994     set_fpu_control_word(old_fpucw);
5995 
5996     return hr;
5997 }
5998 
5999 static BOOL is_mip_level_subset(struct ddraw_surface *dest, struct ddraw_surface *src)
6000 {
6001     struct ddraw_surface *src_level, *dest_level;
6002     IDirectDrawSurface7 *temp;
6003     DDSURFACEDESC2 ddsd;
6004     BOOL levelFound; /* at least one suitable sublevel in dest found */
6005 
6006     /* To satisfy "destination is mip level subset of source" criteria (regular texture counts as 1 level),
6007      * 1) there must be at least one mip level in destination that matched dimensions of some mip level in source and
6008      * 2) there must be no destination levels that don't match any levels in source. Otherwise it's INVALIDPARAMS.
6009      */
6010     levelFound = FALSE;
6011 
6012     src_level = src;
6013     dest_level = dest;
6014 
6015     for (;src_level && dest_level;)
6016     {
6017         if (src_level->surface_desc.dwWidth == dest_level->surface_desc.dwWidth &&
6018             src_level->surface_desc.dwHeight == dest_level->surface_desc.dwHeight)
6019         {
6020             levelFound = TRUE;
6021 
6022             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6023             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6024             IDirectDrawSurface7_GetAttachedSurface(&dest_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6025 
6026             if (dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6027 
6028             dest_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6029         }
6030 
6031         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6032         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6033         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6034 
6035         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6036 
6037         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6038     }
6039 
6040     if (src_level && src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6041     if (dest_level && dest_level != dest) IDirectDrawSurface7_Release(&dest_level->IDirectDrawSurface7_iface);
6042 
6043     return !dest_level && levelFound;
6044 }
6045 
6046 static void copy_mipmap_chain(struct d3d_device *device, struct ddraw_surface *dst,
6047         struct ddraw_surface *src, const POINT *DestPoint, const RECT *SrcRect)
6048 {
6049     struct ddraw_surface *dst_level, *src_level;
6050     IDirectDrawSurface7 *temp;
6051     DDSURFACEDESC2 ddsd;
6052     POINT point;
6053     RECT src_rect;
6054     HRESULT hr;
6055     IDirectDrawPalette *pal = NULL, *pal_src = NULL;
6056     DWORD ckeyflag;
6057     DDCOLORKEY ddckey;
6058 
6059     /* Copy palette, if possible. */
6060     IDirectDrawSurface7_GetPalette(&src->IDirectDrawSurface7_iface, &pal_src);
6061     IDirectDrawSurface7_GetPalette(&dst->IDirectDrawSurface7_iface, &pal);
6062 
6063     if (pal_src != NULL && pal != NULL)
6064     {
6065         PALETTEENTRY palent[256];
6066 
6067         IDirectDrawPalette_GetEntries(pal_src, 0, 0, 256, palent);
6068         IDirectDrawPalette_SetEntries(pal, 0, 0, 256, palent);
6069     }
6070 
6071     if (pal) IDirectDrawPalette_Release(pal);
6072     if (pal_src) IDirectDrawPalette_Release(pal_src);
6073 
6074     /* Copy colorkeys, if present. */
6075     for (ckeyflag = DDCKEY_DESTBLT; ckeyflag <= DDCKEY_SRCOVERLAY; ckeyflag <<= 1)
6076     {
6077         hr = IDirectDrawSurface7_GetColorKey(&src->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6078 
6079         if (SUCCEEDED(hr))
6080         {
6081             IDirectDrawSurface7_SetColorKey(&dst->IDirectDrawSurface7_iface, ckeyflag, &ddckey);
6082         }
6083     }
6084 
6085     src_level = src;
6086     dst_level = dst;
6087 
6088     point = *DestPoint;
6089     src_rect = *SrcRect;
6090 
6091     for (;src_level && dst_level;)
6092     {
6093         if (src_level->surface_desc.dwWidth == dst_level->surface_desc.dwWidth
6094                 && src_level->surface_desc.dwHeight == dst_level->surface_desc.dwHeight)
6095         {
6096             UINT src_w = src_rect.right - src_rect.left;
6097             UINT src_h = src_rect.bottom - src_rect.top;
6098             RECT dst_rect = {point.x, point.y, point.x + src_w, point.y + src_h};
6099 
6100             if (FAILED(hr = wined3d_texture_blt(dst_level->wined3d_texture, dst_level->sub_resource_idx, &dst_rect,
6101                     src_level->wined3d_texture, src_level->sub_resource_idx, &src_rect, 0, NULL, WINED3D_TEXF_POINT)))
6102                 ERR("Blit failed, hr %#x.\n", hr);
6103 
6104             ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6105             ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6106             IDirectDrawSurface7_GetAttachedSurface(&dst_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6107 
6108             if (dst_level != dst)
6109                 IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6110 
6111             dst_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6112         }
6113 
6114         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6115         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
6116         IDirectDrawSurface7_GetAttachedSurface(&src_level->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6117 
6118         if (src_level != src) IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6119 
6120         src_level = unsafe_impl_from_IDirectDrawSurface7(temp);
6121 
6122         point.x /= 2;
6123         point.y /= 2;
6124 
6125         src_rect.top /= 2;
6126         src_rect.left /= 2;
6127         src_rect.right = (src_rect.right + 1) / 2;
6128         src_rect.bottom = (src_rect.bottom + 1) / 2;
6129     }
6130 
6131     if (src_level && src_level != src)
6132         IDirectDrawSurface7_Release(&src_level->IDirectDrawSurface7_iface);
6133     if (dst_level && dst_level != dst)
6134         IDirectDrawSurface7_Release(&dst_level->IDirectDrawSurface7_iface);
6135 }
6136 
6137 /*****************************************************************************
6138  * IDirect3DDevice7::Load
6139  *
6140  * Loads a rectangular area from the source into the destination texture.
6141  * It can also copy the source to the faces of a cubic environment map
6142  *
6143  * Version 7
6144  *
6145  * Params:
6146  *  DestTex: Destination texture
6147  *  DestPoint: Point in the destination where the source image should be
6148  *             written to
6149  *  SrcTex: Source texture
6150  *  SrcRect: Source rectangle
6151  *  Flags: Cubemap faces to load (DDSCAPS2_CUBEMAP_ALLFACES, DDSCAPS2_CUBEMAP_POSITIVEX,
6152  *          DDSCAPS2_CUBEMAP_NEGATIVEX, DDSCAPS2_CUBEMAP_POSITIVEY, DDSCAPS2_CUBEMAP_NEGATIVEY,
6153  *          DDSCAPS2_CUBEMAP_POSITIVEZ, DDSCAPS2_CUBEMAP_NEGATIVEZ)
6154  *
6155  * Returns:
6156  *  D3D_OK on success
6157  *  DDERR_INVALIDPARAMS if dst_texture or src_texture is NULL, broken coordinates or anything unexpected.
6158  *
6159  *
6160  *****************************************************************************/
6161 static HRESULT d3d_device7_Load(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture, POINT *dst_pos,
6162         IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6163 {
6164     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6165     struct ddraw_surface *dest = unsafe_impl_from_IDirectDrawSurface7(dst_texture);
6166     struct ddraw_surface *src = unsafe_impl_from_IDirectDrawSurface7(src_texture);
6167     POINT destpoint;
6168     RECT srcrect;
6169 
6170     TRACE("iface %p, dst_texture %p, dst_pos %s, src_texture %p, src_rect %s, flags %#x.\n",
6171             iface, dst_texture, wine_dbgstr_point(dst_pos), src_texture, wine_dbgstr_rect(src_rect), flags);
6172 
6173     if( (!src) || (!dest) )
6174         return DDERR_INVALIDPARAMS;
6175 
6176     wined3d_mutex_lock();
6177 
6178     if (!src_rect)
6179         SetRect(&srcrect, 0, 0, src->surface_desc.dwWidth, src->surface_desc.dwHeight);
6180     else
6181         srcrect = *src_rect;
6182 
6183     if (!dst_pos)
6184         destpoint.x = destpoint.y = 0;
6185     else
6186         destpoint = *dst_pos;
6187 
6188     /* Check bad dimensions. dst_pos is validated against src, not dest, because
6189      * destination can be a subset of mip levels, in which case actual coordinates used
6190      * for it may be divided. If any dimension of dest is larger than source, it can't be
6191      * mip level subset, so an error can be returned early.
6192      */
6193     if (IsRectEmpty(&srcrect) || srcrect.right > src->surface_desc.dwWidth ||
6194         srcrect.bottom > src->surface_desc.dwHeight ||
6195         destpoint.x + srcrect.right - srcrect.left > src->surface_desc.dwWidth ||
6196         destpoint.y + srcrect.bottom - srcrect.top > src->surface_desc.dwHeight ||
6197         dest->surface_desc.dwWidth > src->surface_desc.dwWidth ||
6198         dest->surface_desc.dwHeight > src->surface_desc.dwHeight)
6199     {
6200         wined3d_mutex_unlock();
6201         return DDERR_INVALIDPARAMS;
6202     }
6203 
6204     /* Must be top level surfaces. */
6205     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL ||
6206         dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_MIPMAPSUBLEVEL)
6207     {
6208         wined3d_mutex_unlock();
6209         return DDERR_INVALIDPARAMS;
6210     }
6211 
6212     if (src->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6213     {
6214         struct ddraw_surface *src_face, *dest_face;
6215         DWORD src_face_flag, dest_face_flag;
6216         IDirectDrawSurface7 *temp;
6217         DDSURFACEDESC2 ddsd;
6218         int i;
6219 
6220         if (!(dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
6221         {
6222             wined3d_mutex_unlock();
6223             return DDERR_INVALIDPARAMS;
6224         }
6225 
6226         /* Iterate through cube faces 2 times. First time is just to check INVALIDPARAMS conditions, second
6227          * time it's actual surface loading. */
6228         for (i = 0; i < 2; i++)
6229         {
6230             dest_face = dest;
6231             src_face = src;
6232 
6233             for (;dest_face && src_face;)
6234             {
6235                 src_face_flag = src_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6236                 dest_face_flag = dest_face->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES;
6237 
6238                 if (src_face_flag == dest_face_flag)
6239                 {
6240                     if (i == 0)
6241                     {
6242                         /* Destination mip levels must be subset of source mip levels. */
6243                         if (!is_mip_level_subset(dest_face, src_face))
6244                         {
6245                             wined3d_mutex_unlock();
6246                             return DDERR_INVALIDPARAMS;
6247                         }
6248                     }
6249                     else if (flags & dest_face_flag)
6250                     {
6251                         copy_mipmap_chain(device, dest_face, src_face, &destpoint, &srcrect);
6252                     }
6253 
6254                     if (src_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6255                     {
6256                         ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6257                         ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (src_face_flag << 1);
6258                         IDirectDrawSurface7_GetAttachedSurface(&src->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6259 
6260                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6261 
6262                         src_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6263                     }
6264                     else
6265                     {
6266                         if (src_face != src) IDirectDrawSurface7_Release(&src_face->IDirectDrawSurface7_iface);
6267 
6268                         src_face = NULL;
6269                     }
6270                 }
6271 
6272                 if (dest_face_flag < DDSCAPS2_CUBEMAP_NEGATIVEZ)
6273                 {
6274                     ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
6275                     ddsd.ddsCaps.dwCaps2 = DDSCAPS2_CUBEMAP | (dest_face_flag << 1);
6276                     IDirectDrawSurface7_GetAttachedSurface(&dest->IDirectDrawSurface7_iface, &ddsd.ddsCaps, &temp);
6277 
6278                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6279 
6280                     dest_face = unsafe_impl_from_IDirectDrawSurface7(temp);
6281                 }
6282                 else
6283                 {
6284                     if (dest_face != dest) IDirectDrawSurface7_Release(&dest_face->IDirectDrawSurface7_iface);
6285 
6286                     dest_face = NULL;
6287                 }
6288             }
6289 
6290             if (i == 0)
6291             {
6292                 /* Native returns error if src faces are not subset of dest faces. */
6293                 if (src_face)
6294                 {
6295                     wined3d_mutex_unlock();
6296                     return DDERR_INVALIDPARAMS;
6297                 }
6298             }
6299         }
6300 
6301         wined3d_mutex_unlock();
6302         return D3D_OK;
6303     }
6304     else if (dest->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
6305     {
6306         wined3d_mutex_unlock();
6307         return DDERR_INVALIDPARAMS;
6308     }
6309 
6310     /* Handle non cube map textures. */
6311 
6312     /* Destination mip levels must be subset of source mip levels. */
6313     if (!is_mip_level_subset(dest, src))
6314     {
6315         wined3d_mutex_unlock();
6316         return DDERR_INVALIDPARAMS;
6317     }
6318 
6319     copy_mipmap_chain(device, dest, src, &destpoint, &srcrect);
6320 
6321     wined3d_mutex_unlock();
6322 
6323     return D3D_OK;
6324 }
6325 
6326 static HRESULT WINAPI d3d_device7_Load_FPUSetup(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6327         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6328 {
6329     return d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6330 }
6331 
6332 static HRESULT WINAPI d3d_device7_Load_FPUPreserve(IDirect3DDevice7 *iface, IDirectDrawSurface7 *dst_texture,
6333         POINT *dst_pos, IDirectDrawSurface7 *src_texture, RECT *src_rect, DWORD flags)
6334 {
6335     HRESULT hr;
6336     WORD old_fpucw;
6337 
6338     old_fpucw = d3d_fpu_setup();
6339     hr = d3d_device7_Load(iface, dst_texture, dst_pos, src_texture, src_rect, flags);
6340     set_fpu_control_word(old_fpucw);
6341 
6342     return hr;
6343 }
6344 
6345 /*****************************************************************************
6346  * IDirect3DDevice7::LightEnable
6347  *
6348  * Enables or disables a light
6349  *
6350  * Version 7, IDirect3DLight uses this method too.
6351  *
6352  * Params:
6353  *  LightIndex: The index of the light to enable / disable
6354  *  Enable: Enable or disable the light
6355  *
6356  * Returns:
6357  *  D3D_OK on success
6358  *
6359  *****************************************************************************/
6360 static HRESULT d3d_device7_LightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6361 {
6362     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6363     HRESULT hr;
6364 
6365     TRACE("iface %p, light_idx %u, enabled %#x.\n", iface, light_idx, enabled);
6366 
6367     wined3d_mutex_lock();
6368     hr = wined3d_device_set_light_enable(device->wined3d_device, light_idx, enabled);
6369     wined3d_mutex_unlock();
6370 
6371     return hr_ddraw_from_wined3d(hr);
6372 }
6373 
6374 static HRESULT WINAPI d3d_device7_LightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6375 {
6376     return d3d_device7_LightEnable(iface, light_idx, enabled);
6377 }
6378 
6379 static HRESULT WINAPI d3d_device7_LightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL enabled)
6380 {
6381     HRESULT hr;
6382     WORD old_fpucw;
6383 
6384     old_fpucw = d3d_fpu_setup();
6385     hr = d3d_device7_LightEnable(iface, light_idx, enabled);
6386     set_fpu_control_word(old_fpucw);
6387 
6388     return hr;
6389 }
6390 
6391 /*****************************************************************************
6392  * IDirect3DDevice7::GetLightEnable
6393  *
6394  * Retrieves if the light with the given index is enabled or not
6395  *
6396  * Version 7
6397  *
6398  * Params:
6399  *  LightIndex: Index of desired light
6400  *  Enable: Pointer to a BOOL which contains the result
6401  *
6402  * Returns:
6403  *  D3D_OK on success
6404  *  DDERR_INVALIDPARAMS if Enable is NULL
6405  *
6406  *****************************************************************************/
6407 static HRESULT d3d_device7_GetLightEnable(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6408 {
6409     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6410     HRESULT hr;
6411 
6412     TRACE("iface %p, light_idx %u, enabled %p.\n", iface, light_idx, enabled);
6413 
6414     if (!enabled)
6415         return DDERR_INVALIDPARAMS;
6416 
6417     wined3d_mutex_lock();
6418     hr = wined3d_device_get_light_enable(device->wined3d_device, light_idx, enabled);
6419     wined3d_mutex_unlock();
6420 
6421     return hr_ddraw_from_wined3d(hr);
6422 }
6423 
6424 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUSetup(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6425 {
6426     return d3d_device7_GetLightEnable(iface, light_idx, enabled);
6427 }
6428 
6429 static HRESULT WINAPI d3d_device7_GetLightEnable_FPUPreserve(IDirect3DDevice7 *iface, DWORD light_idx, BOOL *enabled)
6430 {
6431     HRESULT hr;
6432     WORD old_fpucw;
6433 
6434     old_fpucw = d3d_fpu_setup();
6435     hr = d3d_device7_GetLightEnable(iface, light_idx, enabled);
6436     set_fpu_control_word(old_fpucw);
6437 
6438     return hr;
6439 }
6440 
6441 /*****************************************************************************
6442  * IDirect3DDevice7::SetClipPlane
6443  *
6444  * Sets custom clipping plane
6445  *
6446  * Version 7
6447  *
6448  * Params:
6449  *  Index: The index of the clipping plane
6450  *  PlaneEquation: An equation defining the clipping plane
6451  *
6452  * Returns:
6453  *  D3D_OK on success
6454  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6455  *
6456  *****************************************************************************/
6457 static HRESULT d3d_device7_SetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6458 {
6459     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6460     const struct wined3d_vec4 *wined3d_plane;
6461     HRESULT hr;
6462 
6463     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6464 
6465     if (!plane)
6466         return DDERR_INVALIDPARAMS;
6467 
6468     wined3d_plane = (struct wined3d_vec4 *)plane;
6469 
6470     wined3d_mutex_lock();
6471     hr = wined3d_device_set_clip_plane(device->wined3d_device, idx, wined3d_plane);
6472     if (idx < ARRAY_SIZE(device->user_clip_planes))
6473     {
6474         device->user_clip_planes[idx] = *wined3d_plane;
6475         if (hr == WINED3DERR_INVALIDCALL)
6476         {
6477             WARN("Clip plane %u is not supported.\n", idx);
6478             hr = D3D_OK;
6479         }
6480     }
6481     wined3d_mutex_unlock();
6482 
6483     return hr;
6484 }
6485 
6486 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6487 {
6488     return d3d_device7_SetClipPlane(iface, idx, plane);
6489 }
6490 
6491 static HRESULT WINAPI d3d_device7_SetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6492 {
6493     HRESULT hr;
6494     WORD old_fpucw;
6495 
6496     old_fpucw = d3d_fpu_setup();
6497     hr = d3d_device7_SetClipPlane(iface, idx, plane);
6498     set_fpu_control_word(old_fpucw);
6499 
6500     return hr;
6501 }
6502 
6503 /*****************************************************************************
6504  * IDirect3DDevice7::GetClipPlane
6505  *
6506  * Returns the clipping plane with a specific index
6507  *
6508  * Params:
6509  *  Index: The index of the desired plane
6510  *  PlaneEquation: Address to store the plane equation to
6511  *
6512  * Returns:
6513  *  D3D_OK on success
6514  *  DDERR_INVALIDPARAMS if PlaneEquation is NULL
6515  *
6516  *****************************************************************************/
6517 static HRESULT d3d_device7_GetClipPlane(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6518 {
6519     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
6520     struct wined3d_vec4 *wined3d_plane;
6521     HRESULT hr;
6522 
6523     TRACE("iface %p, idx %u, plane %p.\n", iface, idx, plane);
6524 
6525     if (!plane)
6526         return DDERR_INVALIDPARAMS;
6527 
6528     wined3d_plane = (struct wined3d_vec4 *)plane;
6529 
6530     wined3d_mutex_lock();
6531     hr = wined3d_device_get_clip_plane(device->wined3d_device, idx, wined3d_plane);
6532     if (hr == WINED3DERR_INVALIDCALL && idx < ARRAY_SIZE(device->user_clip_planes))
6533     {
6534         WARN("Clip plane %u is not supported.\n", idx);
6535         *wined3d_plane = device->user_clip_planes[idx];
6536         hr = D3D_OK;
6537     }
6538     wined3d_mutex_unlock();
6539 
6540     return hr;
6541 }
6542 
6543 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUSetup(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6544 {
6545     return d3d_device7_GetClipPlane(iface, idx, plane);
6546 }
6547 
6548 static HRESULT WINAPI d3d_device7_GetClipPlane_FPUPreserve(IDirect3DDevice7 *iface, DWORD idx, D3DVALUE *plane)
6549 {
6550     HRESULT hr;
6551     WORD old_fpucw;
6552 
6553     old_fpucw = d3d_fpu_setup();
6554     hr = d3d_device7_GetClipPlane(iface, idx, plane);
6555     set_fpu_control_word(old_fpucw);
6556 
6557     return hr;
6558 }
6559 
6560 /*****************************************************************************
6561  * IDirect3DDevice7::GetInfo
6562  *
6563  * Retrieves some information about the device. The DirectX sdk says that
6564  * this version returns S_FALSE for all retail builds of DirectX, that's what
6565  * this implementation does.
6566  *
6567  * Params:
6568  *  DevInfoID: Information type requested
6569  *  DevInfoStruct: Pointer to a structure to store the info to
6570  *  Size: Size of the structure
6571  *
6572  * Returns:
6573  *  S_FALSE, because it's a non-debug driver
6574  *
6575  *****************************************************************************/
6576 static HRESULT WINAPI d3d_device7_GetInfo(IDirect3DDevice7 *iface, DWORD info_id, void *info, DWORD info_size)
6577 {
6578     TRACE("iface %p, info_id %#x, info %p, info_size %u.\n",
6579             iface, info_id, info, info_size);
6580 
6581     if (TRACE_ON(ddraw))
6582     {
6583         TRACE(" info requested : ");
6584         switch (info_id)
6585         {
6586             case D3DDEVINFOID_TEXTUREMANAGER: TRACE("D3DDEVINFOID_TEXTUREMANAGER\n"); break;
6587             case D3DDEVINFOID_D3DTEXTUREMANAGER: TRACE("D3DDEVINFOID_D3DTEXTUREMANAGER\n"); break;
6588             case D3DDEVINFOID_TEXTURING: TRACE("D3DDEVINFOID_TEXTURING\n"); break;
6589             default: ERR(" invalid flag !!!\n"); return DDERR_INVALIDPARAMS;
6590         }
6591     }
6592 
6593     return S_FALSE; /* According to MSDN, this is valid for a non-debug driver */
6594 }
6595 
6596 /* For performance optimization, devices created in FPUSETUP and FPUPRESERVE modes
6597  * have separate vtables. Simple functions where this doesn't matter like GetDirect3D
6598  * are not duplicated.
6599 
6600  * Device created with DDSCL_FPUSETUP (d3d7 default) - device methods assume that FPU
6601  * has already been setup for optimal d3d operation.
6602 
6603  * Device created with DDSCL_FPUPRESERVE - resets and restores FPU mode when necessary in
6604  * d3d calls (FPU may be in a mode non-suitable for d3d when the app calls d3d). Required
6605  * by Sacrifice (game). */
6606 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_setup_vtbl =
6607 {
6608     /*** IUnknown Methods ***/
6609     d3d_device7_QueryInterface,
6610     d3d_device7_AddRef,
6611     d3d_device7_Release,
6612     /*** IDirect3DDevice7 ***/
6613     d3d_device7_GetCaps_FPUSetup,
6614     d3d_device7_EnumTextureFormats_FPUSetup,
6615     d3d_device7_BeginScene_FPUSetup,
6616     d3d_device7_EndScene_FPUSetup,
6617     d3d_device7_GetDirect3D,
6618     d3d_device7_SetRenderTarget_FPUSetup,
6619     d3d_device7_GetRenderTarget,
6620     d3d_device7_Clear_FPUSetup,
6621     d3d_device7_SetTransform_FPUSetup,
6622     d3d_device7_GetTransform_FPUSetup,
6623     d3d_device7_SetViewport_FPUSetup,
6624     d3d_device7_MultiplyTransform_FPUSetup,
6625     d3d_device7_GetViewport_FPUSetup,
6626     d3d_device7_SetMaterial_FPUSetup,
6627     d3d_device7_GetMaterial_FPUSetup,
6628     d3d_device7_SetLight_FPUSetup,
6629     d3d_device7_GetLight_FPUSetup,
6630     d3d_device7_SetRenderState_FPUSetup,
6631     d3d_device7_GetRenderState_FPUSetup,
6632     d3d_device7_BeginStateBlock_FPUSetup,
6633     d3d_device7_EndStateBlock_FPUSetup,
6634     d3d_device7_PreLoad_FPUSetup,
6635     d3d_device7_DrawPrimitive_FPUSetup,
6636     d3d_device7_DrawIndexedPrimitive_FPUSetup,
6637     d3d_device7_SetClipStatus,
6638     d3d_device7_GetClipStatus,
6639     d3d_device7_DrawPrimitiveStrided_FPUSetup,
6640     d3d_device7_DrawIndexedPrimitiveStrided_FPUSetup,
6641     d3d_device7_DrawPrimitiveVB_FPUSetup,
6642     d3d_device7_DrawIndexedPrimitiveVB_FPUSetup,
6643     d3d_device7_ComputeSphereVisibility,
6644     d3d_device7_GetTexture_FPUSetup,
6645     d3d_device7_SetTexture_FPUSetup,
6646     d3d_device7_GetTextureStageState_FPUSetup,
6647     d3d_device7_SetTextureStageState_FPUSetup,
6648     d3d_device7_ValidateDevice_FPUSetup,
6649     d3d_device7_ApplyStateBlock_FPUSetup,
6650     d3d_device7_CaptureStateBlock_FPUSetup,
6651     d3d_device7_DeleteStateBlock_FPUSetup,
6652     d3d_device7_CreateStateBlock_FPUSetup,
6653     d3d_device7_Load_FPUSetup,
6654     d3d_device7_LightEnable_FPUSetup,
6655     d3d_device7_GetLightEnable_FPUSetup,
6656     d3d_device7_SetClipPlane_FPUSetup,
6657     d3d_device7_GetClipPlane_FPUSetup,
6658     d3d_device7_GetInfo
6659 };
6660 
6661 static const struct IDirect3DDevice7Vtbl d3d_device7_fpu_preserve_vtbl =
6662 {
6663     /*** IUnknown Methods ***/
6664     d3d_device7_QueryInterface,
6665     d3d_device7_AddRef,
6666     d3d_device7_Release,
6667     /*** IDirect3DDevice7 ***/
6668     d3d_device7_GetCaps_FPUPreserve,
6669     d3d_device7_EnumTextureFormats_FPUPreserve,
6670     d3d_device7_BeginScene_FPUPreserve,
6671     d3d_device7_EndScene_FPUPreserve,
6672     d3d_device7_GetDirect3D,
6673     d3d_device7_SetRenderTarget_FPUPreserve,
6674     d3d_device7_GetRenderTarget,
6675     d3d_device7_Clear_FPUPreserve,
6676     d3d_device7_SetTransform_FPUPreserve,
6677     d3d_device7_GetTransform_FPUPreserve,
6678     d3d_device7_SetViewport_FPUPreserve,
6679     d3d_device7_MultiplyTransform_FPUPreserve,
6680     d3d_device7_GetViewport_FPUPreserve,
6681     d3d_device7_SetMaterial_FPUPreserve,
6682     d3d_device7_GetMaterial_FPUPreserve,
6683     d3d_device7_SetLight_FPUPreserve,
6684     d3d_device7_GetLight_FPUPreserve,
6685     d3d_device7_SetRenderState_FPUPreserve,
6686     d3d_device7_GetRenderState_FPUPreserve,
6687     d3d_device7_BeginStateBlock_FPUPreserve,
6688     d3d_device7_EndStateBlock_FPUPreserve,
6689     d3d_device7_PreLoad_FPUPreserve,
6690     d3d_device7_DrawPrimitive_FPUPreserve,
6691     d3d_device7_DrawIndexedPrimitive_FPUPreserve,
6692     d3d_device7_SetClipStatus,
6693     d3d_device7_GetClipStatus,
6694     d3d_device7_DrawPrimitiveStrided_FPUPreserve,
6695     d3d_device7_DrawIndexedPrimitiveStrided_FPUPreserve,
6696     d3d_device7_DrawPrimitiveVB_FPUPreserve,
6697     d3d_device7_DrawIndexedPrimitiveVB_FPUPreserve,
6698     d3d_device7_ComputeSphereVisibility,
6699     d3d_device7_GetTexture_FPUPreserve,
6700     d3d_device7_SetTexture_FPUPreserve,
6701     d3d_device7_GetTextureStageState_FPUPreserve,
6702     d3d_device7_SetTextureStageState_FPUPreserve,
6703     d3d_device7_ValidateDevice_FPUPreserve,
6704     d3d_device7_ApplyStateBlock_FPUPreserve,
6705     d3d_device7_CaptureStateBlock_FPUPreserve,
6706     d3d_device7_DeleteStateBlock_FPUPreserve,
6707     d3d_device7_CreateStateBlock_FPUPreserve,
6708     d3d_device7_Load_FPUPreserve,
6709     d3d_device7_LightEnable_FPUPreserve,
6710     d3d_device7_GetLightEnable_FPUPreserve,
6711     d3d_device7_SetClipPlane_FPUPreserve,
6712     d3d_device7_GetClipPlane_FPUPreserve,
6713     d3d_device7_GetInfo
6714 };
6715 
6716 static const struct IDirect3DDevice3Vtbl d3d_device3_vtbl =
6717 {
6718     /*** IUnknown Methods ***/
6719     d3d_device3_QueryInterface,
6720     d3d_device3_AddRef,
6721     d3d_device3_Release,
6722     /*** IDirect3DDevice3 ***/
6723     d3d_device3_GetCaps,
6724     d3d_device3_GetStats,
6725     d3d_device3_AddViewport,
6726     d3d_device3_DeleteViewport,
6727     d3d_device3_NextViewport,
6728     d3d_device3_EnumTextureFormats,
6729     d3d_device3_BeginScene,
6730     d3d_device3_EndScene,
6731     d3d_device3_GetDirect3D,
6732     d3d_device3_SetCurrentViewport,
6733     d3d_device3_GetCurrentViewport,
6734     d3d_device3_SetRenderTarget,
6735     d3d_device3_GetRenderTarget,
6736     d3d_device3_Begin,
6737     d3d_device3_BeginIndexed,
6738     d3d_device3_Vertex,
6739     d3d_device3_Index,
6740     d3d_device3_End,
6741     d3d_device3_GetRenderState,
6742     d3d_device3_SetRenderState,
6743     d3d_device3_GetLightState,
6744     d3d_device3_SetLightState,
6745     d3d_device3_SetTransform,
6746     d3d_device3_GetTransform,
6747     d3d_device3_MultiplyTransform,
6748     d3d_device3_DrawPrimitive,
6749     d3d_device3_DrawIndexedPrimitive,
6750     d3d_device3_SetClipStatus,
6751     d3d_device3_GetClipStatus,
6752     d3d_device3_DrawPrimitiveStrided,
6753     d3d_device3_DrawIndexedPrimitiveStrided,
6754     d3d_device3_DrawPrimitiveVB,
6755     d3d_device3_DrawIndexedPrimitiveVB,
6756     d3d_device3_ComputeSphereVisibility,
6757     d3d_device3_GetTexture,
6758     d3d_device3_SetTexture,
6759     d3d_device3_GetTextureStageState,
6760     d3d_device3_SetTextureStageState,
6761     d3d_device3_ValidateDevice
6762 };
6763 
6764 static const struct IDirect3DDevice2Vtbl d3d_device2_vtbl =
6765 {
6766     /*** IUnknown Methods ***/
6767     d3d_device2_QueryInterface,
6768     d3d_device2_AddRef,
6769     d3d_device2_Release,
6770     /*** IDirect3DDevice2 ***/
6771     d3d_device2_GetCaps,
6772     d3d_device2_SwapTextureHandles,
6773     d3d_device2_GetStats,
6774     d3d_device2_AddViewport,
6775     d3d_device2_DeleteViewport,
6776     d3d_device2_NextViewport,
6777     d3d_device2_EnumTextureFormats,
6778     d3d_device2_BeginScene,
6779     d3d_device2_EndScene,
6780     d3d_device2_GetDirect3D,
6781     d3d_device2_SetCurrentViewport,
6782     d3d_device2_GetCurrentViewport,
6783     d3d_device2_SetRenderTarget,
6784     d3d_device2_GetRenderTarget,
6785     d3d_device2_Begin,
6786     d3d_device2_BeginIndexed,
6787     d3d_device2_Vertex,
6788     d3d_device2_Index,
6789     d3d_device2_End,
6790     d3d_device2_GetRenderState,
6791     d3d_device2_SetRenderState,
6792     d3d_device2_GetLightState,
6793     d3d_device2_SetLightState,
6794     d3d_device2_SetTransform,
6795     d3d_device2_GetTransform,
6796     d3d_device2_MultiplyTransform,
6797     d3d_device2_DrawPrimitive,
6798     d3d_device2_DrawIndexedPrimitive,
6799     d3d_device2_SetClipStatus,
6800     d3d_device2_GetClipStatus
6801 };
6802 
6803 static const struct IDirect3DDeviceVtbl d3d_device1_vtbl =
6804 {
6805     /*** IUnknown Methods ***/
6806     d3d_device1_QueryInterface,
6807     d3d_device1_AddRef,
6808     d3d_device1_Release,
6809     /*** IDirect3DDevice1 ***/
6810     d3d_device1_Initialize,
6811     d3d_device1_GetCaps,
6812     d3d_device1_SwapTextureHandles,
6813     d3d_device1_CreateExecuteBuffer,
6814     d3d_device1_GetStats,
6815     d3d_device1_Execute,
6816     d3d_device1_AddViewport,
6817     d3d_device1_DeleteViewport,
6818     d3d_device1_NextViewport,
6819     d3d_device1_Pick,
6820     d3d_device1_GetPickRecords,
6821     d3d_device1_EnumTextureFormats,
6822     d3d_device1_CreateMatrix,
6823     d3d_device1_SetMatrix,
6824     d3d_device1_GetMatrix,
6825     d3d_device1_DeleteMatrix,
6826     d3d_device1_BeginScene,
6827     d3d_device1_EndScene,
6828     d3d_device1_GetDirect3D
6829 };
6830 
6831 static const struct IUnknownVtbl d3d_device_inner_vtbl =
6832 {
6833     d3d_device_inner_QueryInterface,
6834     d3d_device_inner_AddRef,
6835     d3d_device_inner_Release,
6836 };
6837 
6838 struct d3d_device *unsafe_impl_from_IDirect3DDevice7(IDirect3DDevice7 *iface)
6839 {
6840     if (!iface) return NULL;
6841     assert((iface->lpVtbl == &d3d_device7_fpu_preserve_vtbl) || (iface->lpVtbl == &d3d_device7_fpu_setup_vtbl));
6842     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice7_iface);
6843 }
6844 
6845 struct d3d_device *unsafe_impl_from_IDirect3DDevice3(IDirect3DDevice3 *iface)
6846 {
6847     if (!iface) return NULL;
6848     assert(iface->lpVtbl == &d3d_device3_vtbl);
6849     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice3_iface);
6850 }
6851 
6852 struct d3d_device *unsafe_impl_from_IDirect3DDevice2(IDirect3DDevice2 *iface)
6853 {
6854     if (!iface) return NULL;
6855     assert(iface->lpVtbl == &d3d_device2_vtbl);
6856     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice2_iface);
6857 }
6858 
6859 struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
6860 {
6861     if (!iface) return NULL;
6862     assert(iface->lpVtbl == &d3d_device1_vtbl);
6863     return CONTAINING_RECORD(iface, struct d3d_device, IDirect3DDevice_iface);
6864 }
6865 
6866 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
6867 {
6868     IDirectDrawSurface7 *depthStencil = NULL;
6869     IDirectDrawSurface7 *render_target;
6870     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, {0} };
6871     struct ddraw_surface *dsi;
6872 
6873     if (device->rt_iface && SUCCEEDED(IUnknown_QueryInterface(device->rt_iface,
6874             &IID_IDirectDrawSurface7, (void **)&render_target)))
6875     {
6876         IDirectDrawSurface7_GetAttachedSurface(render_target, &depthcaps, &depthStencil);
6877         IDirectDrawSurface7_Release(render_target);
6878     }
6879     if (!depthStencil)
6880     {
6881         TRACE("Setting wined3d depth stencil to NULL\n");
6882         wined3d_device_set_depth_stencil_view(device->wined3d_device, NULL);
6883         return WINED3D_ZB_FALSE;
6884     }
6885 
6886     dsi = impl_from_IDirectDrawSurface7(depthStencil);
6887     wined3d_device_set_depth_stencil_view(device->wined3d_device,
6888             ddraw_surface_get_rendertarget_view(dsi));
6889 
6890     IDirectDrawSurface7_Release(depthStencil);
6891     return WINED3D_ZB_TRUE;
6892 }
6893 
6894 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw, BOOL hw,
6895         struct ddraw_surface *target, IUnknown *rt_iface, UINT version, IUnknown *outer_unknown)
6896 {
6897     static const D3DMATRIX ident =
6898     {
6899         1.0f, 0.0f, 0.0f, 0.0f,
6900         0.0f, 1.0f, 0.0f, 0.0f,
6901         0.0f, 0.0f, 1.0f, 0.0f,
6902         0.0f, 0.0f, 0.0f, 1.0f,
6903     };
6904     HRESULT hr;
6905 
6906     if (ddraw->cooperative_level & DDSCL_FPUPRESERVE)
6907         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_preserve_vtbl;
6908     else
6909         device->IDirect3DDevice7_iface.lpVtbl = &d3d_device7_fpu_setup_vtbl;
6910 
6911     device->IDirect3DDevice3_iface.lpVtbl = &d3d_device3_vtbl;
6912     device->IDirect3DDevice2_iface.lpVtbl = &d3d_device2_vtbl;
6913     device->IDirect3DDevice_iface.lpVtbl = &d3d_device1_vtbl;
6914     device->IUnknown_inner.lpVtbl = &d3d_device_inner_vtbl;
6915     device->ref = 1;
6916     device->version = version;
6917     device->hw = hw;
6918 
6919     if (outer_unknown)
6920         device->outer_unknown = outer_unknown;
6921     else
6922         device->outer_unknown = &device->IUnknown_inner;
6923 
6924     device->ddraw = ddraw;
6925     list_init(&device->viewport_list);
6926 
6927     if (!ddraw_handle_table_init(&device->handle_table, 64))
6928     {
6929         ERR("Failed to initialize handle table.\n");
6930         return DDERR_OUTOFMEMORY;
6931     }
6932 
6933     device->legacyTextureBlending = FALSE;
6934     device->legacy_projection = ident;
6935     device->legacy_clipspace = ident;
6936 
6937     /* This is for convenience. */
6938     device->wined3d_device = ddraw->wined3d_device;
6939     wined3d_device_incref(ddraw->wined3d_device);
6940 
6941     /* Render to the back buffer */
6942     if (FAILED(hr = wined3d_device_set_rendertarget_view(ddraw->wined3d_device,
6943             0, ddraw_surface_get_rendertarget_view(target), TRUE)))
6944     {
6945         ERR("Failed to set render target, hr %#x.\n", hr);
6946         ddraw_handle_table_destroy(&device->handle_table);
6947         return hr;
6948     }
6949 
6950     device->rt_iface = rt_iface;
6951     if (version != 1)
6952         IUnknown_AddRef(device->rt_iface);
6953 
6954     ddraw->d3ddevice = device;
6955 
6956     wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_ZENABLE,
6957             d3d_device_update_depth_stencil(device));
6958     if (version == 1) /* Color keying is initially enabled for version 1 devices. */
6959         wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_COLORKEYENABLE, TRUE);
6960     else if (version == 2)
6961         wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_SPECULARENABLE, TRUE);
6962     if (version < 7)
6963         wined3d_device_set_render_state(ddraw->wined3d_device, WINED3D_RS_NORMALIZENORMALS, TRUE);
6964 
6965     return D3D_OK;
6966 }
6967 
6968 HRESULT d3d_device_create(struct ddraw *ddraw, const GUID *guid, struct ddraw_surface *target, IUnknown *rt_iface,
6969         UINT version, struct d3d_device **device, IUnknown *outer_unknown)
6970 {
6971     struct d3d_device *object;
6972     BOOL hw = TRUE;
6973     HRESULT hr;
6974 
6975     TRACE("ddraw %p, guid %s, target %p, version %u, device %p, outer_unknown %p.\n",
6976             ddraw, debugstr_guid(guid), target, version, device, outer_unknown);
6977 
6978     if (IsEqualGUID(guid, &IID_IDirect3DRGBDevice))
6979         hw = FALSE;
6980 
6981     if (!(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
6982             || (target->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
6983     {
6984         WARN("Surface %p is not a render target.\n", target);
6985         return DDERR_INVALIDCAPS;
6986     }
6987 
6988     if (!validate_surface_palette(target))
6989     {
6990         WARN("Surface %p has an indexed pixel format, but no palette.\n", target);
6991         return DDERR_NOPALETTEATTACHED;
6992     }
6993 
6994     if (hw && !(target->surface_desc.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY))
6995     {
6996         WARN("Surface %p is not in video memory.\n", target);
6997         return D3DERR_SURFACENOTINVIDMEM;
6998     }
6999 
7000     if (ddraw->flags & DDRAW_NO3D)
7001     {
7002         ERR_(winediag)("The application wants to create a Direct3D device, "
7003                 "but the current DirectDrawRenderer does not support this.\n");
7004 
7005         return DDERR_NO3D;
7006     }
7007 
7008     if (ddraw->d3ddevice)
7009     {
7010         FIXME("Only one Direct3D device per DirectDraw object supported.\n");
7011         return DDERR_INVALIDPARAMS;
7012     }
7013 
7014     if (!(object = heap_alloc_zero(sizeof(*object))))
7015     {
7016         ERR("Failed to allocate device memory.\n");
7017         return DDERR_OUTOFMEMORY;
7018     }
7019 
7020     if (FAILED(hr = d3d_device_init(object, ddraw, hw, target, rt_iface, version, outer_unknown)))
7021     {
7022         WARN("Failed to initialize device, hr %#x.\n", hr);
7023         heap_free(object);
7024         return hr;
7025     }
7026 
7027     TRACE("Created device %p.\n", object);
7028     *device = object;
7029 
7030     return D3D_OK;
7031 }
7032