~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ddraw/device.c

Version: ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Copyright (c) 1998-2004 Lionel Ulmer
  3  * Copyright (c) 2002-2005 Christian Costa
  4  * Copyright (c) 2006 Stefan Dösinger
  5  * Copyright (c) 2008 Alexander Dorofeyev
  6  *
  7  * This library is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU Lesser General Public
  9  * License as published by the Free Software Foundation; either
 10  * version 2.1 of the License, or (at your option) any later version.
 11  *
 12  * This library is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15  * Lesser General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public
 18  * License along with this library; if not, write to the Free Software
 19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 20  *
 21  * IDirect3DDevice implementation, version 1, 2, 3 and 7. Rendering is relayed
 22  * to WineD3D, some minimal DirectDraw specific management is handled here.
 23  * The Direct3DDevice is NOT the parent of the WineD3DDevice, because d3d
 24  * is initialized when DirectDraw creates the primary surface.
 25  * Some type management is necessary, because some D3D types changed between
 26  * D3D7 and D3D9.
 27  *
 28  */
 29 
 30 #include "config.h"
 31 #include "wine/port.h"
 32 
 33 #include <assert.h>
 34 #include <stdarg.h>
 35 #include <string.h>
 36 #include <stdlib.h>
 37 
 38 #define COBJMACROS
 39 #define NONAMELESSUNION
 40 
 41 #include "windef.h"
 42 #include "winbase.h"
 43 #include "winerror.h"
 44 #include "wingdi.h"
 45 #include "wine/exception.h"
 46 
 47 #include "ddraw.h"
 48 #include "d3d.h"
 49 
 50 #include "ddraw_private.h"
 51 #include "wine/debug.h"
 52 
 53 WINE_DEFAULT_DEBUG_CHANNEL(d3d7);
 54 WINE_DECLARE_DEBUG_CHANNEL(ddraw_thunk);
 55 
 56 /* The device ID */
 57 const GUID IID_D3DDEVICE_WineD3D = {
 58   0xaef72d43,
 59   0xb09a,
 60   0x4b7b,
 61   { 0xb7,0x98,0xc6,0x8a,0x77,0x2d,0x72,0x2a }
 62 };
 63 
 64 static inline void set_fpu_control_word(WORD fpucw)
 65 {
 66 #if defined(__i386__) && defined(__GNUC__)
 67     __asm__ volatile ("fldcw %0" : : "m" (fpucw));
 68 #elif defined(__i386__) && defined(_MSC_VER)
 69     __asm fldcw fpucw;
 70 #endif
 71 }
 72 
 73 static inline WORD d3d_fpu_setup(void)
 74 {
 75     WORD oldcw;
 76 
 77 #if defined(__i386__) && defined(__GNUC__)
 78     __asm__ volatile ("fnstcw %0" : "=m" (oldcw));
 79 #elif defined(__i386__) && defined(_MSC_VER)
 80     __asm fnstcw oldcw;
 81 #else
 82     static BOOL warned = FALSE;
 83     if(!warned)
 84     {
 85         FIXME("FPUPRESERVE not implemented for this platform / compiler\n");
 86         warned = TRUE;
 87     }
 88 #endif
 89 
 90     set_fpu_control_word(0x37f);
 91 
 92     return oldcw;
 93 }
 94 
 95 /*****************************************************************************
 96  * IUnknown Methods. Common for Version 1, 2, 3 and 7 
 97  *****************************************************************************/
 98 
 99 /*****************************************************************************
100  * IDirect3DDevice7::QueryInterface
101  *
102  * Used to query other interfaces from a Direct3DDevice interface.
103  * It can return interface pointers to all Direct3DDevice versions as well
104  * as IDirectDraw and IDirect3D. For a link to QueryInterface
105  * rules see ddraw.c, IDirectDraw7::QueryInterface
106  *
107  * Exists in Version 1, 2, 3 and 7
108  *
109  * Params:
110  *  refiid: Interface ID queried for
111  *  obj: Used to return the interface pointer
112  *
113  * Returns:
114  *  D3D_OK or E_NOINTERFACE
115  *
116  *****************************************************************************/
117 static HRESULT WINAPI
118 IDirect3DDeviceImpl_7_QueryInterface(IDirect3DDevice7 *iface,
119                                      REFIID refiid,
120                                      void **obj)
121 {
122     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
123     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
124 
125     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
126     *obj = NULL;
127 
128     if(!refiid)
129         return DDERR_INVALIDPARAMS;
130 
131     if ( IsEqualGUID( &IID_IUnknown, refiid ) )
132     {
133         *obj = ICOM_INTERFACE(This, IDirect3DDevice7);
134     }
135 
136     /* Check DirectDraw Interfacs */
137     else if( IsEqualGUID( &IID_IDirectDraw7, refiid ) )
138     {
139         *obj = ICOM_INTERFACE(This->ddraw, IDirectDraw7);
140         TRACE("(%p) Returning IDirectDraw7 interface at %p\n", This, *obj);
141     }
142     else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
143     {
144         *obj = ICOM_INTERFACE(This->ddraw, IDirectDraw4);
145         TRACE("(%p) Returning IDirectDraw4 interface at %p\n", This, *obj);
146     }
147     else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
148     {
149         *obj = ICOM_INTERFACE(This->ddraw, IDirectDraw2);
150         TRACE("(%p) Returning IDirectDraw2 interface at %p\n", This, *obj);
151     }
152     else if( IsEqualGUID( &IID_IDirectDraw, refiid ) )
153     {
154         *obj = ICOM_INTERFACE(This->ddraw, IDirectDraw);
155         TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
156     }
157 
158     /* Direct3D */
159     else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) )
160     {
161         *obj = ICOM_INTERFACE(This->ddraw, IDirect3D);
162         TRACE("(%p) Returning IDirect3D interface at %p\n", This, *obj);
163     }
164     else if ( IsEqualGUID( &IID_IDirect3D2 , refiid ) )
165     {
166         *obj = ICOM_INTERFACE(This->ddraw, IDirect3D2);
167         TRACE("(%p) Returning IDirect3D2 interface at %p\n", This, *obj);
168     }
169     else if ( IsEqualGUID( &IID_IDirect3D3 , refiid ) )
170     {
171         *obj = ICOM_INTERFACE(This->ddraw, IDirect3D3);
172         TRACE("(%p) Returning IDirect3D3 interface at %p\n", This, *obj);
173     }
174     else if ( IsEqualGUID( &IID_IDirect3D7 , refiid ) )
175     {
176         *obj = ICOM_INTERFACE(This->ddraw, IDirect3D7);
177         TRACE("(%p) Returning IDirect3D7 interface at %p\n", This, *obj);
178     }
179 
180     /* Direct3DDevice */
181     else if ( IsEqualGUID( &IID_IDirect3DDevice  , refiid ) )
182     {
183         *obj = ICOM_INTERFACE(This, IDirect3DDevice);
184         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
185     }
186     else if ( IsEqualGUID( &IID_IDirect3DDevice2  , refiid ) ) {
187         *obj = ICOM_INTERFACE(This, IDirect3DDevice2);
188         TRACE("(%p) Returning IDirect3DDevice2 interface at %p\n", This, *obj);
189     }
190     else if ( IsEqualGUID( &IID_IDirect3DDevice3  , refiid ) ) {
191         *obj = ICOM_INTERFACE(This, IDirect3DDevice3);
192         TRACE("(%p) Returning IDirect3DDevice3 interface at %p\n", This, *obj);
193     }
194     else if ( IsEqualGUID( &IID_IDirect3DDevice7  , refiid ) ) {
195         *obj = ICOM_INTERFACE(This, IDirect3DDevice7);
196         TRACE("(%p) Returning IDirect3DDevice7 interface at %p\n", This, *obj);
197     }
198 
199     /* Unknown interface */
200     else
201     {
202         ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
203         return E_NOINTERFACE;
204     }
205 
206     /* AddRef the returned interface */
207     IUnknown_AddRef( (IUnknown *) *obj);
208     return D3D_OK;
209 }
210 
211 static HRESULT WINAPI
212 Thunk_IDirect3DDeviceImpl_3_QueryInterface(IDirect3DDevice3 *iface,
213                                            REFIID riid,
214                                            void **obj)
215 {
216     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
217     TRACE_(ddraw_thunk)("(%p)->(%s,%p) thunking to IDirect3DDevice7 interface.\n", This, debugstr_guid(riid), obj);
218     return IDirect3DDevice7_QueryInterface(ICOM_INTERFACE(This, IDirect3DDevice7),
219                                            riid,
220                                            obj);
221 }
222 
223 static HRESULT WINAPI
224 Thunk_IDirect3DDeviceImpl_2_QueryInterface(IDirect3DDevice2 *iface,
225                                            REFIID riid,
226                                            void **obj)
227 {
228     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
229     TRACE_(ddraw_thunk)("(%p)->(%s,%p) thunking to IDirect3DDevice7 interface.\n", This, debugstr_guid(riid), obj);
230     return IDirect3DDevice7_QueryInterface(ICOM_INTERFACE(This, IDirect3DDevice7),
231                                            riid,
232                                            obj);
233 }
234 
235 static HRESULT WINAPI
236 Thunk_IDirect3DDeviceImpl_1_QueryInterface(IDirect3DDevice *iface,
237                                            REFIID riid,
238                                            void **obp)
239 {
240     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
241     TRACE_(ddraw_thunk)("(%p)->(%s,%p) thunking to IDirect3DDevice7 interface.\n", This, debugstr_guid(riid), obp);
242     return IDirect3DDevice7_QueryInterface(ICOM_INTERFACE(This, IDirect3DDevice7),
243                                            riid,
244                                            obp);
245 }
246 
247 /*****************************************************************************
248  * IDirect3DDevice7::AddRef
249  *
250  * Increases the refcount....
251  * The most exciting Method, definitely
252  *
253  * Exists in Version 1, 2, 3 and 7
254  *
255  * Returns:
256  *  The new refcount
257  *
258  *****************************************************************************/
259 static ULONG WINAPI
260 IDirect3DDeviceImpl_7_AddRef(IDirect3DDevice7 *iface)
261 {
262     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
263     ULONG ref = InterlockedIncrement(&This->ref);
264 
265     TRACE("(%p) : incrementing from %u.\n", This, ref -1);
266 
267     return ref;
268 }
269 
270 static ULONG WINAPI
271 Thunk_IDirect3DDeviceImpl_3_AddRef(IDirect3DDevice3 *iface)
272 {
273     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
274     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DDevice7 interface.\n", This);
275     return IDirect3DDevice7_AddRef(ICOM_INTERFACE(This, IDirect3DDevice7));
276 }
277 
278 static ULONG WINAPI
279 Thunk_IDirect3DDeviceImpl_2_AddRef(IDirect3DDevice2 *iface)
280 {
281     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
282     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DDevice7 interface.\n", This);
283     return IDirect3DDevice7_AddRef(ICOM_INTERFACE(This, IDirect3DDevice7));
284 }
285 
286 static ULONG WINAPI
287 Thunk_IDirect3DDeviceImpl_1_AddRef(IDirect3DDevice *iface)
288 {
289     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DDevice7 interface.\n", iface);
290     return IDirect3DDevice7_AddRef(COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice, IDirect3DDevice7, iface));
291 }
292 
293 /*****************************************************************************
294  * IDirect3DDevice7::Release
295  *
296  * Decreases the refcount of the interface
297  * When the refcount is reduced to 0, the object is destroyed.
298  *
299  * Exists in Version 1, 2, 3 and 7
300  *
301  * Returns:d
302  *  The new refcount
303  *
304  *****************************************************************************/
305 static ULONG WINAPI
306 IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface)
307 {
308     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
309     ULONG ref = InterlockedDecrement(&This->ref);
310 
311     TRACE("(%p)->() decrementing from %u.\n", This, ref +1);
312 
313     /* This method doesn't destroy the WineD3DDevice, because it's still in use for
314      * 2D rendering. IDirectDrawSurface7::Release will destroy the WineD3DDevice
315      * when the render target is released
316      */
317     if (ref == 0)
318     {
319         IParent *IndexBufferParent;
320         DWORD i;
321 
322         EnterCriticalSection(&ddraw_cs);
323         /* Free the index buffer. */
324         IWineD3DDevice_SetIndices(This->wineD3DDevice, NULL);
325         IWineD3DIndexBuffer_GetParent(This->indexbuffer,
326                                       (IUnknown **) &IndexBufferParent);
327         IParent_Release(IndexBufferParent); /* Once for the getParent */
328         if( IParent_Release(IndexBufferParent) != 0)  /* And now to destroy it */
329         {
330             ERR(" (%p) Something is still holding the index buffer parent %p\n", This, IndexBufferParent);
331         }
332 
333         /* There is no need to unset the vertex buffer here, IWineD3DDevice_Uninit3D will do that when
334          * destroying the primary stateblock. If a vertex buffer is destroyed while it is bound
335          * IDirect3DVertexBuffer::Release will unset it.
336          */
337 
338         /* Restore the render targets */
339         if(This->OffScreenTarget)
340         {
341             WINED3DVIEWPORT vp;
342 
343             vp.X = 0;
344             vp.Y = 0;
345             vp.Width = This->ddraw->d3d_target->surface_desc.dwWidth;
346             vp.Height = This->ddraw->d3d_target->surface_desc.dwHeight;
347             vp.MinZ = 0.0;
348             vp.MaxZ = 1.0;
349             IWineD3DDevice_SetViewport(This->wineD3DDevice,
350                                        &vp);
351 
352             /* Set the device up to render to the front buffer since the back buffer will
353              * vanish soon.
354              */
355             IWineD3DDevice_SetRenderTarget(This->wineD3DDevice, 0,
356                                            This->ddraw->d3d_target->WineD3DSurface);
357             /* This->target is the offscreen target.
358              * This->ddraw->d3d_target is the target used by DDraw
359              */
360             TRACE("(%p) Release: Using %p as front buffer, %p as back buffer\n", This, This->ddraw->d3d_target, NULL);
361             IWineD3DDevice_SetFrontBackBuffers(This->wineD3DDevice,
362                                                This->ddraw->d3d_target->WineD3DSurface,
363                                                NULL);
364         }
365 
366         /* Release the WineD3DDevice. This won't destroy it */
367         if(IWineD3DDevice_Release(This->wineD3DDevice) <= 0)
368         {
369             ERR(" (%p) The wineD3D device %p was destroyed unexpectedly. Prepare for trouble\n", This, This->wineD3DDevice);
370         }
371 
372         /* The texture handles should be unset by now, but there might be some bits
373          * missing in our reference counting(needs test). Do a sanity check
374          */
375         for(i = 0; i < This->numHandles; i++)
376         {
377             if(This->Handles[i].ptr)
378             {
379                 switch(This->Handles[i].type)
380                 {
381                     case DDrawHandle_Texture:
382                     {
383                         IDirectDrawSurfaceImpl *surf = (IDirectDrawSurfaceImpl *) This->Handles[i].ptr;
384                         FIXME("Texture Handle %d not unset properly\n", i + 1);
385                         surf->Handle = 0;
386                     }
387                     break;
388 
389                     case DDrawHandle_Material:
390                     {
391                         IDirect3DMaterialImpl *mat = (IDirect3DMaterialImpl *) This->Handles[i].ptr;
392                         FIXME("Material handle %d not unset properly\n", i + 1);
393                         mat->Handle = 0;
394                     }
395                     break;
396 
397                     case DDrawHandle_Matrix:
398                     {
399                         /* No fixme here because this might happen because of sloppy apps */
400                         WARN("Leftover matrix handle %d, deleting\n", i + 1);
401                         IDirect3DDevice_DeleteMatrix(ICOM_INTERFACE(This, IDirect3DDevice),
402                                                      i + 1);
403                     }
404                     break;
405 
406                     case DDrawHandle_StateBlock:
407                     {
408                         /* No fixme here because this might happen because of sloppy apps */
409                         WARN("Leftover stateblock handle %d, deleting\n", i + 1);
410                         IDirect3DDevice7_DeleteStateBlock(ICOM_INTERFACE(This, IDirect3DDevice7),
411                                                           i + 1);
412                     }
413                     break;
414 
415                     default:
416                         FIXME("Unknown handle %d not unset properly\n", i + 1);
417                 }
418             }
419         }
420 
421         HeapFree(GetProcessHeap(), 0, This->Handles);
422 
423         TRACE("Releasing target %p %p\n", This->target, This->ddraw->d3d_target);
424         /* Release the render target and the WineD3D render target
425          * (See IDirect3D7::CreateDevice for more comments on this)
426          */
427         IDirectDrawSurface7_Release(ICOM_INTERFACE(This->target, IDirectDrawSurface7));
428         IDirectDrawSurface7_Release(ICOM_INTERFACE(This->ddraw->d3d_target,IDirectDrawSurface7));
429         TRACE("Target release done\n");
430 
431         This->ddraw->d3ddevice = NULL;
432 
433         /* Now free the structure */
434         HeapFree(GetProcessHeap(), 0, This);
435         LeaveCriticalSection(&ddraw_cs);
436     }
437 
438     TRACE("Done\n");
439     return ref;
440 }
441 
442 static ULONG WINAPI
443 Thunk_IDirect3DDeviceImpl_3_Release(IDirect3DDevice3 *iface)
444 {
445     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
446     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DDevice7 interface.\n", This);
447     return IDirect3DDevice7_Release(ICOM_INTERFACE(This, IDirect3DDevice7));
448 }
449 
450 static ULONG WINAPI
451 Thunk_IDirect3DDeviceImpl_2_Release(IDirect3DDevice2 *iface)
452 {
453     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
454     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DDevice7 interface.\n", This);
455     return IDirect3DDevice7_Release(ICOM_INTERFACE(This, IDirect3DDevice7));
456 }
457 
458 static ULONG WINAPI
459 Thunk_IDirect3DDeviceImpl_1_Release(IDirect3DDevice *iface)
460 {
461     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
462     TRACE_(ddraw_thunk)("(%p)->() thunking to IDirect3DDevice7 interface.\n", This);
463     return IDirect3DDevice7_Release(ICOM_INTERFACE(This, IDirect3DDevice7));
464 }
465 
466 /*****************************************************************************
467  * IDirect3DDevice Methods
468  *****************************************************************************/
469 
470 /*****************************************************************************
471  * IDirect3DDevice::Initialize
472  *
473  * Initializes a Direct3DDevice. This implementation is a no-op, as all
474  * initialization is done at create time.
475  *
476  * Exists in Version 1
477  *
478  * Parameters:
479  *  No idea what they mean, as the MSDN page is gone
480  *
481  * Returns: DD_OK
482  *
483  *****************************************************************************/
484 static HRESULT WINAPI
485 IDirect3DDeviceImpl_1_Initialize(IDirect3DDevice *iface,
486                                  IDirect3D *Direct3D, GUID *guid,
487                                  D3DDEVICEDESC *Desc)
488 {
489     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
490 
491     /* It shouldn't be crucial, but print a FIXME, I'm interested if
492      * any game calls it and when
493      */
494     FIXME("(%p)->(%p,%p,%p): No-op!\n", This, Direct3D, guid, Desc);
495 
496     return D3D_OK;
497 }
498 
499 /*****************************************************************************
500  * IDirect3DDevice7::GetCaps
501  *
502  * Retrieves the device's capabilities
503  *
504  * This implementation is used for Version 7 only, the older versions have
505  * their own implementation.
506  *
507  * Parameters:
508  *  Desc: Pointer to a D3DDEVICEDESC7 structure to fill
509  *
510  * Returns:
511  *  D3D_OK on success
512  *  D3DERR_* if a problem occurs. See WineD3D
513  *
514  *****************************************************************************/
515 static HRESULT
516 IDirect3DDeviceImpl_7_GetCaps(IDirect3DDevice7 *iface,
517                               D3DDEVICEDESC7 *Desc)
518 {
519     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface);
520     D3DDEVICEDESC OldDesc;
521     TRACE("(%p)->(%p)\n", This, Desc);
522 
523     /* Call the same function used by IDirect3D, this saves code */
524     return IDirect3DImpl_GetCaps(This->ddraw->wineD3D, &OldDesc, Desc);
525 }
526 
527 static HRESULT WINAPI
528 IDirect3DDeviceImpl_7_GetCaps_FPUSetup(IDirect3DDevice7 *iface,
529                               D3DDEVICEDESC7 *Desc)
530 {
531     return IDirect3DDeviceImpl_7_GetCaps(iface, Desc);
532 }
533 
534 static HRESULT WINAPI
535 IDirect3DDeviceImpl_7_GetCaps_FPUPreserve(IDirect3DDevice7 *iface,
536                               D3DDEVICEDESC7 *Desc)
537 {
538     HRESULT hr;
539     WORD old_fpucw;
540 
541     old_fpucw = d3d_fpu_setup();
542     hr = IDirect3DDeviceImpl_7_GetCaps(iface, Desc);
543     set_fpu_control_word(old_fpucw);
544 
545     return hr;
546 }
547 /*****************************************************************************
548  * IDirect3DDevice3::GetCaps
549  *
550  * Retrieves the capabilities of the hardware device and the emulation
551  * device. For Wine, hardware and emulation are the same (it's all HW).
552  *
553  * This implementation is used for Version 1, 2, and 3. Version 7 has its own
554  *
555  * Parameters:
556  *  HWDesc: Structure to fill with the HW caps
557  *  HelDesc: Structure to fill with the hardware emulation caps
558  *
559  * Returns:
560  *  D3D_OK on success
561  *  D3DERR_* if a problem occurs. See WineD3D
562  *
563  *****************************************************************************/
564 static HRESULT WINAPI
565 IDirect3DDeviceImpl_3_GetCaps(IDirect3DDevice3 *iface,
566                               D3DDEVICEDESC *HWDesc,
567                               D3DDEVICEDESC *HelDesc)
568 {
569     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
570     D3DDEVICEDESC7 newDesc;
571     HRESULT hr;
572     TRACE("(%p)->(%p,%p)\n", iface, HWDesc, HelDesc);
573 
574     hr = IDirect3DImpl_GetCaps(This->ddraw->wineD3D, HWDesc, &newDesc);
575     if(hr != D3D_OK) return hr;
576 
577     *HelDesc = *HWDesc;
578     return D3D_OK;
579 }
580 
581 static HRESULT WINAPI
582 Thunk_IDirect3DDeviceImpl_2_GetCaps(IDirect3DDevice2 *iface,
583                                     D3DDEVICEDESC *D3DHWDevDesc,
584                                     D3DDEVICEDESC *D3DHELDevDesc)
585 {
586     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
587     TRACE_(ddraw_thunk)("(%p)->(%p,%p) thunking to IDirect3DDevice3 interface.\n", This, D3DHWDevDesc, D3DHELDevDesc);
588     return IDirect3DDevice3_GetCaps(ICOM_INTERFACE(This, IDirect3DDevice3),
589                                     D3DHWDevDesc,
590                                     D3DHELDevDesc);
591 }
592 
593 static HRESULT WINAPI
594 Thunk_IDirect3DDeviceImpl_1_GetCaps(IDirect3DDevice *iface,
595                                     D3DDEVICEDESC *D3DHWDevDesc,
596                                     D3DDEVICEDESC *D3DHELDevDesc)
597 {
598     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
599     TRACE_(ddraw_thunk)("(%p)->(%p,%p) thunking to IDirect3DDevice3 interface.\n", This, D3DHWDevDesc, D3DHELDevDesc);
600     return IDirect3DDevice3_GetCaps(ICOM_INTERFACE(This, IDirect3DDevice3),
601                                     D3DHWDevDesc,
602                                     D3DHELDevDesc);
603 }
604 
605 /*****************************************************************************
606  * IDirect3DDevice2::SwapTextureHandles
607  *
608  * Swaps the texture handles of 2 Texture interfaces. Version 1 and 2
609  *
610  * Parameters:
611  *  Tex1, Tex2: The 2 Textures to swap
612  *
613  * Returns:
614  *  D3D_OK
615  *
616  *****************************************************************************/
617 static HRESULT WINAPI
618 IDirect3DDeviceImpl_2_SwapTextureHandles(IDirect3DDevice2 *iface,
619                                          IDirect3DTexture2 *Tex1,
620                                          IDirect3DTexture2 *Tex2)
621 {
622     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
623     DWORD swap;
624     IDirectDrawSurfaceImpl *surf1 = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, Tex1);
625     IDirectDrawSurfaceImpl *surf2 = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, Tex2);
626     TRACE("(%p)->(%p,%p)\n", This, surf1, surf2);
627 
628     EnterCriticalSection(&ddraw_cs);
629     This->Handles[surf1->Handle - 1].ptr = surf2;
630     This->Handles[surf2->Handle - 1].ptr = surf1;
631 
632     swap = surf2->Handle;
633     surf2->Handle = surf1->Handle;
634     surf1->Handle = swap;
635     LeaveCriticalSection(&ddraw_cs);
636 
637     return D3D_OK;
638 }
639 
640 static HRESULT WINAPI
641 Thunk_IDirect3DDeviceImpl_1_SwapTextureHandles(IDirect3DDevice *iface,
642                                                IDirect3DTexture *D3DTex1,
643                                                IDirect3DTexture *D3DTex2)
644 {
645     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
646     IDirectDrawSurfaceImpl *surf1 = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture, D3DTex1);
647     IDirectDrawSurfaceImpl *surf2 = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture, D3DTex2);
648     TRACE_(ddraw_thunk)("(%p)->(%p,%p) thunking to IDirect3DDevice2 interface.\n", This, surf1, surf2);
649     return IDirect3DDevice2_SwapTextureHandles(ICOM_INTERFACE(This, IDirect3DDevice2),
650                                                ICOM_INTERFACE(surf1, IDirect3DTexture2),
651                                                ICOM_INTERFACE(surf2, IDirect3DTexture2));
652 }
653 
654 /*****************************************************************************
655  * IDirect3DDevice3::GetStats
656  *
657  * This method seems to retrieve some stats from the device.
658  * The MSDN documentation doesn't exist any more, but the D3DSTATS
659  * structure suggests that the amount of drawn primitives and processed
660  * vertices is returned.
661  *
662  * Exists in Version 1, 2 and 3
663  *
664  * Parameters:
665  *  Stats: Pointer to a D3DSTATS structure to be filled
666  *
667  * Returns:
668  *  D3D_OK on success
669  *  DDERR_INVALIDPARAMS if Stats == NULL
670  *
671  *****************************************************************************/
672 static HRESULT WINAPI
673 IDirect3DDeviceImpl_3_GetStats(IDirect3DDevice3 *iface,
674                                D3DSTATS *Stats)
675 {
676     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
677     FIXME("(%p)->(%p): Stub!\n", This, Stats);
678 
679     if(!Stats)
680         return DDERR_INVALIDPARAMS;
681 
682     /* Fill the Stats with 0 */
683     Stats->dwTrianglesDrawn = 0;
684     Stats->dwLinesDrawn = 0;
685     Stats->dwPointsDrawn = 0;
686     Stats->dwSpansDrawn = 0;
687     Stats->dwVerticesProcessed = 0;
688 
689     return D3D_OK;
690 }
691 
692 static HRESULT WINAPI
693 Thunk_IDirect3DDeviceImpl_2_GetStats(IDirect3DDevice2 *iface,
694                                      D3DSTATS *Stats)
695 {
696     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
697     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice3 interface.\n", This, Stats);
698     return IDirect3DDevice3_GetStats(ICOM_INTERFACE(This, IDirect3DDevice3),
699                                      Stats);
700 }
701 
702 static HRESULT WINAPI
703 Thunk_IDirect3DDeviceImpl_1_GetStats(IDirect3DDevice *iface,
704                                      D3DSTATS *Stats)
705 {
706     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
707     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice3 interface.\n", This, Stats);
708     return IDirect3DDevice3_GetStats(ICOM_INTERFACE(This, IDirect3DDevice3),
709                                      Stats);
710 }
711 
712 /*****************************************************************************
713  * IDirect3DDevice::CreateExecuteBuffer
714  *
715  * Creates an IDirect3DExecuteBuffer, used for rendering with a
716  * Direct3DDevice.
717  *
718  * Version 1 only.
719  *
720  * Params:
721  *  Desc: Buffer description
722  *  ExecuteBuffer: Address to return the Interface pointer at
723  *  UnkOuter: Must be NULL. Basically for aggregation, which ddraw doesn't
724  *            support
725  *
726  * Returns:
727  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
728  *  DDERR_OUTOFMEMORY if we ran out of memory
729  *  D3D_OK on success
730  *
731  *****************************************************************************/
732 static HRESULT WINAPI
733 IDirect3DDeviceImpl_1_CreateExecuteBuffer(IDirect3DDevice *iface,
734                                           D3DEXECUTEBUFFERDESC *Desc,
735                                           IDirect3DExecuteBuffer **ExecuteBuffer,
736                                           IUnknown *UnkOuter)
737 {
738     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
739     IDirect3DExecuteBufferImpl* object;
740     TRACE("(%p)->(%p,%p,%p)!\n", This, Desc, ExecuteBuffer, UnkOuter);
741 
742     if(UnkOuter)
743         return CLASS_E_NOAGGREGATION;
744 
745     /* Allocate the new Execute Buffer */
746     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DExecuteBufferImpl));
747     if(!object)
748     {
749         ERR("Out of memory when allocating a IDirect3DExecuteBufferImpl structure\n");
750         return DDERR_OUTOFMEMORY;
751     }
752 
753     ICOM_INIT_INTERFACE(object, IDirect3DExecuteBuffer, IDirect3DExecuteBuffer_Vtbl);
754 
755     object->ref = 1;
756     object->d3ddev = This;
757 
758     /* Initializes memory */
759     memcpy(&object->desc, Desc, Desc->dwSize);
760 
761     /* No buffer given */
762     if ((object->desc.dwFlags & D3DDEB_LPDATA) == 0)
763         object->desc.lpData = NULL;
764 
765     /* No buffer size given */
766     if ((object->desc.dwFlags & D3DDEB_BUFSIZE) == 0)
767         object->desc.dwBufferSize = 0;
768 
769     /* Create buffer if asked */
770     if ((object->desc.lpData == NULL) && (object->desc.dwBufferSize > 0))
771     {
772         object->need_free = TRUE;
773         object->desc.lpData = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,object->desc.dwBufferSize);
774         if(!object->desc.lpData)
775         {
776             ERR("Out of memory when allocating the execute buffer data\n");
777             HeapFree(GetProcessHeap(), 0, object);
778             return DDERR_OUTOFMEMORY;
779         }
780     }
781     else
782     {
783         object->need_free = FALSE;
784     }
785 
786     /* No vertices for the moment */
787     object->vertex_data = NULL;
788 
789     object->desc.dwFlags |= D3DDEB_LPDATA;
790 
791     object->indices = NULL;
792     object->nb_indices = 0;
793 
794     *ExecuteBuffer = ICOM_INTERFACE(object, IDirect3DExecuteBuffer);
795 
796     TRACE(" Returning IDirect3DExecuteBuffer at %p, implementation is at %p\n", *ExecuteBuffer, object);
797 
798     return D3D_OK;
799 }
800 
801 /*****************************************************************************
802  * IDirect3DDevice::Execute
803  *
804  * Executes all the stuff in an execute buffer.
805  *
806  * Params:
807  *  ExecuteBuffer: The buffer to execute
808  *  Viewport: The viewport used for rendering
809  *  Flags: Some flags
810  *
811  * Returns:
812  *  DDERR_INVALIDPARAMS if ExecuteBuffer == NULL
813  *  D3D_OK on success
814  *
815  *****************************************************************************/
816 static HRESULT WINAPI
817 IDirect3DDeviceImpl_1_Execute(IDirect3DDevice *iface,
818                               IDirect3DExecuteBuffer *ExecuteBuffer,
819                               IDirect3DViewport *Viewport,
820                               DWORD Flags)
821 {
822     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
823     IDirect3DExecuteBufferImpl *Direct3DExecuteBufferImpl = ICOM_OBJECT(IDirect3DExecuteBufferImpl, IDirect3DExecuteBuffer, ExecuteBuffer);
824     IDirect3DViewportImpl *Direct3DViewportImpl = ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, Viewport);
825 
826     TRACE("(%p)->(%p,%p,%08x)\n", This, Direct3DExecuteBufferImpl, Direct3DViewportImpl, Flags);
827 
828     if(!Direct3DExecuteBufferImpl)
829         return DDERR_INVALIDPARAMS;
830 
831     /* Execute... */
832     EnterCriticalSection(&ddraw_cs);
833     IDirect3DExecuteBufferImpl_Execute(Direct3DExecuteBufferImpl, This, Direct3DViewportImpl);
834     LeaveCriticalSection(&ddraw_cs);
835 
836     return D3D_OK;
837 }
838 
839 /*****************************************************************************
840  * IDirect3DDevice3::AddViewport
841  *
842  * Add a Direct3DViewport to the device's viewport list. These viewports
843  * are wrapped to IDirect3DDevice7 viewports in viewport.c
844  *
845  * Exists in Version 1, 2 and 3. Note that IDirect3DViewport 1, 2 and 3
846  * are the same interfaces.
847  *
848  * Params:
849  *  Viewport: The viewport to add
850  *
851  * Returns:
852  *  DDERR_INVALIDPARAMS if Viewport == NULL
853  *  D3D_OK on success
854  *
855  *****************************************************************************/
856 static HRESULT WINAPI
857 IDirect3DDeviceImpl_3_AddViewport(IDirect3DDevice3 *iface,
858                                   IDirect3DViewport3 *Viewport)
859 {
860     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice3, iface);
861     IDirect3DViewportImpl *vp = ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, Viewport);
862 
863     TRACE("(%p)->(%p)\n", This, vp);
864 
865     /* Sanity check */
866     if(!vp)
867         return DDERR_INVALIDPARAMS;
868 
869     EnterCriticalSection(&ddraw_cs);
870     vp->next = This->viewport_list;
871     This->viewport_list = vp;
872     vp->active_device = This; /* Viewport must be usable for Clear() after AddViewport,
873                                     so set active_device here. */
874     LeaveCriticalSection(&ddraw_cs);
875 
876     return D3D_OK;
877 }
878 
879 static HRESULT WINAPI
880 Thunk_IDirect3DDeviceImpl_2_AddViewport(IDirect3DDevice2 *iface,
881                                         IDirect3DViewport2 *Direct3DViewport2)
882 {
883     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice2, iface);
884     IDirect3DViewportImpl *vp = ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, Direct3DViewport2);
885     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice3 interface.\n", This, vp);
886     return IDirect3DDevice3_AddViewport(ICOM_INTERFACE(This, IDirect3DDevice3),
887                                         ICOM_INTERFACE(vp, IDirect3DViewport3));
888 }
889 
890 static HRESULT WINAPI
891 Thunk_IDirect3DDeviceImpl_1_AddViewport(IDirect3DDevice *iface,
892                                         IDirect3DViewport *Direct3DViewport)
893 {
894     ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice, iface);
895     IDirect3DViewportImpl *vp = ICOM_OBJECT(IDirect3DViewportImpl, IDirect3DViewport3, Direct3DViewport);
896     TRACE_(ddraw_thunk)("(%p)->(%p) thunking to IDirect3DDevice3 interface.\n", This, vp);
897     return IDirect3DDevice3_AddViewport(ICOM_INTERFACE(This, IDirect3DDevice3),
898                                         ICOM_INTERFACE(vp, IDirect3DViewport3));
899 }
900 
901 /*****************************************************************************
902  * IDirect3DDevice3::DeleteViewport
903  *
904  * Deletes a Direct3DViewport from the device's viewport list.
905  *
906  * Exists in Version 1, 2 and 3. Note that all Viewport interface versions
907  * are equal.
908  *
909  * Params:
910  *  Viewport: The viewport to delete
911  *
912  * Returns:
913  *  D3D_OK on success
914  *  DDERR_INVALIDPARAMS if the viewport wasn't found in the list
915  *
916  *****************************************************************************/
917 static HRESULT WINAPI
918 IDirect3DDeviceImpl_3_DeleteViewport(IDirect3DDevice3 *iface,
919                                      IDirect3DViewport3 *Viewport)
920 {
921     ICOM_T