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