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