winegcc: Import kernel32 and ntdll by default also when building Wine.
[wine/multimedia.git] / dlls / ddraw / ddraw.c
blobe55ac5bbde8e5561b447a412d7ef18fa0f2b1418
1 /*
2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2006 Stefan Dösinger
6 * Copyright 2008 Denver Gingerich
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdlib.h>
31 #define COBJMACROS
32 #define NONAMELESSUNION
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "wingdi.h"
38 #include "wine/exception.h"
40 #include "ddraw.h"
41 #include "d3d.h"
43 #include "ddraw_private.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
48 /* Device identifier. Don't relay it to WineD3D */
49 static const DDDEVICEIDENTIFIER2 deviceidentifier =
51 "display",
52 "DirectDraw HAL",
53 { { 0x00010001, 0x00010001 } },
54 0, 0, 0, 0,
55 /* a8373c10-7ac4-4deb-849a-009844d08b2d */
56 {0xa8373c10,0x7ac4,0x4deb, {0x84,0x9a,0x00,0x98,0x44,0xd0,0x8b,0x2d}},
60 static void STDMETHODCALLTYPE ddraw_null_wined3d_object_destroyed(void *parent) {}
62 const struct wined3d_parent_ops ddraw_null_wined3d_parent_ops =
64 ddraw_null_wined3d_object_destroyed,
67 static inline IDirectDrawImpl *ddraw_from_ddraw1(IDirectDraw *iface)
69 return (IDirectDrawImpl *)((char*)iface - FIELD_OFFSET(IDirectDrawImpl, IDirectDraw_vtbl));
72 static inline IDirectDrawImpl *ddraw_from_ddraw2(IDirectDraw2 *iface)
74 return (IDirectDrawImpl *)((char*)iface - FIELD_OFFSET(IDirectDrawImpl, IDirectDraw2_vtbl));
77 static inline IDirectDrawImpl *ddraw_from_ddraw3(IDirectDraw3 *iface)
79 return (IDirectDrawImpl *)((char*)iface - FIELD_OFFSET(IDirectDrawImpl, IDirectDraw3_vtbl));
82 static inline IDirectDrawImpl *ddraw_from_ddraw4(IDirectDraw4 *iface)
84 return (IDirectDrawImpl *)((char*)iface - FIELD_OFFSET(IDirectDrawImpl, IDirectDraw4_vtbl));
87 /*****************************************************************************
88 * IUnknown Methods
89 *****************************************************************************/
91 /*****************************************************************************
92 * IDirectDraw7::QueryInterface
94 * Queries different interfaces of the DirectDraw object. It can return
95 * IDirectDraw interfaces in version 1, 2, 4 and 7, and IDirect3D interfaces
96 * in version 1, 2, 3 and 7. An IDirect3DDevice can be created with this
97 * method.
98 * The returned interface is AddRef()-ed before it's returned
100 * Used for version 1, 2, 4 and 7
102 * Params:
103 * refiid: Interface ID asked for
104 * obj: Used to return the interface pointer
106 * Returns:
107 * S_OK if an interface was found
108 * E_NOINTERFACE if the requested interface wasn't found
110 *****************************************************************************/
111 static HRESULT WINAPI ddraw7_QueryInterface(IDirectDraw7 *iface, REFIID refiid, void **obj)
113 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
115 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
117 /* Can change surface impl type */
118 EnterCriticalSection(&ddraw_cs);
120 /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
121 *obj = NULL;
123 if(!refiid)
125 LeaveCriticalSection(&ddraw_cs);
126 return DDERR_INVALIDPARAMS;
129 /* Check DirectDraw Interfaces */
130 if ( IsEqualGUID( &IID_IUnknown, refiid ) ||
131 IsEqualGUID( &IID_IDirectDraw7, refiid ) )
133 *obj = This;
134 TRACE("(%p) Returning IDirectDraw7 interface at %p\n", This, *obj);
136 else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
138 *obj = &This->IDirectDraw4_vtbl;
139 TRACE("(%p) Returning IDirectDraw4 interface at %p\n", This, *obj);
141 else if ( IsEqualGUID( &IID_IDirectDraw3, refiid ) )
143 /* This Interface exists in ddrawex.dll, it is implemented in a wrapper */
144 WARN("IDirectDraw3 is not valid in ddraw.dll\n");
145 *obj = NULL;
146 LeaveCriticalSection(&ddraw_cs);
147 return E_NOINTERFACE;
149 else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
151 *obj = &This->IDirectDraw2_vtbl;
152 TRACE("(%p) Returning IDirectDraw2 interface at %p\n", This, *obj);
154 else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
156 *obj = &This->IDirectDraw_vtbl;
157 TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
160 /* Direct3D
161 * The refcount unit test revealed that an IDirect3D7 interface can only be queried
162 * from a DirectDraw object that was created as an IDirectDraw7 interface. No idea
163 * who had this idea and why. The older interfaces can query and IDirect3D version
164 * because they are all created as IDirectDraw(1). This isn't really crucial behavior,
165 * and messy to implement with the common creation function, so it has been left out here.
167 else if ( IsEqualGUID( &IID_IDirect3D , refiid ) ||
168 IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
169 IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
170 IsEqualGUID( &IID_IDirect3D7 , refiid ) )
172 /* Check the surface implementation */
173 if(This->ImplType == SURFACE_UNKNOWN)
175 /* Apps may create the IDirect3D Interface before the primary surface.
176 * set the surface implementation */
177 This->ImplType = SURFACE_OPENGL;
178 TRACE("(%p) Choosing OpenGL surfaces because a Direct3D interface was requested\n", This);
180 else if(This->ImplType != SURFACE_OPENGL && DefaultSurfaceType == SURFACE_UNKNOWN)
182 ERR("(%p) The App is requesting a D3D device, but a non-OpenGL surface type was choosen. Prepare for trouble!\n", This);
183 ERR(" (%p) You may want to contact wine-devel for help\n", This);
184 /* Should I assert(0) here??? */
186 else if(This->ImplType != SURFACE_OPENGL)
188 WARN("The app requests a Direct3D interface, but non-opengl surfaces where set in winecfg\n");
189 /* Do not abort here, only reject 3D Device creation */
192 if ( IsEqualGUID( &IID_IDirect3D , refiid ) )
194 This->d3dversion = 1;
195 *obj = &This->IDirect3D_vtbl;
196 TRACE(" returning Direct3D interface at %p.\n", *obj);
198 else if ( IsEqualGUID( &IID_IDirect3D2 , refiid ) )
200 This->d3dversion = 2;
201 *obj = &This->IDirect3D2_vtbl;
202 TRACE(" returning Direct3D2 interface at %p.\n", *obj);
204 else if ( IsEqualGUID( &IID_IDirect3D3 , refiid ) )
206 This->d3dversion = 3;
207 *obj = &This->IDirect3D3_vtbl;
208 TRACE(" returning Direct3D3 interface at %p.\n", *obj);
210 else if(IsEqualGUID( &IID_IDirect3D7 , refiid ))
212 This->d3dversion = 7;
213 *obj = &This->IDirect3D7_vtbl;
214 TRACE(" returning Direct3D7 interface at %p.\n", *obj);
217 else if (IsEqualGUID(refiid, &IID_IWineD3DDeviceParent))
219 *obj = &This->device_parent_vtbl;
222 /* Unknown interface */
223 else
225 ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
226 LeaveCriticalSection(&ddraw_cs);
227 return E_NOINTERFACE;
230 IUnknown_AddRef( (IUnknown *) *obj );
231 LeaveCriticalSection(&ddraw_cs);
232 return S_OK;
235 static HRESULT WINAPI ddraw4_QueryInterface(IDirectDraw4 *iface, REFIID riid, void **object)
237 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
239 return ddraw7_QueryInterface((IDirectDraw7 *)ddraw_from_ddraw4(iface), riid, object);
242 static HRESULT WINAPI ddraw3_QueryInterface(IDirectDraw3 *iface, REFIID riid, void **object)
244 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
246 return ddraw7_QueryInterface((IDirectDraw7 *)ddraw_from_ddraw3(iface), riid, object);
249 static HRESULT WINAPI ddraw2_QueryInterface(IDirectDraw2 *iface, REFIID riid, void **object)
251 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
253 return ddraw7_QueryInterface((IDirectDraw7 *)ddraw_from_ddraw2(iface), riid, object);
256 static HRESULT WINAPI ddraw1_QueryInterface(IDirectDraw *iface, REFIID riid, void **object)
258 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
260 return ddraw7_QueryInterface((IDirectDraw7 *)ddraw_from_ddraw1(iface), riid, object);
263 /*****************************************************************************
264 * IDirectDraw7::AddRef
266 * Increases the interfaces refcount, basically
268 * DDraw refcounting is a bit tricky. The different DirectDraw interface
269 * versions have individual refcounts, but the IDirect3D interfaces do not.
270 * All interfaces are from one object, that means calling QueryInterface on an
271 * IDirectDraw7 interface for an IDirectDraw4 interface does not create a new
272 * IDirectDrawImpl object.
274 * That means all AddRef and Release implementations of IDirectDrawX work
275 * with their own counter, and IDirect3DX::AddRef thunk to IDirectDraw (1),
276 * except of IDirect3D7 which thunks to IDirectDraw7
278 * Returns: The new refcount
280 *****************************************************************************/
281 static ULONG WINAPI ddraw7_AddRef(IDirectDraw7 *iface)
283 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
284 ULONG ref = InterlockedIncrement(&This->ref7);
286 TRACE("(%p) : incrementing IDirectDraw7 refcount from %u.\n", This, ref -1);
288 if(ref == 1) InterlockedIncrement(&This->numIfaces);
290 return ref;
293 static ULONG WINAPI ddraw4_AddRef(IDirectDraw4 *iface)
295 IDirectDrawImpl *ddraw = ddraw_from_ddraw4(iface);
296 ULONG ref = InterlockedIncrement(&ddraw->ref4);
298 TRACE("%p increasing refcount to %u.\n", ddraw, ref);
300 if (ref == 1) InterlockedIncrement(&ddraw->numIfaces);
302 return ref;
305 static ULONG WINAPI ddraw3_AddRef(IDirectDraw3 *iface)
307 IDirectDrawImpl *ddraw = ddraw_from_ddraw3(iface);
308 ULONG ref = InterlockedIncrement(&ddraw->ref3);
310 TRACE("%p increasing refcount to %u.\n", ddraw, ref);
312 if (ref == 1) InterlockedIncrement(&ddraw->numIfaces);
314 return ref;
317 static ULONG WINAPI ddraw2_AddRef(IDirectDraw2 *iface)
319 IDirectDrawImpl *ddraw = ddraw_from_ddraw2(iface);
320 ULONG ref = InterlockedIncrement(&ddraw->ref2);
322 TRACE("%p increasing refcount to %u.\n", ddraw, ref);
324 if (ref == 1) InterlockedIncrement(&ddraw->numIfaces);
326 return ref;
329 static ULONG WINAPI ddraw1_AddRef(IDirectDraw *iface)
331 IDirectDrawImpl *ddraw = ddraw_from_ddraw1(iface);
332 ULONG ref = InterlockedIncrement(&ddraw->ref1);
334 TRACE("%p increasing refcount to %u.\n", ddraw, ref);
336 if (ref == 1) InterlockedIncrement(&ddraw->numIfaces);
338 return ref;
341 /*****************************************************************************
342 * ddraw_destroy
344 * Destroys a ddraw object if all refcounts are 0. This is to share code
345 * between the IDirectDrawX::Release functions
347 * Params:
348 * This: DirectDraw object to destroy
350 *****************************************************************************/
351 static void ddraw_destroy(IDirectDrawImpl *This)
353 IDirectDraw7_SetCooperativeLevel((IDirectDraw7 *)This, NULL, DDSCL_NORMAL);
354 IDirectDraw7_RestoreDisplayMode((IDirectDraw7 *)This);
356 /* Destroy the device window if we created one */
357 if(This->devicewindow != 0)
359 TRACE(" (%p) Destroying the device window %p\n", This, This->devicewindow);
360 DestroyWindow(This->devicewindow);
361 This->devicewindow = 0;
364 EnterCriticalSection(&ddraw_cs);
365 list_remove(&This->ddraw_list_entry);
366 LeaveCriticalSection(&ddraw_cs);
368 /* Release the attached WineD3D stuff */
369 IWineD3DDevice_Release(This->wineD3DDevice);
370 IWineD3D_Release(This->wineD3D);
372 /* Now free the object */
373 HeapFree(GetProcessHeap(), 0, This);
376 /*****************************************************************************
377 * IDirectDraw7::Release
379 * Decreases the refcount. If the refcount falls to 0, the object is destroyed
381 * Returns: The new refcount
382 *****************************************************************************/
383 static ULONG WINAPI ddraw7_Release(IDirectDraw7 *iface)
385 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
386 ULONG ref = InterlockedDecrement(&This->ref7);
388 TRACE("(%p)->() decrementing IDirectDraw7 refcount from %u.\n", This, ref +1);
390 if (!ref && !InterlockedDecrement(&This->numIfaces))
391 ddraw_destroy(This);
393 return ref;
396 static ULONG WINAPI ddraw4_Release(IDirectDraw4 *iface)
398 IDirectDrawImpl *ddraw = ddraw_from_ddraw4(iface);
399 ULONG ref = InterlockedDecrement(&ddraw->ref4);
401 TRACE("%p decreasing refcount to %u.\n", ddraw, ref);
403 if (!ref && !InterlockedDecrement(&ddraw->numIfaces))
404 ddraw_destroy(ddraw);
406 return ref;
409 static ULONG WINAPI ddraw3_Release(IDirectDraw3 *iface)
411 IDirectDrawImpl *ddraw = ddraw_from_ddraw3(iface);
412 ULONG ref = InterlockedDecrement(&ddraw->ref3);
414 TRACE("%p decreasing refcount to %u.\n", ddraw, ref);
416 if (!ref && !InterlockedDecrement(&ddraw->numIfaces))
417 ddraw_destroy(ddraw);
419 return ref;
422 static ULONG WINAPI ddraw2_Release(IDirectDraw2 *iface)
424 IDirectDrawImpl *ddraw = ddraw_from_ddraw2(iface);
425 ULONG ref = InterlockedDecrement(&ddraw->ref2);
427 TRACE("%p decreasing refcount to %u.\n", ddraw, ref);
429 if (!ref && !InterlockedDecrement(&ddraw->numIfaces))
430 ddraw_destroy(ddraw);
432 return ref;
435 static ULONG WINAPI ddraw1_Release(IDirectDraw *iface)
437 IDirectDrawImpl *ddraw = ddraw_from_ddraw1(iface);
438 ULONG ref = InterlockedDecrement(&ddraw->ref1);
440 TRACE("%p decreasing refcount to %u.\n", ddraw, ref);
442 if (!ref && !InterlockedDecrement(&ddraw->numIfaces))
443 ddraw_destroy(ddraw);
445 return ref;
448 /*****************************************************************************
449 * IDirectDraw methods
450 *****************************************************************************/
452 /*****************************************************************************
453 * IDirectDraw7::SetCooperativeLevel
455 * Sets the cooperative level for the DirectDraw object, and the window
456 * assigned to it. The cooperative level determines the general behavior
457 * of the DirectDraw application
459 * Warning: This is quite tricky, as it's not really documented which
460 * cooperative levels can be combined with each other. If a game fails
461 * after this function, try to check the cooperative levels passed on
462 * Windows, and if it returns something different.
464 * If you think that this function caused the failure because it writes a
465 * fixme, be sure to run again with a +ddraw trace.
467 * What is known about cooperative levels (See the ddraw modes test):
468 * DDSCL_EXCLUSIVE and DDSCL_FULLSCREEN must be used with each other
469 * DDSCL_NORMAL is not compatible with DDSCL_EXCLUSIVE or DDSCL_FULLSCREEN
470 * DDSCL_SETFOCUSWINDOW can be passed only in DDSCL_NORMAL mode, but after that
471 * DDSCL_FULLSCREEN can be activated
472 * DDSCL_SETFOCUSWINDOW may only be used with DDSCL_NOWINDOWCHANGES
474 * Handled flags: DDSCL_NORMAL, DDSCL_FULLSCREEN, DDSCL_EXCLUSIVE,
475 * DDSCL_SETFOCUSWINDOW (partially),
476 * DDSCL_MULTITHREADED (work in progress)
478 * Unhandled flags, which should be implemented
479 * DDSCL_SETDEVICEWINDOW: Sets a window specially used for rendering (I don't
480 * expect any difference to a normal window for wine)
481 * DDSCL_CREATEDEVICEWINDOW: Tells ddraw to create its own window for
482 * rendering (Possible test case: Half-Life)
484 * Unsure about these: DDSCL_FPUSETUP DDSCL_FPURESERVE
486 * These don't seem very important for wine:
487 * DDSCL_ALLOWREBOOT, DDSCL_NOWINDOWCHANGES, DDSCL_ALLOWMODEX
489 * Returns:
490 * DD_OK if the cooperative level was set successfully
491 * DDERR_INVALIDPARAMS if the passed cooperative level combination is invalid
492 * DDERR_HWNDALREADYSET if DDSCL_SETFOCUSWINDOW is passed in exclusive mode
493 * (Probably others too, have to investigate)
495 *****************************************************************************/
496 static HRESULT WINAPI ddraw7_SetCooperativeLevel(IDirectDraw7 *iface, HWND hwnd, DWORD cooplevel)
498 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
499 HWND window;
501 TRACE("(%p)->(%p,%08x)\n",This,hwnd,cooplevel);
502 DDRAW_dump_cooperativelevel(cooplevel);
504 EnterCriticalSection(&ddraw_cs);
506 /* Get the old window */
507 window = This->dest_window;
509 /* Tests suggest that we need one of them: */
510 if(!(cooplevel & (DDSCL_SETFOCUSWINDOW |
511 DDSCL_NORMAL |
512 DDSCL_EXCLUSIVE )))
514 TRACE("Incorrect cooplevel flags, returning DDERR_INVALIDPARAMS\n");
515 LeaveCriticalSection(&ddraw_cs);
516 return DDERR_INVALIDPARAMS;
519 /* Handle those levels first which set various hwnds */
520 if(cooplevel & DDSCL_SETFOCUSWINDOW)
522 /* This isn't compatible with a lot of flags */
523 if(cooplevel & ( DDSCL_MULTITHREADED |
524 DDSCL_FPUSETUP |
525 DDSCL_FPUPRESERVE |
526 DDSCL_ALLOWREBOOT |
527 DDSCL_ALLOWMODEX |
528 DDSCL_SETDEVICEWINDOW |
529 DDSCL_NORMAL |
530 DDSCL_EXCLUSIVE |
531 DDSCL_FULLSCREEN ) )
533 TRACE("Called with incompatible flags, returning DDERR_INVALIDPARAMS\n");
534 LeaveCriticalSection(&ddraw_cs);
535 return DDERR_INVALIDPARAMS;
537 else if( (This->cooperative_level & DDSCL_FULLSCREEN) && window)
539 TRACE("Setting DDSCL_SETFOCUSWINDOW with an already set window, returning DDERR_HWNDALREADYSET\n");
540 LeaveCriticalSection(&ddraw_cs);
541 return DDERR_HWNDALREADYSET;
544 This->focuswindow = hwnd;
545 /* Won't use the hwnd param for anything else */
546 hwnd = NULL;
548 /* Use the focus window for drawing too */
549 This->dest_window = This->focuswindow;
551 /* Destroy the device window, if we have one */
552 if(This->devicewindow)
554 DestroyWindow(This->devicewindow);
555 This->devicewindow = NULL;
558 /* DDSCL_NORMAL or DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE */
559 if(cooplevel & DDSCL_NORMAL)
561 /* Can't coexist with fullscreen or exclusive */
562 if(cooplevel & (DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) )
564 TRACE("(%p) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE\n", This);
565 LeaveCriticalSection(&ddraw_cs);
566 return DDERR_INVALIDPARAMS;
569 /* Switching from fullscreen? */
570 if(This->cooperative_level & DDSCL_FULLSCREEN)
572 This->cooperative_level &= ~DDSCL_FULLSCREEN;
573 This->cooperative_level &= ~DDSCL_EXCLUSIVE;
574 This->cooperative_level &= ~DDSCL_ALLOWMODEX;
576 IWineD3DDevice_ReleaseFocusWindow(This->wineD3DDevice);
579 /* Don't override focus windows or private device windows */
580 if( hwnd &&
581 !(This->focuswindow) &&
582 !(This->devicewindow) &&
583 (hwnd != window) )
585 This->dest_window = hwnd;
588 else if(cooplevel & DDSCL_FULLSCREEN)
590 /* Needs DDSCL_EXCLUSIVE */
591 if(!(cooplevel & DDSCL_EXCLUSIVE) )
593 TRACE("(%p) DDSCL_FULLSCREEN needs DDSCL_EXCLUSIVE\n", This);
594 LeaveCriticalSection(&ddraw_cs);
595 return DDERR_INVALIDPARAMS;
597 /* Need a HWND
598 if(hwnd == 0)
600 TRACE("(%p) DDSCL_FULLSCREEN needs a HWND\n", This);
601 return DDERR_INVALIDPARAMS;
605 This->cooperative_level &= ~DDSCL_NORMAL;
607 /* Don't override focus windows or private device windows */
608 if( hwnd &&
609 !(This->focuswindow) &&
610 !(This->devicewindow) &&
611 (hwnd != window) )
613 HRESULT hr = IWineD3DDevice_AcquireFocusWindow(This->wineD3DDevice, hwnd);
614 if (FAILED(hr))
616 ERR("Failed to acquire focus window, hr %#x.\n", hr);
617 LeaveCriticalSection(&ddraw_cs);
618 return hr;
620 This->dest_window = hwnd;
623 else if(cooplevel & DDSCL_EXCLUSIVE)
625 TRACE("(%p) DDSCL_EXCLUSIVE needs DDSCL_FULLSCREEN\n", This);
626 LeaveCriticalSection(&ddraw_cs);
627 return DDERR_INVALIDPARAMS;
630 if(cooplevel & DDSCL_CREATEDEVICEWINDOW)
632 /* Don't create a device window if a focus window is set */
633 if( !(This->focuswindow) )
635 HWND devicewindow = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "DDraw device window",
636 WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
637 NULL, NULL, NULL, NULL);
638 if (!devicewindow)
640 ERR("Failed to create window, last error %#x.\n", GetLastError());
641 LeaveCriticalSection(&ddraw_cs);
642 return E_FAIL;
645 ShowWindow(devicewindow, SW_SHOW); /* Just to be sure */
646 TRACE("(%p) Created a DDraw device window. HWND=%p\n", This, devicewindow);
648 This->devicewindow = devicewindow;
649 This->dest_window = devicewindow;
653 if(cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED))
655 /* Enable thread safety in wined3d */
656 IWineD3DDevice_SetMultithreaded(This->wineD3DDevice);
659 /* Unhandled flags */
660 if(cooplevel & DDSCL_ALLOWREBOOT)
661 WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This);
662 if(cooplevel & DDSCL_ALLOWMODEX)
663 WARN("(%p) Unhandled flag DDSCL_ALLOWMODEX, harmless\n", This);
664 if(cooplevel & DDSCL_FPUSETUP)
665 WARN("(%p) Unhandled flag DDSCL_FPUSETUP, harmless\n", This);
667 /* Store the cooperative_level */
668 This->cooperative_level |= cooplevel;
669 TRACE("SetCooperativeLevel retuning DD_OK\n");
670 LeaveCriticalSection(&ddraw_cs);
671 return DD_OK;
674 static HRESULT WINAPI ddraw4_SetCooperativeLevel(IDirectDraw4 *iface, HWND window, DWORD flags)
676 TRACE("iface %p, window %p, flags %#x.\n", iface, window, flags);
678 return ddraw7_SetCooperativeLevel((IDirectDraw7 *)ddraw_from_ddraw4(iface), window, flags);
681 static HRESULT WINAPI ddraw3_SetCooperativeLevel(IDirectDraw3 *iface, HWND window, DWORD flags)
683 TRACE("iface %p, window %p, flags %#x.\n", iface, window, flags);
685 return ddraw7_SetCooperativeLevel((IDirectDraw7 *)ddraw_from_ddraw3(iface), window, flags);
688 static HRESULT WINAPI ddraw2_SetCooperativeLevel(IDirectDraw2 *iface, HWND window, DWORD flags)
690 TRACE("iface %p, window %p, flags %#x.\n", iface, window, flags);
692 return ddraw7_SetCooperativeLevel((IDirectDraw7 *)ddraw_from_ddraw2(iface), window, flags);
695 static HRESULT WINAPI ddraw1_SetCooperativeLevel(IDirectDraw *iface, HWND window, DWORD flags)
697 TRACE("iface %p, window %p, flags %#x.\n", iface, window, flags);
699 return ddraw7_SetCooperativeLevel((IDirectDraw7 *)ddraw_from_ddraw1(iface), window, flags);
702 /*****************************************************************************
704 * Helper function for SetDisplayMode and RestoreDisplayMode
706 * Implements DirectDraw's SetDisplayMode, but ignores the value of
707 * ForceRefreshRate, since it is already handled by
708 * ddraw7_SetDisplayMode. RestoreDisplayMode can use this function
709 * without worrying that ForceRefreshRate will override the refresh rate. For
710 * argument and return value documentation, see
711 * ddraw7_SetDisplayMode.
713 *****************************************************************************/
714 static HRESULT ddraw_set_display_mode(IDirectDraw7 *iface, DWORD Width, DWORD Height,
715 DWORD BPP, DWORD RefreshRate, DWORD Flags)
717 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
718 WINED3DDISPLAYMODE Mode;
719 HRESULT hr;
720 TRACE("(%p)->(%d,%d,%d,%d,%x): Relay!\n", This, Width, Height, BPP, RefreshRate, Flags);
722 EnterCriticalSection(&ddraw_cs);
723 if( !Width || !Height )
725 ERR("Width=%d, Height=%d, what to do?\n", Width, Height);
726 /* It looks like Need for Speed Porsche Unleashed expects DD_OK here */
727 LeaveCriticalSection(&ddraw_cs);
728 return DD_OK;
731 /* Check the exclusive mode
732 if(!(This->cooperative_level & DDSCL_EXCLUSIVE))
733 return DDERR_NOEXCLUSIVEMODE;
734 * This is WRONG. Don't know if the SDK is completely
735 * wrong and if there are any conditions when DDERR_NOEXCLUSIVE
736 * is returned, but Half-Life 1.1.1.1 (Steam version)
737 * depends on this
740 Mode.Width = Width;
741 Mode.Height = Height;
742 Mode.RefreshRate = RefreshRate;
743 switch(BPP)
745 case 8: Mode.Format = WINED3DFMT_P8_UINT; break;
746 case 15: Mode.Format = WINED3DFMT_B5G5R5X1_UNORM; break;
747 case 16: Mode.Format = WINED3DFMT_B5G6R5_UNORM; break;
748 case 24: Mode.Format = WINED3DFMT_B8G8R8_UNORM; break;
749 case 32: Mode.Format = WINED3DFMT_B8G8R8X8_UNORM; break;
752 /* TODO: The possible return values from msdn suggest that
753 * the screen mode can't be changed if a surface is locked
754 * or some drawing is in progress
757 /* TODO: Lose the primary surface */
758 hr = IWineD3DDevice_SetDisplayMode(This->wineD3DDevice,
759 0, /* First swapchain */
760 &Mode);
761 LeaveCriticalSection(&ddraw_cs);
762 switch(hr)
764 case WINED3DERR_NOTAVAILABLE: return DDERR_UNSUPPORTED;
765 default: return hr;
769 /*****************************************************************************
770 * IDirectDraw7::SetDisplayMode
772 * Sets the display screen resolution, color depth and refresh frequency
773 * when in fullscreen mode (in theory).
774 * Possible return values listed in the SDK suggest that this method fails
775 * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets
776 * the display mode in DDSCL_NORMAL mode without an hwnd specified.
777 * It seems to be valid to pass 0 for With and Height, this has to be tested
778 * It could mean that the current video mode should be left as-is. (But why
779 * call it then?)
781 * Params:
782 * Height, Width: Screen dimension
783 * BPP: Color depth in Bits per pixel
784 * Refreshrate: Screen refresh rate
785 * Flags: Other stuff
787 * Returns
788 * DD_OK on success
790 *****************************************************************************/
791 static HRESULT WINAPI ddraw7_SetDisplayMode(IDirectDraw7 *iface, DWORD Width, DWORD Height,
792 DWORD BPP, DWORD RefreshRate, DWORD Flags)
794 if (force_refresh_rate != 0)
796 TRACE("ForceRefreshRate overriding passed-in refresh rate (%d Hz) to %d Hz\n", RefreshRate, force_refresh_rate);
797 RefreshRate = force_refresh_rate;
800 return ddraw_set_display_mode(iface, Width, Height, BPP, RefreshRate, Flags);
803 static HRESULT WINAPI ddraw4_SetDisplayMode(IDirectDraw4 *iface,
804 DWORD width, DWORD height, DWORD bpp, DWORD refresh_rate, DWORD flags)
806 TRACE("iface %p, width %u, height %u, bpp %u, refresh_rate %u, flags %#x.\n",
807 iface, width, height, bpp, refresh_rate, flags);
809 return ddraw7_SetDisplayMode((IDirectDraw7 *)ddraw_from_ddraw4(iface),
810 width, height, bpp, refresh_rate, flags);
813 static HRESULT WINAPI ddraw3_SetDisplayMode(IDirectDraw3 *iface,
814 DWORD width, DWORD height, DWORD bpp, DWORD refresh_rate, DWORD flags)
816 TRACE("iface %p, width %u, height %u, bpp %u, refresh_rate %u, flags %#x.\n",
817 iface, width, height, bpp, refresh_rate, flags);
819 return ddraw7_SetDisplayMode((IDirectDraw7 *)ddraw_from_ddraw3(iface),
820 width, height, bpp, refresh_rate, flags);
823 static HRESULT WINAPI ddraw2_SetDisplayMode(IDirectDraw2 *iface,
824 DWORD width, DWORD height, DWORD bpp, DWORD refresh_rate, DWORD flags)
826 TRACE("iface %p, width %u, height %u, bpp %u, refresh_rate %u, flags %#x.\n",
827 iface, width, height, bpp, refresh_rate, flags);
829 return ddraw7_SetDisplayMode((IDirectDraw7 *)ddraw_from_ddraw2(iface),
830 width, height, bpp, refresh_rate, flags);
833 static HRESULT WINAPI ddraw1_SetDisplayMode(IDirectDraw *iface, DWORD width, DWORD height, DWORD bpp)
835 TRACE("iface %p, width %u, height %u, bpp %u.\n", iface, width, height, bpp);
837 return ddraw7_SetDisplayMode((IDirectDraw7 *)ddraw_from_ddraw1(iface), width, height, bpp, 0, 0);
840 /*****************************************************************************
841 * IDirectDraw7::RestoreDisplayMode
843 * Restores the display mode to what it was at creation time. Basically.
845 * A problem arises when there are 2 DirectDraw objects using the same hwnd:
846 * -> DD_1 finds the screen at 1400x1050x32 when created, sets it to 640x480x16
847 * -> DD_2 is created, finds the screen at 640x480x16, sets it to 1024x768x32
848 * -> DD_1 is released. The screen should be left at 1024x768x32.
849 * -> DD_2 is released. The screen should be set to 1400x1050x32
850 * This case is unhandled right now, but Empire Earth does it this way.
851 * (But perhaps there is something in SetCooperativeLevel to prevent this)
853 * The msdn says that this method resets the display mode to what it was before
854 * SetDisplayMode was called. What if SetDisplayModes is called 2 times??
856 * Returns
857 * DD_OK on success
858 * DDERR_NOEXCLUSIVE mode if the device isn't in fullscreen mode
860 *****************************************************************************/
861 static HRESULT WINAPI ddraw7_RestoreDisplayMode(IDirectDraw7 *iface)
863 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
864 TRACE("(%p)\n", This);
866 return ddraw_set_display_mode(iface, This->orig_width, This->orig_height, This->orig_bpp, 0, 0);
869 static HRESULT WINAPI ddraw4_RestoreDisplayMode(IDirectDraw4 *iface)
871 TRACE("iface %p.\n", iface);
873 return ddraw7_RestoreDisplayMode((IDirectDraw7 *)ddraw_from_ddraw4(iface));
876 static HRESULT WINAPI ddraw3_RestoreDisplayMode(IDirectDraw3 *iface)
878 TRACE("iface %p.\n", iface);
880 return ddraw7_RestoreDisplayMode((IDirectDraw7 *)ddraw_from_ddraw3(iface));
883 static HRESULT WINAPI ddraw2_RestoreDisplayMode(IDirectDraw2 *iface)
885 TRACE("iface %p.\n", iface);
887 return ddraw7_RestoreDisplayMode((IDirectDraw7 *)ddraw_from_ddraw2(iface));
890 static HRESULT WINAPI ddraw1_RestoreDisplayMode(IDirectDraw *iface)
892 TRACE("iface %p.\n", iface);
894 return ddraw7_RestoreDisplayMode((IDirectDraw7 *)ddraw_from_ddraw1(iface));
897 /*****************************************************************************
898 * IDirectDraw7::GetCaps
900 * Returns the drives capabilities
902 * Used for version 1, 2, 4 and 7
904 * Params:
905 * DriverCaps: Structure to write the Hardware accelerated caps to
906 * HelCaps: Structure to write the emulation caps to
908 * Returns
909 * This implementation returns DD_OK only
911 *****************************************************************************/
912 static HRESULT WINAPI ddraw7_GetCaps(IDirectDraw7 *iface, DDCAPS *DriverCaps, DDCAPS *HELCaps)
914 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
915 DDCAPS caps;
916 WINED3DCAPS winecaps;
917 HRESULT hr;
918 DDSCAPS2 ddscaps = {0, 0, 0, 0};
919 TRACE("(%p)->(%p,%p)\n", This, DriverCaps, HELCaps);
921 /* One structure must be != NULL */
922 if( (!DriverCaps) && (!HELCaps) )
924 ERR("(%p) Invalid params to ddraw7_GetCaps\n", This);
925 return DDERR_INVALIDPARAMS;
928 memset(&caps, 0, sizeof(caps));
929 memset(&winecaps, 0, sizeof(winecaps));
930 caps.dwSize = sizeof(caps);
931 EnterCriticalSection(&ddraw_cs);
932 hr = IWineD3DDevice_GetDeviceCaps(This->wineD3DDevice, &winecaps);
933 if(FAILED(hr)) {
934 WARN("IWineD3DDevice::GetDeviceCaps failed\n");
935 LeaveCriticalSection(&ddraw_cs);
936 return hr;
939 hr = IDirectDraw7_GetAvailableVidMem(iface, &ddscaps, &caps.dwVidMemTotal, &caps.dwVidMemFree);
940 LeaveCriticalSection(&ddraw_cs);
941 if(FAILED(hr)) {
942 WARN("IDirectDraw7::GetAvailableVidMem failed\n");
943 return hr;
946 caps.dwCaps = winecaps.DirectDrawCaps.Caps;
947 caps.dwCaps2 = winecaps.DirectDrawCaps.Caps2;
948 caps.dwCKeyCaps = winecaps.DirectDrawCaps.CKeyCaps;
949 caps.dwFXCaps = winecaps.DirectDrawCaps.FXCaps;
950 caps.dwPalCaps = winecaps.DirectDrawCaps.PalCaps;
951 caps.ddsCaps.dwCaps = winecaps.DirectDrawCaps.ddsCaps;
952 caps.dwSVBCaps = winecaps.DirectDrawCaps.SVBCaps;
953 caps.dwSVBCKeyCaps = winecaps.DirectDrawCaps.SVBCKeyCaps;
954 caps.dwSVBFXCaps = winecaps.DirectDrawCaps.SVBFXCaps;
955 caps.dwVSBCaps = winecaps.DirectDrawCaps.VSBCaps;
956 caps.dwVSBCKeyCaps = winecaps.DirectDrawCaps.VSBCKeyCaps;
957 caps.dwVSBFXCaps = winecaps.DirectDrawCaps.VSBFXCaps;
958 caps.dwSSBCaps = winecaps.DirectDrawCaps.SSBCaps;
959 caps.dwSSBCKeyCaps = winecaps.DirectDrawCaps.SSBCKeyCaps;
960 caps.dwSSBFXCaps = winecaps.DirectDrawCaps.SSBFXCaps;
962 /* Even if WineD3D supports 3D rendering, remove the cap if ddraw is configured
963 * not to use it
965 if(DefaultSurfaceType == SURFACE_GDI) {
966 caps.dwCaps &= ~DDCAPS_3D;
967 caps.ddsCaps.dwCaps &= ~(DDSCAPS_3DDEVICE | DDSCAPS_MIPMAP | DDSCAPS_TEXTURE | DDSCAPS_ZBUFFER);
969 if(winecaps.DirectDrawCaps.StrideAlign != 0) {
970 caps.dwCaps |= DDCAPS_ALIGNSTRIDE;
971 caps.dwAlignStrideAlign = winecaps.DirectDrawCaps.StrideAlign;
974 if(DriverCaps)
976 DD_STRUCT_COPY_BYSIZE(DriverCaps, &caps);
977 if (TRACE_ON(ddraw))
979 TRACE("Driver Caps :\n");
980 DDRAW_dump_DDCAPS(DriverCaps);
984 if(HELCaps)
986 DD_STRUCT_COPY_BYSIZE(HELCaps, &caps);
987 if (TRACE_ON(ddraw))
989 TRACE("HEL Caps :\n");
990 DDRAW_dump_DDCAPS(HELCaps);
994 return DD_OK;
997 static HRESULT WINAPI ddraw4_GetCaps(IDirectDraw4 *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
999 TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1001 return ddraw7_GetCaps((IDirectDraw7 *)ddraw_from_ddraw4(iface), driver_caps, hel_caps);
1004 static HRESULT WINAPI ddraw3_GetCaps(IDirectDraw3 *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1006 TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1008 return ddraw7_GetCaps((IDirectDraw7 *)ddraw_from_ddraw3(iface), driver_caps, hel_caps);
1011 static HRESULT WINAPI ddraw2_GetCaps(IDirectDraw2 *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1013 TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1015 return ddraw7_GetCaps((IDirectDraw7 *)ddraw_from_ddraw2(iface), driver_caps, hel_caps);
1018 static HRESULT WINAPI ddraw1_GetCaps(IDirectDraw *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1020 TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1022 return ddraw7_GetCaps((IDirectDraw7 *)ddraw_from_ddraw1(iface), driver_caps, hel_caps);
1025 /*****************************************************************************
1026 * IDirectDraw7::Compact
1028 * No idea what it does, MSDN says it's not implemented.
1030 * Returns
1031 * DD_OK, but this is unchecked
1033 *****************************************************************************/
1034 static HRESULT WINAPI ddraw7_Compact(IDirectDraw7 *iface)
1036 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1037 TRACE("(%p)\n", This);
1039 return DD_OK;
1042 static HRESULT WINAPI ddraw4_Compact(IDirectDraw4 *iface)
1044 TRACE("iface %p.\n", iface);
1046 return ddraw7_Compact((IDirectDraw7 *)ddraw_from_ddraw4(iface));
1049 static HRESULT WINAPI ddraw3_Compact(IDirectDraw3 *iface)
1051 TRACE("iface %p.\n", iface);
1053 return ddraw7_Compact((IDirectDraw7 *)ddraw_from_ddraw3(iface));
1056 static HRESULT WINAPI ddraw2_Compact(IDirectDraw2 *iface)
1058 TRACE("iface %p.\n", iface);
1060 return ddraw7_Compact((IDirectDraw7 *)ddraw_from_ddraw2(iface));
1063 static HRESULT WINAPI ddraw1_Compact(IDirectDraw *iface)
1065 TRACE("iface %p.\n", iface);
1067 return ddraw7_Compact((IDirectDraw7 *)ddraw_from_ddraw1(iface));
1070 /*****************************************************************************
1071 * IDirectDraw7::GetDisplayMode
1073 * Returns information about the current display mode
1075 * Exists in Version 1, 2, 4 and 7
1077 * Params:
1078 * DDSD: Address of a surface description structure to write the info to
1080 * Returns
1081 * DD_OK
1083 *****************************************************************************/
1084 static HRESULT WINAPI ddraw7_GetDisplayMode(IDirectDraw7 *iface, DDSURFACEDESC2 *DDSD)
1086 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1087 HRESULT hr;
1088 WINED3DDISPLAYMODE Mode;
1089 DWORD Size;
1090 TRACE("(%p)->(%p): Relay\n", This, DDSD);
1092 EnterCriticalSection(&ddraw_cs);
1093 /* This seems sane */
1094 if (!DDSD)
1096 LeaveCriticalSection(&ddraw_cs);
1097 return DDERR_INVALIDPARAMS;
1100 /* The necessary members of LPDDSURFACEDESC and LPDDSURFACEDESC2 are equal,
1101 * so one method can be used for all versions (Hopefully)
1103 hr = IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
1104 0 /* swapchain 0 */,
1105 &Mode);
1106 if( hr != D3D_OK )
1108 ERR(" (%p) IWineD3DDevice::GetDisplayMode returned %08x\n", This, hr);
1109 LeaveCriticalSection(&ddraw_cs);
1110 return hr;
1113 Size = DDSD->dwSize;
1114 memset(DDSD, 0, Size);
1116 DDSD->dwSize = Size;
1117 DDSD->dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_REFRESHRATE;
1118 DDSD->dwWidth = Mode.Width;
1119 DDSD->dwHeight = Mode.Height;
1120 DDSD->u2.dwRefreshRate = 60;
1121 DDSD->ddsCaps.dwCaps = 0;
1122 DDSD->u4.ddpfPixelFormat.dwSize = sizeof(DDSD->u4.ddpfPixelFormat);
1123 PixelFormat_WineD3DtoDD(&DDSD->u4.ddpfPixelFormat, Mode.Format);
1124 DDSD->u1.lPitch = Mode.Width * DDSD->u4.ddpfPixelFormat.u1.dwRGBBitCount / 8;
1126 if(TRACE_ON(ddraw))
1128 TRACE("Returning surface desc :\n");
1129 DDRAW_dump_surface_desc(DDSD);
1132 LeaveCriticalSection(&ddraw_cs);
1133 return DD_OK;
1136 static HRESULT WINAPI ddraw4_GetDisplayMode(IDirectDraw4 *iface, DDSURFACEDESC2 *surface_desc)
1138 TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1140 return ddraw7_GetDisplayMode((IDirectDraw7 *)ddraw_from_ddraw4(iface), surface_desc);
1143 static HRESULT WINAPI ddraw3_GetDisplayMode(IDirectDraw3 *iface, DDSURFACEDESC *surface_desc)
1145 TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1147 return ddraw7_GetDisplayMode((IDirectDraw7 *)ddraw_from_ddraw3(iface), (DDSURFACEDESC2 *)surface_desc);
1150 static HRESULT WINAPI ddraw2_GetDisplayMode(IDirectDraw2 *iface, DDSURFACEDESC *surface_desc)
1152 TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1154 return ddraw7_GetDisplayMode((IDirectDraw7 *)ddraw_from_ddraw2(iface), (DDSURFACEDESC2 *)surface_desc);
1157 static HRESULT WINAPI ddraw1_GetDisplayMode(IDirectDraw *iface, DDSURFACEDESC *surface_desc)
1159 TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1161 return ddraw7_GetDisplayMode((IDirectDraw7 *)ddraw_from_ddraw1(iface), (DDSURFACEDESC2 *)surface_desc);
1164 /*****************************************************************************
1165 * IDirectDraw7::GetFourCCCodes
1167 * Returns an array of supported FourCC codes.
1169 * Exists in Version 1, 2, 4 and 7
1171 * Params:
1172 * NumCodes: Contains the number of Codes that Codes can carry. Returns the number
1173 * of enumerated codes
1174 * Codes: Pointer to an array of DWORDs where the supported codes are written
1175 * to
1177 * Returns
1178 * Always returns DD_OK, as it's a stub for now
1180 *****************************************************************************/
1181 static HRESULT WINAPI ddraw7_GetFourCCCodes(IDirectDraw7 *iface, DWORD *NumCodes, DWORD *Codes)
1183 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1184 WINED3DFORMAT formats[] = {
1185 WINED3DFMT_YUY2, WINED3DFMT_UYVY, WINED3DFMT_YV12,
1186 WINED3DFMT_DXT1, WINED3DFMT_DXT2, WINED3DFMT_DXT3, WINED3DFMT_DXT4, WINED3DFMT_DXT5,
1187 WINED3DFMT_ATI2N, WINED3DFMT_NVHU, WINED3DFMT_NVHS
1189 DWORD count = 0, i, outsize;
1190 HRESULT hr;
1191 WINED3DDISPLAYMODE d3ddm;
1192 WINED3DSURFTYPE type = This->ImplType;
1193 TRACE("(%p)->(%p, %p)\n", This, NumCodes, Codes);
1195 IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
1196 0 /* swapchain 0 */,
1197 &d3ddm);
1199 outsize = NumCodes && Codes ? *NumCodes : 0;
1201 if(type == SURFACE_UNKNOWN) type = SURFACE_GDI;
1203 for(i = 0; i < (sizeof(formats) / sizeof(formats[0])); i++) {
1204 hr = IWineD3D_CheckDeviceFormat(This->wineD3D,
1205 WINED3DADAPTER_DEFAULT,
1206 WINED3DDEVTYPE_HAL,
1207 d3ddm.Format /* AdapterFormat */,
1208 0 /* usage */,
1209 WINED3DRTYPE_SURFACE,
1210 formats[i],
1211 type);
1212 if(SUCCEEDED(hr)) {
1213 if(count < outsize) {
1214 Codes[count] = formats[i];
1216 count++;
1219 if(NumCodes) {
1220 TRACE("Returning %u FourCC codes\n", count);
1221 *NumCodes = count;
1224 return DD_OK;
1227 static HRESULT WINAPI ddraw4_GetFourCCCodes(IDirectDraw4 *iface, DWORD *codes_count, DWORD *codes)
1229 TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1231 return ddraw7_GetFourCCCodes((IDirectDraw7 *)ddraw_from_ddraw4(iface), codes_count, codes);
1234 static HRESULT WINAPI ddraw3_GetFourCCCodes(IDirectDraw3 *iface, DWORD *codes_count, DWORD *codes)
1236 TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1238 return ddraw7_GetFourCCCodes((IDirectDraw7 *)ddraw_from_ddraw3(iface), codes_count, codes);
1241 static HRESULT WINAPI ddraw2_GetFourCCCodes(IDirectDraw2 *iface, DWORD *codes_count, DWORD *codes)
1243 TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1245 return ddraw7_GetFourCCCodes((IDirectDraw7 *)ddraw_from_ddraw2(iface), codes_count, codes);
1248 static HRESULT WINAPI ddraw1_GetFourCCCodes(IDirectDraw *iface, DWORD *codes_count, DWORD *codes)
1250 TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1252 return ddraw7_GetFourCCCodes((IDirectDraw7 *)ddraw_from_ddraw1(iface), codes_count, codes);
1255 /*****************************************************************************
1256 * IDirectDraw7::GetMonitorFrequency
1258 * Returns the monitor's frequency
1260 * Exists in Version 1, 2, 4 and 7
1262 * Params:
1263 * Freq: Pointer to a DWORD to write the frequency to
1265 * Returns
1266 * Always returns DD_OK
1268 *****************************************************************************/
1269 static HRESULT WINAPI ddraw7_GetMonitorFrequency(IDirectDraw7 *iface, DWORD *Freq)
1271 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1272 TRACE("(%p)->(%p)\n", This, Freq);
1274 /* Ideally this should be in WineD3D, as it concerns the screen setup,
1275 * but for now this should make the games happy
1277 *Freq = 60;
1278 return DD_OK;
1281 static HRESULT WINAPI ddraw4_GetMonitorFrequency(IDirectDraw4 *iface, DWORD *frequency)
1283 TRACE("iface %p, frequency %p.\n", iface, frequency);
1285 return ddraw7_GetMonitorFrequency((IDirectDraw7 *)ddraw_from_ddraw4(iface), frequency);
1288 static HRESULT WINAPI ddraw3_GetMonitorFrequency(IDirectDraw3 *iface, DWORD *frequency)
1290 TRACE("iface %p, frequency %p.\n", iface, frequency);
1292 return ddraw7_GetMonitorFrequency((IDirectDraw7 *)ddraw_from_ddraw3(iface), frequency);
1295 static HRESULT WINAPI ddraw2_GetMonitorFrequency(IDirectDraw2 *iface, DWORD *frequency)
1297 TRACE("iface %p, frequency %p.\n", iface, frequency);
1299 return ddraw7_GetMonitorFrequency((IDirectDraw7 *)ddraw_from_ddraw2(iface), frequency);
1302 static HRESULT WINAPI ddraw1_GetMonitorFrequency(IDirectDraw *iface, DWORD *frequency)
1304 TRACE("iface %p, frequency %p.\n", iface, frequency);
1306 return ddraw7_GetMonitorFrequency((IDirectDraw7 *)ddraw_from_ddraw1(iface), frequency);
1309 /*****************************************************************************
1310 * IDirectDraw7::GetVerticalBlankStatus
1312 * Returns the Vertical blank status of the monitor. This should be in WineD3D
1313 * too basically, but as it's a semi stub, I didn't create a function there
1315 * Params:
1316 * status: Pointer to a BOOL to be filled with the vertical blank status
1318 * Returns
1319 * DD_OK on success
1320 * DDERR_INVALIDPARAMS if status is NULL
1322 *****************************************************************************/
1323 static HRESULT WINAPI ddraw7_GetVerticalBlankStatus(IDirectDraw7 *iface, BOOL *status)
1325 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1326 TRACE("(%p)->(%p)\n", This, status);
1328 /* This looks sane, the MSDN suggests it too */
1329 EnterCriticalSection(&ddraw_cs);
1330 if(!status)
1332 LeaveCriticalSection(&ddraw_cs);
1333 return DDERR_INVALIDPARAMS;
1336 *status = This->fake_vblank;
1337 This->fake_vblank = !This->fake_vblank;
1338 LeaveCriticalSection(&ddraw_cs);
1339 return DD_OK;
1342 static HRESULT WINAPI ddraw4_GetVerticalBlankStatus(IDirectDraw4 *iface, BOOL *status)
1344 TRACE("iface %p, status %p.\n", iface, status);
1346 return ddraw7_GetVerticalBlankStatus((IDirectDraw7 *)ddraw_from_ddraw4(iface), status);
1349 static HRESULT WINAPI ddraw3_GetVerticalBlankStatus(IDirectDraw3 *iface, BOOL *status)
1351 TRACE("iface %p, status %p.\n", iface, status);
1353 return ddraw7_GetVerticalBlankStatus((IDirectDraw7 *)ddraw_from_ddraw3(iface), status);
1356 static HRESULT WINAPI ddraw2_GetVerticalBlankStatus(IDirectDraw2 *iface, BOOL *status)
1358 TRACE("iface %p, status %p.\n", iface, status);
1360 return ddraw7_GetVerticalBlankStatus((IDirectDraw7 *)ddraw_from_ddraw2(iface), status);
1363 static HRESULT WINAPI ddraw1_GetVerticalBlankStatus(IDirectDraw *iface, BOOL *status)
1365 TRACE("iface %p, status %p.\n", iface, status);
1367 return ddraw7_GetVerticalBlankStatus((IDirectDraw7 *)ddraw_from_ddraw1(iface), status);
1370 /*****************************************************************************
1371 * IDirectDraw7::GetAvailableVidMem
1373 * Returns the total and free video memory
1375 * Params:
1376 * Caps: Specifies the memory type asked for
1377 * total: Pointer to a DWORD to be filled with the total memory
1378 * free: Pointer to a DWORD to be filled with the free memory
1380 * Returns
1381 * DD_OK on success
1382 * DDERR_INVALIDPARAMS of free and total are NULL
1384 *****************************************************************************/
1385 static HRESULT WINAPI ddraw7_GetAvailableVidMem(IDirectDraw7 *iface, DDSCAPS2 *Caps, DWORD *total, DWORD *free)
1387 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1388 TRACE("(%p)->(%p, %p, %p)\n", This, Caps, total, free);
1390 if(TRACE_ON(ddraw))
1392 TRACE("(%p) Asked for memory with description: ", This);
1393 DDRAW_dump_DDSCAPS2(Caps);
1395 EnterCriticalSection(&ddraw_cs);
1397 /* Todo: System memory vs local video memory vs non-local video memory
1398 * The MSDN also mentions differences between texture memory and other
1399 * resources, but that's not important
1402 if( (!total) && (!free) )
1404 LeaveCriticalSection(&ddraw_cs);
1405 return DDERR_INVALIDPARAMS;
1408 if(total) *total = This->total_vidmem;
1409 if(free) *free = IWineD3DDevice_GetAvailableTextureMem(This->wineD3DDevice);
1411 LeaveCriticalSection(&ddraw_cs);
1412 return DD_OK;
1415 static HRESULT WINAPI ddraw4_GetAvailableVidMem(IDirectDraw4 *iface,
1416 DDSCAPS2 *caps, DWORD *total, DWORD *free)
1418 TRACE("iface %p, caps %p, total %p, free %p.\n", iface, caps, total, free);
1420 return ddraw7_GetAvailableVidMem((IDirectDraw7 *)ddraw_from_ddraw4(iface), caps, total, free);
1423 static HRESULT WINAPI ddraw3_GetAvailableVidMem(IDirectDraw3 *iface,
1424 DDSCAPS *caps, DWORD *total, DWORD *free)
1426 DDSCAPS2 caps2;
1428 TRACE("iface %p, caps %p, total %p, free %p.\n", iface, caps, total, free);
1430 DDRAW_Convert_DDSCAPS_1_To_2(caps, &caps2);
1431 return ddraw7_GetAvailableVidMem((IDirectDraw7 *)ddraw_from_ddraw3(iface), &caps2, total, free);
1434 static HRESULT WINAPI ddraw2_GetAvailableVidMem(IDirectDraw2 *iface,
1435 DDSCAPS *caps, DWORD *total, DWORD *free)
1437 DDSCAPS2 caps2;
1439 TRACE("iface %p, caps %p, total %p, free %p.\n", iface, caps, total, free);
1441 DDRAW_Convert_DDSCAPS_1_To_2(caps, &caps2);
1442 return ddraw7_GetAvailableVidMem((IDirectDraw7 *)ddraw_from_ddraw2(iface), &caps2, total, free);
1445 /*****************************************************************************
1446 * IDirectDraw7::Initialize
1448 * Initializes a DirectDraw interface.
1450 * Params:
1451 * GUID: Interface identifier. Well, don't know what this is really good
1452 * for
1454 * Returns
1455 * Returns DD_OK on the first call,
1456 * DDERR_ALREADYINITIALIZED on repeated calls
1458 *****************************************************************************/
1459 static HRESULT WINAPI ddraw7_Initialize(IDirectDraw7 *iface, GUID *Guid)
1461 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1462 TRACE("(%p)->(%s): No-op\n", This, debugstr_guid(Guid));
1464 if(This->initialized)
1466 return DDERR_ALREADYINITIALIZED;
1468 else
1470 return DD_OK;
1474 static HRESULT WINAPI ddraw4_Initialize(IDirectDraw4 *iface, GUID *guid)
1476 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
1478 return ddraw7_Initialize((IDirectDraw7 *)ddraw_from_ddraw4(iface), guid);
1481 static HRESULT WINAPI ddraw3_Initialize(IDirectDraw3 *iface, GUID *guid)
1483 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
1485 return ddraw7_Initialize((IDirectDraw7 *)ddraw_from_ddraw3(iface), guid);
1488 static HRESULT WINAPI ddraw2_Initialize(IDirectDraw2 *iface, GUID *guid)
1490 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
1492 return ddraw7_Initialize((IDirectDraw7 *)ddraw_from_ddraw2(iface), guid);
1495 static HRESULT WINAPI ddraw1_Initialize(IDirectDraw *iface, GUID *guid)
1497 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
1499 return ddraw7_Initialize((IDirectDraw7 *)ddraw_from_ddraw1(iface), guid);
1502 /*****************************************************************************
1503 * IDirectDraw7::FlipToGDISurface
1505 * "Makes the surface that the GDI writes to the primary surface"
1506 * Looks like some windows specific thing we don't have to care about.
1507 * According to MSDN it permits GDI dialog boxes in FULLSCREEN mode. Good to
1508 * show error boxes ;)
1509 * Well, just return DD_OK.
1511 * Returns:
1512 * Always returns DD_OK
1514 *****************************************************************************/
1515 static HRESULT WINAPI ddraw7_FlipToGDISurface(IDirectDraw7 *iface)
1517 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1518 TRACE("(%p)\n", This);
1520 return DD_OK;
1523 static HRESULT WINAPI ddraw4_FlipToGDISurface(IDirectDraw4 *iface)
1525 TRACE("iface %p.\n", iface);
1527 return ddraw7_FlipToGDISurface((IDirectDraw7 *)ddraw_from_ddraw4(iface));
1530 static HRESULT WINAPI ddraw3_FlipToGDISurface(IDirectDraw3 *iface)
1532 TRACE("iface %p.\n", iface);
1534 return ddraw7_FlipToGDISurface((IDirectDraw7 *)ddraw_from_ddraw3(iface));
1537 static HRESULT WINAPI ddraw2_FlipToGDISurface(IDirectDraw2 *iface)
1539 TRACE("iface %p.\n", iface);
1541 return ddraw7_FlipToGDISurface((IDirectDraw7 *)ddraw_from_ddraw2(iface));
1544 static HRESULT WINAPI ddraw1_FlipToGDISurface(IDirectDraw *iface)
1546 TRACE("iface %p.\n", iface);
1548 return ddraw7_FlipToGDISurface((IDirectDraw7 *)ddraw_from_ddraw1(iface));
1551 /*****************************************************************************
1552 * IDirectDraw7::WaitForVerticalBlank
1554 * This method allows applications to get in sync with the vertical blank
1555 * interval.
1556 * The wormhole demo in the DirectX 7 sdk uses this call, and it doesn't
1557 * redraw the screen, most likely because of this stub
1559 * Parameters:
1560 * Flags: one of DDWAITVB_BLOCKBEGIN, DDWAITVB_BLOCKBEGINEVENT
1561 * or DDWAITVB_BLOCKEND
1562 * h: Not used, according to MSDN
1564 * Returns:
1565 * Always returns DD_OK
1567 *****************************************************************************/
1568 static HRESULT WINAPI ddraw7_WaitForVerticalBlank(IDirectDraw7 *iface, DWORD Flags, HANDLE h)
1570 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1571 static BOOL hide = FALSE;
1573 /* This function is called often, so print the fixme only once */
1574 if(!hide)
1576 FIXME("(%p)->(%x,%p): Stub\n", This, Flags, h);
1577 hide = TRUE;
1580 /* MSDN says DDWAITVB_BLOCKBEGINEVENT is not supported */
1581 if(Flags & DDWAITVB_BLOCKBEGINEVENT)
1582 return DDERR_UNSUPPORTED; /* unchecked */
1584 return DD_OK;
1587 static HRESULT WINAPI ddraw4_WaitForVerticalBlank(IDirectDraw4 *iface, DWORD flags, HANDLE event)
1589 TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
1591 return ddraw7_WaitForVerticalBlank((IDirectDraw7 *)ddraw_from_ddraw4(iface), flags, event);
1594 static HRESULT WINAPI ddraw3_WaitForVerticalBlank(IDirectDraw3 *iface, DWORD flags, HANDLE event)
1596 TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
1598 return ddraw7_WaitForVerticalBlank((IDirectDraw7 *)ddraw_from_ddraw3(iface), flags, event);
1601 static HRESULT WINAPI ddraw2_WaitForVerticalBlank(IDirectDraw2 *iface, DWORD flags, HANDLE event)
1603 TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
1605 return ddraw7_WaitForVerticalBlank((IDirectDraw7 *)ddraw_from_ddraw2(iface), flags, event);
1608 static HRESULT WINAPI ddraw1_WaitForVerticalBlank(IDirectDraw *iface, DWORD flags, HANDLE event)
1610 TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
1612 return ddraw7_WaitForVerticalBlank((IDirectDraw7 *)ddraw_from_ddraw1(iface), flags, event);
1615 /*****************************************************************************
1616 * IDirectDraw7::GetScanLine
1618 * Returns the scan line that is being drawn on the monitor
1620 * Parameters:
1621 * Scanline: Address to write the scan line value to
1623 * Returns:
1624 * Always returns DD_OK
1626 *****************************************************************************/
1627 static HRESULT WINAPI ddraw7_GetScanLine(IDirectDraw7 *iface, DWORD *Scanline)
1629 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1630 static BOOL hide = FALSE;
1631 WINED3DDISPLAYMODE Mode;
1633 /* This function is called often, so print the fixme only once */
1634 EnterCriticalSection(&ddraw_cs);
1635 if(!hide)
1637 FIXME("(%p)->(%p): Semi-Stub\n", This, Scanline);
1638 hide = TRUE;
1641 IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
1643 &Mode);
1645 /* Fake the line sweeping of the monitor */
1646 /* FIXME: We should synchronize with a source to keep the refresh rate */
1647 *Scanline = This->cur_scanline++;
1648 /* Assume 20 scan lines in the vertical blank */
1649 if (This->cur_scanline >= Mode.Height + 20)
1650 This->cur_scanline = 0;
1652 LeaveCriticalSection(&ddraw_cs);
1653 return DD_OK;
1656 static HRESULT WINAPI ddraw4_GetScanLine(IDirectDraw4 *iface, DWORD *line)
1658 TRACE("iface %p, line %p.\n", iface, line);
1660 return ddraw7_GetScanLine((IDirectDraw7 *)ddraw_from_ddraw4(iface), line);
1663 static HRESULT WINAPI ddraw3_GetScanLine(IDirectDraw3 *iface, DWORD *line)
1665 TRACE("iface %p, line %p.\n", iface, line);
1667 return ddraw7_GetScanLine((IDirectDraw7 *)ddraw_from_ddraw3(iface), line);
1670 static HRESULT WINAPI ddraw2_GetScanLine(IDirectDraw2 *iface, DWORD *line)
1672 TRACE("iface %p, line %p.\n", iface, line);
1674 return ddraw7_GetScanLine((IDirectDraw7 *)ddraw_from_ddraw2(iface), line);
1677 static HRESULT WINAPI ddraw1_GetScanLine(IDirectDraw *iface, DWORD *line)
1679 TRACE("iface %p, line %p.\n", iface, line);
1681 return ddraw7_GetScanLine((IDirectDraw7 *)ddraw_from_ddraw1(iface), line);
1684 /*****************************************************************************
1685 * IDirectDraw7::TestCooperativeLevel
1687 * Informs the application about the state of the video adapter, depending
1688 * on the cooperative level
1690 * Returns:
1691 * DD_OK if the device is in a sane state
1692 * DDERR_NOEXCLUSIVEMODE or DDERR_EXCLUSIVEMODEALREADYSET
1693 * if the state is not correct(See below)
1695 *****************************************************************************/
1696 static HRESULT WINAPI ddraw7_TestCooperativeLevel(IDirectDraw7 *iface)
1698 TRACE("iface %p.\n", iface);
1700 return DD_OK;
1703 static HRESULT WINAPI ddraw4_TestCooperativeLevel(IDirectDraw4 *iface)
1705 TRACE("iface %p.\n", iface);
1707 return ddraw7_TestCooperativeLevel((IDirectDraw7 *)ddraw_from_ddraw4(iface));
1710 /*****************************************************************************
1711 * IDirectDraw7::GetGDISurface
1713 * Returns the surface that GDI is treating as the primary surface.
1714 * For Wine this is the front buffer
1716 * Params:
1717 * GDISurface: Address to write the surface pointer to
1719 * Returns:
1720 * DD_OK if the surface was found
1721 * DDERR_NOTFOUND if the GDI surface wasn't found
1723 *****************************************************************************/
1724 static HRESULT WINAPI ddraw7_GetGDISurface(IDirectDraw7 *iface, IDirectDrawSurface7 **GDISurface)
1726 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1727 IWineD3DSurface *Surf;
1728 IDirectDrawSurface7 *ddsurf;
1729 HRESULT hr;
1730 DDSCAPS2 ddsCaps;
1731 TRACE("(%p)->(%p)\n", This, GDISurface);
1733 /* Get the back buffer from the wineD3DDevice and search its
1734 * attached surfaces for the front buffer
1736 EnterCriticalSection(&ddraw_cs);
1737 hr = IWineD3DDevice_GetBackBuffer(This->wineD3DDevice,
1738 0, /* SwapChain */
1739 0, /* first back buffer*/
1740 WINED3DBACKBUFFER_TYPE_MONO,
1741 &Surf);
1743 if( (hr != D3D_OK) ||
1744 (!Surf) )
1746 ERR("IWineD3DDevice::GetBackBuffer failed\n");
1747 LeaveCriticalSection(&ddraw_cs);
1748 return DDERR_NOTFOUND;
1751 /* GetBackBuffer AddRef()ed the surface, release it */
1752 IWineD3DSurface_Release(Surf);
1754 IWineD3DSurface_GetParent(Surf,
1755 (IUnknown **) &ddsurf);
1756 IDirectDrawSurface7_Release(ddsurf); /* For the GetParent */
1758 /* Find the front buffer */
1759 ddsCaps.dwCaps = DDSCAPS_FRONTBUFFER;
1760 hr = IDirectDrawSurface7_GetAttachedSurface(ddsurf,
1761 &ddsCaps,
1762 GDISurface);
1763 if(hr != DD_OK)
1765 ERR("IDirectDrawSurface7::GetAttachedSurface failed, hr = %x\n", hr);
1768 /* The AddRef is OK this time */
1769 LeaveCriticalSection(&ddraw_cs);
1770 return hr;
1773 static HRESULT WINAPI ddraw4_GetGDISurface(IDirectDraw4 *iface, IDirectDrawSurface4 **surface)
1775 TRACE("iface %p, surface %p.\n", iface, surface);
1777 return ddraw7_GetGDISurface((IDirectDraw7 *)ddraw_from_ddraw4(iface), (IDirectDrawSurface7 **)surface);
1780 static HRESULT WINAPI ddraw3_GetGDISurface(IDirectDraw3 *iface, IDirectDrawSurface **surface)
1782 IDirectDrawSurface7 *surface7;
1783 HRESULT hr;
1785 TRACE("iface %p, surface %p.\n", iface, surface);
1787 hr = ddraw7_GetGDISurface((IDirectDraw7 *)ddraw_from_ddraw3(iface), &surface7);
1788 *surface = surface7 ? (IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)surface7)->IDirectDrawSurface3_vtbl : NULL;
1790 return hr;
1793 static HRESULT WINAPI ddraw2_GetGDISurface(IDirectDraw2 *iface, IDirectDrawSurface **surface)
1795 IDirectDrawSurface7 *surface7;
1796 HRESULT hr;
1798 TRACE("iface %p, surface %p.\n", iface, surface);
1800 hr = ddraw7_GetGDISurface((IDirectDraw7 *)ddraw_from_ddraw2(iface), &surface7);
1801 *surface = surface7 ? (IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)surface7)->IDirectDrawSurface3_vtbl : NULL;
1803 return hr;
1806 static HRESULT WINAPI ddraw1_GetGDISurface(IDirectDraw *iface, IDirectDrawSurface **surface)
1808 IDirectDrawSurface7 *surface7;
1809 HRESULT hr;
1811 TRACE("iface %p, surface %p.\n", iface, surface);
1813 hr = ddraw7_GetGDISurface((IDirectDraw7 *)ddraw_from_ddraw1(iface), &surface7);
1814 *surface = surface7 ? (IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)surface7)->IDirectDrawSurface3_vtbl : NULL;
1816 return hr;
1819 struct displaymodescallback_context
1821 LPDDENUMMODESCALLBACK func;
1822 void *context;
1825 static HRESULT CALLBACK EnumDisplayModesCallbackThunk(DDSURFACEDESC2 *surface_desc, void *context)
1827 struct displaymodescallback_context *cbcontext = context;
1828 DDSURFACEDESC desc;
1830 memcpy(&desc, surface_desc, sizeof(desc));
1831 desc.dwSize = sizeof(desc);
1833 return cbcontext->func(&desc, cbcontext->context);
1836 /*****************************************************************************
1837 * IDirectDraw7::EnumDisplayModes
1839 * Enumerates the supported Display modes. The modes can be filtered with
1840 * the DDSD parameter.
1842 * Params:
1843 * Flags: can be DDEDM_REFRESHRATES and DDEDM_STANDARDVGAMODES
1844 * DDSD: Surface description to filter the modes
1845 * Context: Pointer passed back to the callback function
1846 * cb: Application-provided callback function
1848 * Returns:
1849 * DD_OK on success
1850 * DDERR_INVALIDPARAMS if the callback wasn't set
1852 *****************************************************************************/
1853 static HRESULT WINAPI ddraw7_EnumDisplayModes(IDirectDraw7 *iface, DWORD Flags,
1854 DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMMODESCALLBACK2 cb)
1856 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1857 unsigned int modenum, fmt;
1858 WINED3DFORMAT pixelformat = WINED3DFMT_UNKNOWN;
1859 WINED3DDISPLAYMODE mode;
1860 DDSURFACEDESC2 callback_sd;
1861 WINED3DDISPLAYMODE *enum_modes = NULL;
1862 unsigned enum_mode_count = 0, enum_mode_array_size = 0;
1864 WINED3DFORMAT checkFormatList[] =
1866 WINED3DFMT_B8G8R8X8_UNORM,
1867 WINED3DFMT_B5G6R5_UNORM,
1868 WINED3DFMT_P8_UINT,
1871 TRACE("(%p)->(%p,%p,%p): Relay\n", This, DDSD, Context, cb);
1873 EnterCriticalSection(&ddraw_cs);
1874 /* This looks sane */
1875 if(!cb)
1877 LeaveCriticalSection(&ddraw_cs);
1878 return DDERR_INVALIDPARAMS;
1881 if(DDSD)
1883 if ((DDSD->dwFlags & DDSD_PIXELFORMAT) && (DDSD->u4.ddpfPixelFormat.dwFlags & DDPF_RGB) )
1884 pixelformat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
1887 if(!(Flags & DDEDM_REFRESHRATES))
1889 enum_mode_array_size = 16;
1890 enum_modes = HeapAlloc(GetProcessHeap(), 0, sizeof(WINED3DDISPLAYMODE) * enum_mode_array_size);
1891 if (!enum_modes)
1893 ERR("Out of memory\n");
1894 LeaveCriticalSection(&ddraw_cs);
1895 return DDERR_OUTOFMEMORY;
1899 for(fmt = 0; fmt < (sizeof(checkFormatList) / sizeof(checkFormatList[0])); fmt++)
1901 if(pixelformat != WINED3DFMT_UNKNOWN && checkFormatList[fmt] != pixelformat)
1903 continue;
1906 modenum = 0;
1907 while(IWineD3D_EnumAdapterModes(This->wineD3D,
1908 WINED3DADAPTER_DEFAULT,
1909 checkFormatList[fmt],
1910 modenum++,
1911 &mode) == WINED3D_OK)
1913 if(DDSD)
1915 if(DDSD->dwFlags & DDSD_WIDTH && mode.Width != DDSD->dwWidth) continue;
1916 if(DDSD->dwFlags & DDSD_HEIGHT && mode.Height != DDSD->dwHeight) continue;
1919 if(!(Flags & DDEDM_REFRESHRATES))
1921 /* DX docs state EnumDisplayMode should return only unique modes. If DDEDM_REFRESHRATES is not set, refresh
1922 * rate doesn't matter when determining if the mode is unique. So modes only differing in refresh rate have
1923 * to be reduced to a single unique result in such case.
1925 BOOL found = FALSE;
1926 unsigned i;
1928 for (i = 0; i < enum_mode_count; i++)
1930 if(enum_modes[i].Width == mode.Width && enum_modes[i].Height == mode.Height &&
1931 enum_modes[i].Format == mode.Format)
1933 found = TRUE;
1934 break;
1938 if(found) continue;
1941 memset(&callback_sd, 0, sizeof(callback_sd));
1942 callback_sd.dwSize = sizeof(callback_sd);
1943 callback_sd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1945 callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH;
1946 if(Flags & DDEDM_REFRESHRATES)
1948 callback_sd.dwFlags |= DDSD_REFRESHRATE;
1949 callback_sd.u2.dwRefreshRate = mode.RefreshRate;
1952 callback_sd.dwWidth = mode.Width;
1953 callback_sd.dwHeight = mode.Height;
1955 PixelFormat_WineD3DtoDD(&callback_sd.u4.ddpfPixelFormat, mode.Format);
1957 /* Calc pitch and DWORD align like MSDN says */
1958 callback_sd.u1.lPitch = (callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount / 8) * mode.Width;
1959 callback_sd.u1.lPitch = (callback_sd.u1.lPitch + 3) & ~3;
1961 TRACE("Enumerating %dx%dx%d @%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
1962 callback_sd.u2.dwRefreshRate);
1964 if(cb(&callback_sd, Context) == DDENUMRET_CANCEL)
1966 TRACE("Application asked to terminate the enumeration\n");
1967 HeapFree(GetProcessHeap(), 0, enum_modes);
1968 LeaveCriticalSection(&ddraw_cs);
1969 return DD_OK;
1972 if(!(Flags & DDEDM_REFRESHRATES))
1974 if (enum_mode_count == enum_mode_array_size)
1976 WINED3DDISPLAYMODE *new_enum_modes;
1978 enum_mode_array_size *= 2;
1979 new_enum_modes = HeapReAlloc(GetProcessHeap(), 0, enum_modes, sizeof(WINED3DDISPLAYMODE) * enum_mode_array_size);
1981 if (!new_enum_modes)
1983 ERR("Out of memory\n");
1984 HeapFree(GetProcessHeap(), 0, enum_modes);
1985 LeaveCriticalSection(&ddraw_cs);
1986 return DDERR_OUTOFMEMORY;
1989 enum_modes = new_enum_modes;
1992 enum_modes[enum_mode_count++] = mode;
1997 TRACE("End of enumeration\n");
1998 HeapFree(GetProcessHeap(), 0, enum_modes);
1999 LeaveCriticalSection(&ddraw_cs);
2000 return DD_OK;
2003 static HRESULT WINAPI ddraw4_EnumDisplayModes(IDirectDraw4 *iface, DWORD flags,
2004 DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMMODESCALLBACK2 callback)
2006 TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2007 iface, flags, surface_desc, context, callback);
2009 return ddraw7_EnumDisplayModes((IDirectDraw7 *)ddraw_from_ddraw4(iface), flags,
2010 surface_desc, context, callback);
2013 static HRESULT WINAPI ddraw3_EnumDisplayModes(IDirectDraw3 *iface, DWORD flags,
2014 DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2016 struct displaymodescallback_context cbcontext;
2018 TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2019 iface, flags, surface_desc, context, callback);
2021 cbcontext.func = callback;
2022 cbcontext.context = context;
2024 return ddraw7_EnumDisplayModes((IDirectDraw7 *)ddraw_from_ddraw3(iface), flags,
2025 (DDSURFACEDESC2 *)surface_desc, &cbcontext, EnumDisplayModesCallbackThunk);
2028 static HRESULT WINAPI ddraw2_EnumDisplayModes(IDirectDraw2 *iface, DWORD flags,
2029 DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2031 struct displaymodescallback_context cbcontext;
2033 TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2034 iface, flags, surface_desc, context, callback);
2036 cbcontext.func = callback;
2037 cbcontext.context = context;
2039 return ddraw7_EnumDisplayModes((IDirectDraw7 *)ddraw_from_ddraw2(iface), flags,
2040 (DDSURFACEDESC2 *)surface_desc, &cbcontext, EnumDisplayModesCallbackThunk);
2043 static HRESULT WINAPI ddraw1_EnumDisplayModes(IDirectDraw *iface, DWORD flags,
2044 DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2046 struct displaymodescallback_context cbcontext;
2048 TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2049 iface, flags, surface_desc, context, callback);
2051 cbcontext.func = callback;
2052 cbcontext.context = context;
2054 return ddraw7_EnumDisplayModes((IDirectDraw7 *)ddraw_from_ddraw1(iface), flags,
2055 (DDSURFACEDESC2 *)surface_desc, &cbcontext, EnumDisplayModesCallbackThunk);
2058 /*****************************************************************************
2059 * IDirectDraw7::EvaluateMode
2061 * Used with IDirectDraw7::StartModeTest to test video modes.
2062 * EvaluateMode is used to pass or fail a mode, and continue with the next
2063 * mode
2065 * Params:
2066 * Flags: DDEM_MODEPASSED or DDEM_MODEFAILED
2067 * Timeout: Returns the amount of seconds left before the mode would have
2068 * been failed automatically
2070 * Returns:
2071 * This implementation always DD_OK, because it's a stub
2073 *****************************************************************************/
2074 static HRESULT WINAPI ddraw7_EvaluateMode(IDirectDraw7 *iface, DWORD Flags, DWORD *Timeout)
2076 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2077 FIXME("(%p)->(%d,%p): Stub!\n", This, Flags, Timeout);
2079 /* When implementing this, implement it in WineD3D */
2081 return DD_OK;
2084 /*****************************************************************************
2085 * IDirectDraw7::GetDeviceIdentifier
2087 * Returns the device identifier, which gives information about the driver
2088 * Our device identifier is defined at the beginning of this file.
2090 * Params:
2091 * DDDI: Address for the returned structure
2092 * Flags: Can be DDGDI_GETHOSTIDENTIFIER
2094 * Returns:
2095 * On success it returns DD_OK
2096 * DDERR_INVALIDPARAMS if DDDI is NULL
2098 *****************************************************************************/
2099 static HRESULT WINAPI ddraw7_GetDeviceIdentifier(IDirectDraw7 *iface,
2100 DDDEVICEIDENTIFIER2 *DDDI, DWORD Flags)
2102 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2103 TRACE("(%p)->(%p,%08x)\n", This, DDDI, Flags);
2105 if(!DDDI)
2106 return DDERR_INVALIDPARAMS;
2108 /* The DDGDI_GETHOSTIDENTIFIER returns the information about the 2D
2109 * host adapter, if there's a secondary 3D adapter. This doesn't apply
2110 * to any modern hardware, nor is it interesting for Wine, so ignore it.
2111 * Size of DDDEVICEIDENTIFIER2 may be aligned to 8 bytes and thus 4
2112 * bytes too long. So only copy the relevant part of the structure
2115 memcpy(DDDI, &deviceidentifier, FIELD_OFFSET(DDDEVICEIDENTIFIER2, dwWHQLLevel) + sizeof(DWORD));
2116 return DD_OK;
2119 static HRESULT WINAPI ddraw4_GetDeviceIdentifier(IDirectDraw4 *iface,
2120 DDDEVICEIDENTIFIER *identifier, DWORD flags)
2122 DDDEVICEIDENTIFIER2 identifier2;
2123 HRESULT hr;
2125 TRACE("iface %p, identifier %p, flags %#x.\n", iface, identifier, flags);
2127 hr = ddraw7_GetDeviceIdentifier((IDirectDraw7 *)ddraw_from_ddraw4(iface), &identifier2, flags);
2128 DDRAW_Convert_DDDEVICEIDENTIFIER_2_To_1(&identifier2, identifier);
2130 return hr;
2133 /*****************************************************************************
2134 * IDirectDraw7::GetSurfaceFromDC
2136 * Returns the Surface for a GDI device context handle.
2137 * Is this related to IDirectDrawSurface::GetDC ???
2139 * Params:
2140 * hdc: hdc to return the surface for
2141 * Surface: Address to write the surface pointer to
2143 * Returns:
2144 * Always returns DD_OK because it's a stub
2146 *****************************************************************************/
2147 static HRESULT WINAPI ddraw7_GetSurfaceFromDC(IDirectDraw7 *iface, HDC hdc, IDirectDrawSurface7 **Surface)
2149 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2150 IWineD3DSurface *wined3d_surface;
2151 HRESULT hr;
2153 TRACE("iface %p, dc %p, surface %p.\n", iface, hdc, Surface);
2155 if (!Surface) return E_INVALIDARG;
2157 hr = IWineD3DDevice_GetSurfaceFromDC(This->wineD3DDevice, hdc, &wined3d_surface);
2158 if (FAILED(hr))
2160 TRACE("No surface found for dc %p.\n", hdc);
2161 *Surface = NULL;
2162 return DDERR_NOTFOUND;
2165 IWineD3DSurface_GetParent(wined3d_surface, (IUnknown **)Surface);
2166 TRACE("Returning surface %p.\n", Surface);
2167 return DD_OK;
2170 static HRESULT WINAPI ddraw4_GetSurfaceFromDC(IDirectDraw4 *iface, HDC dc, IDirectDrawSurface4 **surface)
2172 IDirectDrawSurface7 *surface7;
2173 HRESULT hr;
2175 TRACE("iface %p, dc %p, surface %p.\n", iface, dc, surface);
2177 if (!surface) return E_INVALIDARG;
2179 hr = ddraw7_GetSurfaceFromDC((IDirectDraw7 *)ddraw_from_ddraw4(iface), dc, &surface7);
2180 *surface = surface7 ? (IDirectDrawSurface4 *)&((IDirectDrawSurfaceImpl *)surface7)->IDirectDrawSurface3_vtbl : NULL;
2182 return hr;
2185 static HRESULT WINAPI ddraw3_GetSurfaceFromDC(IDirectDraw3 *iface, HDC dc, IDirectDrawSurface **surface)
2187 TRACE("iface %p, dc %p, surface %p.\n", iface, dc, surface);
2189 return ddraw7_GetSurfaceFromDC((IDirectDraw7 *)ddraw_from_ddraw3(iface),
2190 dc, (IDirectDrawSurface7 **)surface);
2193 /*****************************************************************************
2194 * IDirectDraw7::RestoreAllSurfaces
2196 * Calls the restore method of all surfaces
2198 * Params:
2200 * Returns:
2201 * Always returns DD_OK because it's a stub
2203 *****************************************************************************/
2204 static HRESULT WINAPI ddraw7_RestoreAllSurfaces(IDirectDraw7 *iface)
2206 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2207 FIXME("(%p): Stub\n", This);
2209 /* This isn't hard to implement: Enumerate all WineD3D surfaces,
2210 * get their parent and call their restore method. Do not implement
2211 * it in WineD3D, as restoring a surface means re-creating the
2212 * WineD3DDSurface
2214 return DD_OK;
2217 static HRESULT WINAPI ddraw4_RestoreAllSurfaces(IDirectDraw4 *iface)
2219 TRACE("iface %p.\n", iface);
2221 return ddraw7_RestoreAllSurfaces((IDirectDraw7 *)ddraw_from_ddraw4(iface));
2224 /*****************************************************************************
2225 * IDirectDraw7::StartModeTest
2227 * Tests the specified video modes to update the system registry with
2228 * refresh rate information. StartModeTest starts the mode test,
2229 * EvaluateMode is used to fail or pass a mode. If EvaluateMode
2230 * isn't called within 15 seconds, the mode is failed automatically
2232 * As refresh rates are handled by the X server, I don't think this
2233 * Method is important
2235 * Params:
2236 * Modes: An array of mode specifications
2237 * NumModes: The number of modes in Modes
2238 * Flags: Some flags...
2240 * Returns:
2241 * Returns DDERR_TESTFINISHED if flags contains DDSMT_ISTESTREQUIRED,
2242 * if no modes are passed, DDERR_INVALIDPARAMS is returned,
2243 * otherwise DD_OK
2245 *****************************************************************************/
2246 static HRESULT WINAPI ddraw7_StartModeTest(IDirectDraw7 *iface, SIZE *Modes, DWORD NumModes, DWORD Flags)
2248 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2249 WARN("(%p)->(%p, %d, %x): Semi-Stub, most likely harmless\n", This, Modes, NumModes, Flags);
2251 /* This looks sane */
2252 if( (!Modes) || (NumModes == 0) ) return DDERR_INVALIDPARAMS;
2254 /* DDSMT_ISTESTREQUIRED asks if a mode test is necessary.
2255 * As it is not, DDERR_TESTFINISHED is returned
2256 * (hopefully that's correct
2258 if(Flags & DDSMT_ISTESTREQUIRED) return DDERR_TESTFINISHED;
2259 * well, that value doesn't (yet) exist in the wine headers, so ignore it
2262 return DD_OK;
2265 /*****************************************************************************
2266 * ddraw_recreate_surfaces_cb
2268 * Enumeration callback for ddraw_recreate_surface.
2269 * It re-recreates the WineD3DSurface. It's pretty straightforward
2271 *****************************************************************************/
2272 HRESULT WINAPI ddraw_recreate_surfaces_cb(IDirectDrawSurface7 *surf, DDSURFACEDESC2 *desc, void *Context)
2274 IDirectDrawSurfaceImpl *surfImpl = (IDirectDrawSurfaceImpl *)surf;
2275 IDirectDrawImpl *This = surfImpl->ddraw;
2276 IUnknown *Parent;
2277 IWineD3DSurface *wineD3DSurface;
2278 IWineD3DSwapChain *swapchain;
2279 HRESULT hr;
2280 IWineD3DClipper *clipper = NULL;
2282 WINED3DSURFACE_DESC Desc;
2283 WINED3DFORMAT Format;
2284 DWORD Usage;
2285 WINED3DPOOL Pool;
2287 WINED3DMULTISAMPLE_TYPE MultiSampleType;
2288 DWORD MultiSampleQuality;
2289 UINT Width;
2290 UINT Height;
2292 TRACE("(%p): Enumerated Surface %p\n", This, surfImpl);
2294 /* For the enumeration */
2295 IDirectDrawSurface7_Release(surf);
2297 if(surfImpl->ImplType == This->ImplType) return DDENUMRET_OK; /* Continue */
2299 /* Get the objects */
2300 swapchain = surfImpl->wineD3DSwapChain;
2301 surfImpl->wineD3DSwapChain = NULL;
2302 wineD3DSurface = surfImpl->WineD3DSurface;
2304 /* get the clipper */
2305 IWineD3DSurface_GetClipper(wineD3DSurface, &clipper);
2307 /* Get the surface properties */
2308 hr = IWineD3DSurface_GetDesc(wineD3DSurface, &Desc);
2309 if(hr != D3D_OK) return hr;
2311 Format = Desc.format;
2312 Usage = Desc.usage;
2313 Pool = Desc.pool;
2314 MultiSampleType = Desc.multisample_type;
2315 MultiSampleQuality = Desc.multisample_quality;
2316 Width = Desc.width;
2317 Height = Desc.height;
2319 IWineD3DSurface_GetParent(wineD3DSurface, &Parent);
2321 /* Create the new surface */
2322 hr = IWineD3DDevice_CreateSurface(This->wineD3DDevice, Width, Height, Format,
2323 TRUE /* Lockable */, FALSE /* Discard */, surfImpl->mipmap_level, &surfImpl->WineD3DSurface, Usage, Pool,
2324 MultiSampleType, MultiSampleQuality, This->ImplType, Parent, &ddraw_null_wined3d_parent_ops);
2325 IUnknown_Release(Parent);
2326 if (FAILED(hr))
2328 surfImpl->WineD3DSurface = wineD3DSurface;
2329 return hr;
2332 IWineD3DSurface_SetClipper(surfImpl->WineD3DSurface, clipper);
2334 /* TODO: Copy the surface content, except for render targets */
2336 /* If there's a swapchain, it owns the wined3d surfaces. So Destroy
2337 * the swapchain
2339 if(swapchain) {
2340 /* The backbuffers have the swapchain set as well, but the primary
2341 * owns it and destroys it
2343 if(surfImpl->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) {
2344 IWineD3DDevice_UninitGDI(This->wineD3DDevice, D3D7CB_DestroySwapChain);
2346 surfImpl->isRenderTarget = FALSE;
2347 } else {
2348 if(IWineD3DSurface_Release(wineD3DSurface) == 0)
2349 TRACE("Surface released successful, next surface\n");
2350 else
2351 ERR("Something's still holding the old WineD3DSurface\n");
2354 surfImpl->ImplType = This->ImplType;
2356 if(clipper)
2358 IWineD3DClipper_Release(clipper);
2360 return DDENUMRET_OK;
2363 /*****************************************************************************
2364 * ddraw_recreate_surfaces
2366 * A function, that converts all wineD3DSurfaces to the new implementation type
2367 * It enumerates all surfaces with IWineD3DDevice::EnumSurfaces, creates a
2368 * new WineD3DSurface, copies the content and releases the old surface
2370 *****************************************************************************/
2371 static HRESULT ddraw_recreate_surfaces(IDirectDrawImpl *This)
2373 DDSURFACEDESC2 desc;
2374 TRACE("(%p): Switch to implementation %d\n", This, This->ImplType);
2376 if(This->ImplType != SURFACE_OPENGL && This->d3d_initialized)
2378 /* Should happen almost never */
2379 FIXME("(%p) Switching to non-opengl surfaces with d3d started. Is this a bug?\n", This);
2380 /* Shutdown d3d */
2381 IWineD3DDevice_Uninit3D(This->wineD3DDevice, D3D7CB_DestroySwapChain);
2383 /* Contrary: D3D starting is handled by the caller, because it knows the render target */
2385 memset(&desc, 0, sizeof(desc));
2386 desc.dwSize = sizeof(desc);
2388 return IDirectDraw7_EnumSurfaces((IDirectDraw7 *)This, 0, &desc, This, ddraw_recreate_surfaces_cb);
2391 ULONG WINAPI D3D7CB_DestroySwapChain(IWineD3DSwapChain *pSwapChain) {
2392 IUnknown* swapChainParent;
2393 TRACE("(%p) call back\n", pSwapChain);
2395 IWineD3DSwapChain_GetParent(pSwapChain, &swapChainParent);
2396 IUnknown_Release(swapChainParent);
2397 return IUnknown_Release(swapChainParent);
2400 /*****************************************************************************
2401 * ddraw_create_surface
2403 * A helper function for IDirectDraw7::CreateSurface. It creates a new surface
2404 * with the passed parameters.
2406 * Params:
2407 * DDSD: Description of the surface to create
2408 * Surf: Address to store the interface pointer at
2410 * Returns:
2411 * DD_OK on success
2413 *****************************************************************************/
2414 static HRESULT ddraw_create_surface(IDirectDrawImpl *This, DDSURFACEDESC2 *pDDSD,
2415 IDirectDrawSurfaceImpl **ppSurf, UINT level)
2417 HRESULT hr;
2418 UINT Width, Height;
2419 WINED3DFORMAT Format = WINED3DFMT_UNKNOWN;
2420 DWORD Usage = 0;
2421 WINED3DSURFTYPE ImplType = This->ImplType;
2422 WINED3DSURFACE_DESC Desc;
2423 WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
2425 if (TRACE_ON(ddraw))
2427 TRACE(" (%p) Requesting surface desc :\n", This);
2428 DDRAW_dump_surface_desc(pDDSD);
2431 /* Select the surface type, if it wasn't choosen yet */
2432 if(ImplType == SURFACE_UNKNOWN)
2434 /* Use GL Surfaces if a D3DDEVICE Surface is requested */
2435 if(pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
2437 TRACE("(%p) Choosing GL surfaces because a 3DDEVICE Surface was requested\n", This);
2438 ImplType = SURFACE_OPENGL;
2441 /* Otherwise use GDI surfaces for now */
2442 else
2444 TRACE("(%p) Choosing GDI surfaces for 2D rendering\n", This);
2445 ImplType = SURFACE_GDI;
2448 /* Policy if all surface implementations are available:
2449 * First, check if a default type was set with winecfg. If not,
2450 * try Xrender surfaces, and use them if they work. Next, check if
2451 * accelerated OpenGL is available, and use GL surfaces in this
2452 * case. If all else fails, use GDI surfaces. If a 3DDEVICE surface
2453 * was created, always use OpenGL surfaces.
2455 * (Note: Xrender surfaces are not implemented for now, the
2456 * unaccelerated implementation uses GDI to render in Software)
2459 /* Store the type. If it needs to be changed, all WineD3DSurfaces have to
2460 * be re-created. This could be done with IDirectDrawSurface7::Restore
2462 This->ImplType = ImplType;
2464 else
2466 if ((pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
2467 && (This->ImplType != SURFACE_OPENGL)
2468 && DefaultSurfaceType == SURFACE_UNKNOWN)
2470 /* We have to change to OpenGL,
2471 * and re-create all WineD3DSurfaces
2473 ImplType = SURFACE_OPENGL;
2474 This->ImplType = ImplType;
2475 TRACE("(%p) Re-creating all surfaces\n", This);
2476 ddraw_recreate_surfaces(This);
2477 TRACE("(%p) Done recreating all surfaces\n", This);
2479 else if(This->ImplType != SURFACE_OPENGL && pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
2481 WARN("The application requests a 3D capable surface, but a non-opengl surface was set in the registry\n");
2482 /* Do not fail surface creation, only fail 3D device creation */
2486 if (!(pDDSD->ddsCaps.dwCaps & (DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY)) &&
2487 !((pDDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE) && (pDDSD->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) )
2489 /* Tests show surfaces without memory flags get these flags added right after creation. */
2490 pDDSD->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
2492 /* Get the correct wined3d usage */
2493 if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
2494 DDSCAPS_3DDEVICE ) )
2496 Usage |= WINED3DUSAGE_RENDERTARGET;
2498 pDDSD->ddsCaps.dwCaps |= DDSCAPS_VISIBLE;
2500 if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_OVERLAY))
2502 Usage |= WINED3DUSAGE_OVERLAY;
2504 if(This->depthstencil || (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) )
2506 /* The depth stencil creation callback sets this flag.
2507 * Set the WineD3D usage to let it know that it's a depth
2508 * Stencil surface.
2510 Usage |= WINED3DUSAGE_DEPTHSTENCIL;
2512 if(pDDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
2514 Pool = WINED3DPOOL_SYSTEMMEM;
2516 else if(pDDSD->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
2518 Pool = WINED3DPOOL_MANAGED;
2519 /* Managed textures have the system memory flag set */
2520 pDDSD->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
2522 else if(pDDSD->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
2524 /* Videomemory adds localvidmem, this is mutually exclusive with systemmemory
2525 * and texturemanage
2527 pDDSD->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM;
2530 Format = PixelFormat_DD2WineD3D(&pDDSD->u4.ddpfPixelFormat);
2531 if(Format == WINED3DFMT_UNKNOWN)
2533 ERR("Unsupported / Unknown pixelformat\n");
2534 return DDERR_INVALIDPIXELFORMAT;
2537 /* Create the Surface object */
2538 *ppSurf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectDrawSurfaceImpl));
2539 if(!*ppSurf)
2541 ERR("(%p) Error allocating memory for a surface\n", This);
2542 return DDERR_OUTOFVIDEOMEMORY;
2544 (*ppSurf)->lpVtbl = &IDirectDrawSurface7_Vtbl;
2545 (*ppSurf)->IDirectDrawSurface3_vtbl = &IDirectDrawSurface3_Vtbl;
2546 (*ppSurf)->IDirectDrawGammaControl_vtbl = &IDirectDrawGammaControl_Vtbl;
2547 (*ppSurf)->IDirect3DTexture2_vtbl = &IDirect3DTexture2_Vtbl;
2548 (*ppSurf)->IDirect3DTexture_vtbl = &IDirect3DTexture1_Vtbl;
2549 (*ppSurf)->ref = 1;
2550 (*ppSurf)->version = 7;
2551 TRACE("%p->version = %d\n", (*ppSurf), (*ppSurf)->version);
2552 (*ppSurf)->ddraw = This;
2553 (*ppSurf)->surface_desc.dwSize = sizeof(DDSURFACEDESC2);
2554 (*ppSurf)->surface_desc.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
2555 DD_STRUCT_COPY_BYSIZE(&(*ppSurf)->surface_desc, pDDSD);
2557 /* Surface attachments */
2558 (*ppSurf)->next_attached = NULL;
2559 (*ppSurf)->first_attached = *ppSurf;
2561 /* Needed to re-create the surface on an implementation change */
2562 (*ppSurf)->ImplType = ImplType;
2564 /* For D3DDevice creation */
2565 (*ppSurf)->isRenderTarget = FALSE;
2567 /* A trace message for debugging */
2568 TRACE("(%p) Created IDirectDrawSurface implementation structure at %p\n", This, *ppSurf);
2570 /* Now create the WineD3D Surface */
2571 hr = IWineD3DDevice_CreateSurface(This->wineD3DDevice, pDDSD->dwWidth, pDDSD->dwHeight, Format,
2572 TRUE /* Lockable */, FALSE /* Discard */, level, &(*ppSurf)->WineD3DSurface,
2573 Usage, Pool, WINED3DMULTISAMPLE_NONE, 0 /* MultiSampleQuality */, ImplType,
2574 (IUnknown *)*ppSurf, &ddraw_null_wined3d_parent_ops);
2576 if(hr != D3D_OK)
2578 ERR("IWineD3DDevice::CreateSurface failed. hr = %08x\n", hr);
2579 return hr;
2582 /* Increase the surface counter, and attach the surface */
2583 InterlockedIncrement(&This->surfaces);
2584 list_add_head(&This->surface_list, &(*ppSurf)->surface_list_entry);
2586 /* Here we could store all created surfaces in the DirectDrawImpl structure,
2587 * But this could also be delegated to WineDDraw, as it keeps track of all its
2588 * resources. Not implemented for now, as there are more important things ;)
2591 /* Get the pixel format of the WineD3DSurface and store it.
2592 * Don't use the Format choosen above, WineD3D might have
2593 * changed it
2595 (*ppSurf)->surface_desc.dwFlags |= DDSD_PIXELFORMAT;
2596 hr = IWineD3DSurface_GetDesc((*ppSurf)->WineD3DSurface, &Desc);
2597 if(hr != D3D_OK)
2599 ERR("IWineD3DSurface::GetDesc failed\n");
2600 IDirectDrawSurface7_Release( (IDirectDrawSurface7 *) *ppSurf);
2601 return hr;
2604 Format = Desc.format;
2605 Width = Desc.width;
2606 Height = Desc.height;
2608 if(Format == WINED3DFMT_UNKNOWN)
2610 FIXME("IWineD3DSurface::GetDesc returned WINED3DFMT_UNKNOWN\n");
2612 PixelFormat_WineD3DtoDD( &(*ppSurf)->surface_desc.u4.ddpfPixelFormat, Format);
2614 /* Anno 1602 stores the pitch right after surface creation, so make sure it's there.
2615 * I can't LockRect() the surface here because if OpenGL surfaces are in use, the
2616 * WineD3DDevice might not be usable for 3D yet, so an extra method was created.
2617 * TODO: Test other fourcc formats
2619 if(Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
2620 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5)
2622 (*ppSurf)->surface_desc.dwFlags |= DDSD_LINEARSIZE;
2623 if(Format == WINED3DFMT_DXT1)
2625 (*ppSurf)->surface_desc.u1.dwLinearSize = max(4, Width) * max(4, Height) / 2;
2627 else
2629 (*ppSurf)->surface_desc.u1.dwLinearSize = max(4, Width) * max(4, Height);
2632 else
2634 (*ppSurf)->surface_desc.dwFlags |= DDSD_PITCH;
2635 (*ppSurf)->surface_desc.u1.lPitch = IWineD3DSurface_GetPitch((*ppSurf)->WineD3DSurface);
2638 /* Application passed a color key? Set it! */
2639 if(pDDSD->dwFlags & DDSD_CKDESTOVERLAY)
2641 IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2642 DDCKEY_DESTOVERLAY,
2643 (WINEDDCOLORKEY *) &pDDSD->u3.ddckCKDestOverlay);
2645 if(pDDSD->dwFlags & DDSD_CKDESTBLT)
2647 IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2648 DDCKEY_DESTBLT,
2649 (WINEDDCOLORKEY *) &pDDSD->ddckCKDestBlt);
2651 if(pDDSD->dwFlags & DDSD_CKSRCOVERLAY)
2653 IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2654 DDCKEY_SRCOVERLAY,
2655 (WINEDDCOLORKEY *) &pDDSD->ddckCKSrcOverlay);
2657 if(pDDSD->dwFlags & DDSD_CKSRCBLT)
2659 IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2660 DDCKEY_SRCBLT,
2661 (WINEDDCOLORKEY *) &pDDSD->ddckCKSrcBlt);
2663 if ( pDDSD->dwFlags & DDSD_LPSURFACE)
2665 hr = IWineD3DSurface_SetMem((*ppSurf)->WineD3DSurface, pDDSD->lpSurface);
2666 if(hr != WINED3D_OK)
2668 /* No need for a trace here, wined3d does that for us */
2669 IDirectDrawSurface7_Release((IDirectDrawSurface7 *)*ppSurf);
2670 return hr;
2674 return DD_OK;
2676 /*****************************************************************************
2677 * CreateAdditionalSurfaces
2679 * Creates a new mipmap chain.
2681 * Params:
2682 * root: Root surface to attach the newly created chain to
2683 * count: number of surfaces to create
2684 * DDSD: Description of the surface. Intentionally not a pointer to avoid side
2685 * effects on the caller
2686 * CubeFaceRoot: Whether the new surface is a root of a cube map face. This
2687 * creates an additional surface without the mipmapping flags
2689 *****************************************************************************/
2690 static HRESULT
2691 CreateAdditionalSurfaces(IDirectDrawImpl *This,
2692 IDirectDrawSurfaceImpl *root,
2693 UINT count,
2694 DDSURFACEDESC2 DDSD,
2695 BOOL CubeFaceRoot)
2697 UINT i, j, level = 0;
2698 HRESULT hr;
2699 IDirectDrawSurfaceImpl *last = root;
2701 for(i = 0; i < count; i++)
2703 IDirectDrawSurfaceImpl *object2 = NULL;
2705 /* increase the mipmap level, but only if a mipmap is created
2706 * In this case, also halve the size
2708 if(DDSD.ddsCaps.dwCaps & DDSCAPS_MIPMAP && !CubeFaceRoot)
2710 level++;
2711 if(DDSD.dwWidth > 1) DDSD.dwWidth /= 2;
2712 if(DDSD.dwHeight > 1) DDSD.dwHeight /= 2;
2713 /* Set the mipmap sublevel flag according to msdn */
2714 DDSD.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
2716 else
2718 DDSD.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
2720 CubeFaceRoot = FALSE;
2722 hr = ddraw_create_surface(This, &DDSD, &object2, level);
2723 if(hr != DD_OK)
2725 return hr;
2728 /* Add the new surface to the complex attachment array */
2729 for(j = 0; j < MAX_COMPLEX_ATTACHED; j++)
2731 if(last->complex_array[j]) continue;
2732 last->complex_array[j] = object2;
2733 break;
2735 last = object2;
2737 /* Remove the (possible) back buffer cap from the new surface description,
2738 * because only one surface in the flipping chain is a back buffer, one
2739 * is a front buffer, the others are just primary surfaces.
2741 DDSD.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
2743 return DD_OK;
2746 /* Must set all attached surfaces (e.g. mipmaps) versions as well */
2747 static void ddraw_set_surface_version(IDirectDrawSurfaceImpl *surface, UINT version)
2749 unsigned int i;
2751 TRACE("surface %p, version %u -> %u.\n", surface, surface->version, version);
2753 surface->version = version;
2754 for (i = 0; i < MAX_COMPLEX_ATTACHED; ++i)
2756 if (!surface->complex_array[i]) break;
2757 ddraw_set_surface_version(surface->complex_array[i], version);
2759 while ((surface = surface->next_attached))
2761 ddraw_set_surface_version(surface, version);
2765 /*****************************************************************************
2766 * ddraw_attach_d3d_device
2768 * Initializes the D3D capabilities of WineD3D
2770 * Params:
2771 * primary: The primary surface for D3D
2773 * Returns
2774 * DD_OK on success,
2775 * DDERR_* otherwise
2777 *****************************************************************************/
2778 static HRESULT ddraw_attach_d3d_device(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *primary)
2780 WINED3DPRESENT_PARAMETERS localParameters;
2781 HWND window = ddraw->dest_window;
2782 HRESULT hr;
2784 TRACE("ddraw %p, primary %p.\n", ddraw, primary);
2786 if (!window || window == GetDesktopWindow())
2788 window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "Hidden D3D Window",
2789 WS_DISABLED, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
2790 NULL, NULL, NULL, NULL);
2791 if (!window)
2793 ERR("Failed to create window, last error %#x.\n", GetLastError());
2794 return E_FAIL;
2797 ShowWindow(window, SW_HIDE); /* Just to be sure */
2798 WARN("No window for the Direct3DDevice, created hidden window %p.\n", window);
2800 else
2802 TRACE("Using existing window %p for Direct3D rendering.\n", window);
2804 ddraw->d3d_window = window;
2806 /* Store the future Render Target surface */
2807 ddraw->d3d_target = primary;
2809 /* Use the surface description for the device parameters, not the device
2810 * settings. The application might render to an offscreen surface. */
2811 localParameters.BackBufferWidth = primary->surface_desc.dwWidth;
2812 localParameters.BackBufferHeight = primary->surface_desc.dwHeight;
2813 localParameters.BackBufferFormat = PixelFormat_DD2WineD3D(&primary->surface_desc.u4.ddpfPixelFormat);
2814 localParameters.BackBufferCount = (primary->surface_desc.dwFlags & DDSD_BACKBUFFERCOUNT)
2815 ? primary->surface_desc.dwBackBufferCount : 0;
2816 localParameters.MultiSampleType = WINED3DMULTISAMPLE_NONE;
2817 localParameters.MultiSampleQuality = 0;
2818 localParameters.SwapEffect = WINED3DSWAPEFFECT_COPY;
2819 localParameters.hDeviceWindow = window;
2820 localParameters.Windowed = !(ddraw->cooperative_level & DDSCL_FULLSCREEN);
2821 localParameters.EnableAutoDepthStencil = TRUE;
2822 localParameters.AutoDepthStencilFormat = WINED3DFMT_D16_UNORM;
2823 localParameters.Flags = 0;
2824 localParameters.FullScreen_RefreshRateInHz = WINED3DPRESENT_RATE_DEFAULT;
2825 localParameters.PresentationInterval = WINED3DPRESENT_INTERVAL_DEFAULT;
2827 /* Set this NOW, otherwise creating the depth stencil surface will cause a
2828 * recursive loop until ram or emulated video memory is full. */
2829 ddraw->d3d_initialized = TRUE;
2830 hr = IWineD3DDevice_Init3D(ddraw->wineD3DDevice, &localParameters);
2831 if (FAILED(hr))
2833 ddraw->d3d_target = NULL;
2834 ddraw->d3d_initialized = FALSE;
2835 return hr;
2838 ddraw->declArraySize = 2;
2839 ddraw->decls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw->decls) * ddraw->declArraySize);
2840 if (!ddraw->decls)
2842 ERR("Error allocating an array for the converted vertex decls.\n");
2843 ddraw->declArraySize = 0;
2844 hr = IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroySwapChain);
2845 return E_OUTOFMEMORY;
2848 TRACE("Successfully initialized 3D.\n");
2850 return DD_OK;
2853 static HRESULT ddraw_create_gdi_swapchain(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *primary)
2855 WINED3DPRESENT_PARAMETERS presentation_parameters;
2856 HWND window;
2857 HRESULT hr;
2859 window = ddraw->dest_window;
2861 memset(&presentation_parameters, 0, sizeof(presentation_parameters));
2863 /* Use the surface description for the device parameters, not the device
2864 * settings. The application might render to an offscreen surface. */
2865 presentation_parameters.BackBufferWidth = primary->surface_desc.dwWidth;
2866 presentation_parameters.BackBufferHeight = primary->surface_desc.dwHeight;
2867 presentation_parameters.BackBufferFormat = PixelFormat_DD2WineD3D(&primary->surface_desc.u4.ddpfPixelFormat);
2868 presentation_parameters.BackBufferCount = (primary->surface_desc.dwFlags & DDSD_BACKBUFFERCOUNT)
2869 ? primary->surface_desc.dwBackBufferCount : 0;
2870 presentation_parameters.MultiSampleType = WINED3DMULTISAMPLE_NONE;
2871 presentation_parameters.MultiSampleQuality = 0;
2872 presentation_parameters.SwapEffect = WINED3DSWAPEFFECT_FLIP;
2873 presentation_parameters.hDeviceWindow = window;
2874 presentation_parameters.Windowed = !(ddraw->cooperative_level & DDSCL_FULLSCREEN);
2875 presentation_parameters.EnableAutoDepthStencil = FALSE; /* Not on GDI swapchains */
2876 presentation_parameters.AutoDepthStencilFormat = 0;
2877 presentation_parameters.Flags = 0;
2878 presentation_parameters.FullScreen_RefreshRateInHz = WINED3DPRESENT_RATE_DEFAULT;
2879 presentation_parameters.PresentationInterval = WINED3DPRESENT_INTERVAL_DEFAULT;
2881 ddraw->d3d_target = primary;
2882 hr = IWineD3DDevice_InitGDI(ddraw->wineD3DDevice, &presentation_parameters);
2883 ddraw->d3d_target = NULL;
2884 if (FAILED(hr))
2886 WARN("Failed to initialize GDI ddraw implementation, hr %#x.\n", hr);
2887 primary->wineD3DSwapChain = NULL;
2890 return hr;
2893 /*****************************************************************************
2894 * IDirectDraw7::CreateSurface
2896 * Creates a new IDirectDrawSurface object and returns its interface.
2898 * The surface connections with wined3d are a bit tricky. Basically it works
2899 * like this:
2901 * |------------------------| |-----------------|
2902 * | DDraw surface | | WineD3DSurface |
2903 * | | | |
2904 * | WineD3DSurface |-------------->| |
2905 * | Child |<------------->| Parent |
2906 * |------------------------| |-----------------|
2908 * The DDraw surface is the parent of the wined3d surface, and it releases
2909 * the WineD3DSurface when the ddraw surface is destroyed.
2911 * However, for all surfaces which can be in a container in WineD3D,
2912 * we have to do this. These surfaces are usually complex surfaces,
2913 * so this concerns primary surfaces with a front and a back buffer,
2914 * and textures.
2916 * |------------------------| |-----------------|
2917 * | DDraw surface | | Container |
2918 * | | | |
2919 * | Child |<------------->| Parent |
2920 * | Texture |<------------->| |
2921 * | WineD3DSurface |<----| | Levels |<--|
2922 * | Complex connection | | | | |
2923 * |------------------------| | |-----------------| |
2924 * ^ | |
2925 * | | |
2926 * | | |
2927 * | |------------------| | |-----------------| |
2928 * | | IParent | |-------->| WineD3DSurface | |
2929 * | | | | | |
2930 * | | Child |<------------->| Parent | |
2931 * | | | | Container |<--|
2932 * | |------------------| |-----------------| |
2933 * | |
2934 * | |----------------------| |
2935 * | | DDraw surface 2 | |
2936 * | | | |
2937 * |<->| Complex root Child | |
2938 * | | Texture | |
2939 * | | WineD3DSurface |<----| |
2940 * | |----------------------| | |
2941 * | | |
2942 * | |---------------------| | |-----------------| |
2943 * | | IParent | |----->| WineD3DSurface | |
2944 * | | | | | |
2945 * | | Child |<---------->| Parent | |
2946 * | |---------------------| | Container |<--|
2947 * | |-----------------| |
2948 * | |
2949 * | ---More surfaces can follow--- |
2951 * The reason is that the IWineD3DSwapchain(render target container)
2952 * and the IWineD3DTexure(Texture container) release the parents
2953 * of their surface's children, but by releasing the complex root
2954 * the surfaces which are complexly attached to it are destroyed
2955 * too. See IDirectDrawSurface::Release for a more detailed
2956 * explanation.
2958 * Params:
2959 * DDSD: Description of the surface to create
2960 * Surf: Address to store the interface pointer at
2961 * UnkOuter: Basically for aggregation support, but ddraw doesn't support
2962 * aggregation, so it has to be NULL
2964 * Returns:
2965 * DD_OK on success
2966 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
2967 * DDERR_* if an error occurs
2969 *****************************************************************************/
2970 static HRESULT WINAPI ddraw7_CreateSurface(IDirectDraw7 *iface,
2971 DDSURFACEDESC2 *DDSD, IDirectDrawSurface7 **Surf, IUnknown *UnkOuter)
2973 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2974 IDirectDrawSurfaceImpl *object = NULL;
2975 HRESULT hr;
2976 LONG extra_surfaces = 0;
2977 DDSURFACEDESC2 desc2;
2978 WINED3DDISPLAYMODE Mode;
2979 const DWORD sysvidmem = DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
2981 TRACE("(%p)->(%p,%p,%p)\n", This, DDSD, Surf, UnkOuter);
2983 /* Some checks before we start */
2984 if (TRACE_ON(ddraw))
2986 TRACE(" (%p) Requesting surface desc :\n", This);
2987 DDRAW_dump_surface_desc(DDSD);
2989 EnterCriticalSection(&ddraw_cs);
2991 if (UnkOuter != NULL)
2993 FIXME("(%p) : outer != NULL?\n", This);
2994 LeaveCriticalSection(&ddraw_cs);
2995 return CLASS_E_NOAGGREGATION; /* unchecked */
2998 if (Surf == NULL)
3000 FIXME("(%p) You want to get back a surface? Don't give NULL ptrs!\n", This);
3001 LeaveCriticalSection(&ddraw_cs);
3002 return E_POINTER; /* unchecked */
3005 if (!(DDSD->dwFlags & DDSD_CAPS))
3007 /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
3008 DDSD->dwFlags |= DDSD_CAPS;
3011 if (DDSD->ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD)
3013 /* If the surface is of the 'alloconload' type, ignore the LPSURFACE field */
3014 DDSD->dwFlags &= ~DDSD_LPSURFACE;
3017 if ((DDSD->dwFlags & DDSD_LPSURFACE) && (DDSD->lpSurface == NULL))
3019 /* Frank Herbert's Dune specifies a null pointer for the surface, ignore the LPSURFACE field */
3020 WARN("(%p) Null surface pointer specified, ignore it!\n", This);
3021 DDSD->dwFlags &= ~DDSD_LPSURFACE;
3024 if((DDSD->ddsCaps.dwCaps & (DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE)) == (DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE) &&
3025 !(This->cooperative_level & DDSCL_EXCLUSIVE))
3027 TRACE("(%p): Attempt to create a flipable primary surface without DDSCL_EXCLUSIVE set\n", This);
3028 *Surf = NULL;
3029 LeaveCriticalSection(&ddraw_cs);
3030 return DDERR_NOEXCLUSIVEMODE;
3033 if(DDSD->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER)) {
3034 WARN("Application tried to create an explicit front or back buffer\n");
3035 LeaveCriticalSection(&ddraw_cs);
3036 return DDERR_INVALIDCAPS;
3039 if((DDSD->ddsCaps.dwCaps & sysvidmem) == sysvidmem)
3041 /* This is a special switch in ddrawex.dll, but not allowed in ddraw.dll */
3042 WARN("Application tries to put the surface in both system and video memory\n");
3043 LeaveCriticalSection(&ddraw_cs);
3044 *Surf = NULL;
3045 return DDERR_INVALIDCAPS;
3048 /* Check cube maps but only if the size includes them */
3049 if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
3051 if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES &&
3052 !(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
3054 WARN("Cube map faces requested without cube map flag\n");
3055 LeaveCriticalSection(&ddraw_cs);
3056 return DDERR_INVALIDCAPS;
3058 if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
3059 (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) == 0)
3061 WARN("Cube map without faces requested\n");
3062 LeaveCriticalSection(&ddraw_cs);
3063 return DDERR_INVALIDPARAMS;
3066 /* Quick tests confirm those can be created, but we don't do that yet */
3067 if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
3068 (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) != DDSCAPS2_CUBEMAP_ALLFACES)
3070 FIXME("Partial cube maps not supported yet\n");
3074 /* According to the msdn this flag is ignored by CreateSurface */
3075 if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
3076 DDSD->ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
3078 /* Modify some flags */
3079 memset(&desc2, 0, sizeof(desc2));
3080 desc2.dwSize = sizeof(desc2); /* For the struct copy */
3081 DD_STRUCT_COPY_BYSIZE(&desc2, DDSD);
3082 desc2.dwSize = sizeof(desc2); /* To override a possibly smaller size */
3083 desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT); /* Just to be sure */
3085 /* Get the video mode from WineD3D - we will need it */
3086 hr = IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
3087 0, /* Swapchain 0 */
3088 &Mode);
3089 if(FAILED(hr))
3091 ERR("Failed to read display mode from wined3d\n");
3092 switch(This->orig_bpp)
3094 case 8:
3095 Mode.Format = WINED3DFMT_P8_UINT;
3096 break;
3098 case 15:
3099 Mode.Format = WINED3DFMT_B5G5R5X1_UNORM;
3100 break;
3102 case 16:
3103 Mode.Format = WINED3DFMT_B5G6R5_UNORM;
3104 break;
3106 case 24:
3107 Mode.Format = WINED3DFMT_B8G8R8_UNORM;
3108 break;
3110 case 32:
3111 Mode.Format = WINED3DFMT_B8G8R8X8_UNORM;
3112 break;
3114 Mode.Width = This->orig_width;
3115 Mode.Height = This->orig_height;
3118 /* No pixelformat given? Use the current screen format */
3119 if(!(desc2.dwFlags & DDSD_PIXELFORMAT))
3121 desc2.dwFlags |= DDSD_PIXELFORMAT;
3122 desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT);
3124 /* Wait: It could be a Z buffer */
3125 if(desc2.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
3127 switch(desc2.u2.dwMipMapCount) /* Who had this glorious idea? */
3129 case 15:
3130 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_S1_UINT_D15_UNORM);
3131 break;
3132 case 16:
3133 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D16_UNORM);
3134 break;
3135 case 24:
3136 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_X8D24_UNORM);
3137 break;
3138 case 32:
3139 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D32_UNORM);
3140 break;
3141 default:
3142 ERR("Unknown Z buffer bit depth\n");
3145 else
3147 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, Mode.Format);
3151 /* No Width or no Height? Use the original screen size
3153 if(!(desc2.dwFlags & DDSD_WIDTH) ||
3154 !(desc2.dwFlags & DDSD_HEIGHT) )
3156 /* Invalid for non-render targets */
3157 if(!(desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
3159 WARN("Creating a non-Primary surface without Width or Height info, returning DDERR_INVALIDPARAMS\n");
3160 *Surf = NULL;
3161 LeaveCriticalSection(&ddraw_cs);
3162 return DDERR_INVALIDPARAMS;
3165 desc2.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
3166 desc2.dwWidth = Mode.Width;
3167 desc2.dwHeight = Mode.Height;
3170 /* Mipmap count fixes */
3171 if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
3173 if(desc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
3175 if(desc2.dwFlags & DDSD_MIPMAPCOUNT)
3177 /* Mipmap count is given, should not be 0 */
3178 if( desc2.u2.dwMipMapCount == 0 )
3180 LeaveCriticalSection(&ddraw_cs);
3181 return DDERR_INVALIDPARAMS;
3184 else
3186 /* Undocumented feature: Create sublevels until
3187 * either the width or the height is 1
3189 DWORD min = desc2.dwWidth < desc2.dwHeight ?
3190 desc2.dwWidth : desc2.dwHeight;
3191 desc2.u2.dwMipMapCount = 0;
3192 while( min )
3194 desc2.u2.dwMipMapCount += 1;
3195 min >>= 1;
3199 else
3201 /* Not-complex mipmap -> Mipmapcount = 1 */
3202 desc2.u2.dwMipMapCount = 1;
3204 extra_surfaces = desc2.u2.dwMipMapCount - 1;
3206 /* There's a mipmap count in the created surface in any case */
3207 desc2.dwFlags |= DDSD_MIPMAPCOUNT;
3209 /* If no mipmap is given, the texture has only one level */
3211 /* The first surface is a front buffer, the back buffer is created afterwards */
3212 if( (desc2.dwFlags & DDSD_CAPS) && (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) )
3214 desc2.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER;
3217 /* The root surface in a cube map is positive x */
3218 if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
3220 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
3221 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
3224 /* Create the first surface */
3225 hr = ddraw_create_surface(This, &desc2, &object, 0);
3226 if( hr != DD_OK)
3228 ERR("ddraw_create_surface failed, hr %#x.\n", hr);
3229 LeaveCriticalSection(&ddraw_cs);
3230 return hr;
3232 object->is_complex_root = TRUE;
3234 *Surf = (IDirectDrawSurface7 *)object;
3236 /* Create Additional surfaces if necessary
3237 * This applies to Primary surfaces which have a back buffer count
3238 * set, but not to mipmap textures. In case of Mipmap textures,
3239 * wineD3D takes care of the creation of additional surfaces
3241 if(DDSD->dwFlags & DDSD_BACKBUFFERCOUNT)
3243 extra_surfaces = DDSD->dwBackBufferCount;
3244 desc2.ddsCaps.dwCaps &= ~DDSCAPS_FRONTBUFFER; /* It's not a front buffer */
3245 desc2.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
3246 desc2.dwBackBufferCount = 0;
3249 hr = DD_OK;
3250 if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
3252 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
3253 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEZ;
3254 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
3255 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEZ;
3256 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEZ;
3257 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
3258 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEZ;
3259 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEY;
3260 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
3261 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEY;
3262 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEY;
3263 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
3264 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEY;
3265 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEX;
3266 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
3267 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEX;
3268 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
3271 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces, desc2, FALSE);
3272 if(hr != DD_OK)
3274 /* This destroys and possibly created surfaces too */
3275 IDirectDrawSurface_Release((IDirectDrawSurface7 *)object);
3276 LeaveCriticalSection(&ddraw_cs);
3277 return hr;
3280 /* If the implementation is OpenGL and there's no d3ddevice, attach a d3ddevice
3281 * But attach the d3ddevice only if the currently created surface was
3282 * a primary surface (2D app in 3D mode) or a 3DDEVICE surface (3D app)
3283 * The only case I can think of where this doesn't apply is when a
3284 * 2D app was configured by the user to run with OpenGL and it didn't create
3285 * the render target as first surface. In this case the render target creation
3286 * will cause the 3D init.
3288 if( (This->ImplType == SURFACE_OPENGL) && !(This->d3d_initialized) &&
3289 desc2.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE) )
3291 IDirectDrawSurfaceImpl *target = object, *surface;
3292 struct list *entry;
3294 /* Search for the primary to use as render target */
3295 LIST_FOR_EACH(entry, &This->surface_list)
3297 surface = LIST_ENTRY(entry, IDirectDrawSurfaceImpl, surface_list_entry);
3298 if((surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER)) ==
3299 (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER))
3301 /* found */
3302 target = surface;
3303 TRACE("Using primary %p as render target\n", target);
3304 break;
3308 TRACE("(%p) Attaching a D3DDevice, rendertarget = %p\n", This, target);
3309 hr = ddraw_attach_d3d_device(This, target);
3310 if (hr != D3D_OK)
3312 IDirectDrawSurfaceImpl *release_surf;
3313 ERR("ddraw_attach_d3d_device failed, hr %#x\n", hr);
3314 *Surf = NULL;
3316 /* The before created surface structures are in an incomplete state here.
3317 * WineD3D holds the reference on the IParents, and it released them on the failure
3318 * already. So the regular release method implementation would fail on the attempt
3319 * to destroy either the IParents or the swapchain. So free the surface here.
3320 * The surface structure here is a list, not a tree, because onscreen targets
3321 * cannot be cube textures
3323 while(object)
3325 release_surf = object;
3326 object = object->complex_array[0];
3327 ddraw_surface_destroy(release_surf);
3329 LeaveCriticalSection(&ddraw_cs);
3330 return hr;
3333 else if(!(This->d3d_initialized) && desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
3335 ddraw_create_gdi_swapchain(This, object);
3338 /* Addref the ddraw interface to keep an reference for each surface */
3339 IDirectDraw7_AddRef(iface);
3340 object->ifaceToRelease = (IUnknown *) iface;
3342 /* Create a WineD3DTexture if a texture was requested */
3343 if(desc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE)
3345 UINT levels;
3346 WINED3DFORMAT Format;
3347 WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
3349 This->tex_root = object;
3351 if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
3353 /* a mipmap is created, create enough levels */
3354 levels = desc2.u2.dwMipMapCount;
3356 else
3358 /* No mipmap is created, create one level */
3359 levels = 1;
3362 /* DDSCAPS_SYSTEMMEMORY textures are in WINED3DPOOL_SYSTEMMEM */
3363 if(DDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
3365 Pool = WINED3DPOOL_SYSTEMMEM;
3367 /* Should I forward the MANAGED cap to the managed pool ? */
3369 /* Get the format. It's set already by CreateNewSurface */
3370 Format = PixelFormat_DD2WineD3D(&object->surface_desc.u4.ddpfPixelFormat);
3372 /* The surfaces are already created, the callback only
3373 * passes the IWineD3DSurface to WineD3D
3375 if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
3377 hr = IWineD3DDevice_CreateCubeTexture(This->wineD3DDevice, DDSD->dwWidth /* Edgelength */,
3378 levels, 0 /* usage */, Format, Pool, (IWineD3DCubeTexture **)&object->wineD3DTexture,
3379 (IUnknown *)object, &ddraw_null_wined3d_parent_ops);
3381 else
3383 hr = IWineD3DDevice_CreateTexture(This->wineD3DDevice, DDSD->dwWidth, DDSD->dwHeight, levels,
3384 0 /* usage */, Format, Pool, (IWineD3DTexture **)&object->wineD3DTexture,
3385 (IUnknown *)object, &ddraw_null_wined3d_parent_ops);
3387 This->tex_root = NULL;
3390 LeaveCriticalSection(&ddraw_cs);
3391 return hr;
3394 static HRESULT WINAPI ddraw4_CreateSurface(IDirectDraw4 *iface,
3395 DDSURFACEDESC2 *surface_desc, IDirectDrawSurface4 **surface, IUnknown *outer_unknown)
3397 IDirectDrawImpl *ddraw = ddraw_from_ddraw4(iface);
3398 IDirectDrawSurfaceImpl *impl;
3399 HRESULT hr;
3401 TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3402 iface, surface_desc, surface, outer_unknown);
3404 hr = ddraw7_CreateSurface((IDirectDraw7 *)ddraw, surface_desc, (IDirectDrawSurface7 **)surface, outer_unknown);
3405 impl = (IDirectDrawSurfaceImpl *)*surface;
3406 if (SUCCEEDED(hr) && impl)
3408 ddraw_set_surface_version(impl, 4);
3409 IDirectDraw7_Release((IDirectDraw7 *)ddraw);
3410 IDirectDraw4_AddRef(iface);
3411 impl->ifaceToRelease = (IUnknown *)iface;
3414 return hr;
3417 static HRESULT WINAPI ddraw3_CreateSurface(IDirectDraw3 *iface,
3418 DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
3420 IDirectDrawImpl *ddraw = ddraw_from_ddraw3(iface);
3421 IDirectDrawSurface7 *surface7;
3422 IDirectDrawSurfaceImpl *impl;
3423 HRESULT hr;
3425 TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3426 iface, surface_desc, surface, outer_unknown);
3428 hr = ddraw7_CreateSurface((IDirectDraw7 *)ddraw, (DDSURFACEDESC2 *)surface_desc, &surface7, outer_unknown);
3429 if (FAILED(hr))
3431 *surface = NULL;
3432 return hr;
3435 impl = (IDirectDrawSurfaceImpl *)surface7;
3436 *surface = (IDirectDrawSurface *)&impl->IDirectDrawSurface3_vtbl;
3437 ddraw_set_surface_version(impl, 3);
3438 IDirectDraw7_Release((IDirectDraw7 *)ddraw);
3439 IDirectDraw3_AddRef(iface);
3440 impl->ifaceToRelease = (IUnknown *)iface;
3442 return hr;
3445 static HRESULT WINAPI ddraw2_CreateSurface(IDirectDraw2 *iface,
3446 DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
3448 IDirectDrawImpl *ddraw = ddraw_from_ddraw2(iface);
3449 IDirectDrawSurface7 *surface7;
3450 IDirectDrawSurfaceImpl *impl;
3451 HRESULT hr;
3453 TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3454 iface, surface_desc, surface, outer_unknown);
3456 hr = ddraw7_CreateSurface((IDirectDraw7 *)ddraw, (DDSURFACEDESC2 *)surface_desc, &surface7, outer_unknown);
3457 if (FAILED(hr))
3459 *surface = NULL;
3460 return hr;
3463 impl = (IDirectDrawSurfaceImpl *)surface7;
3464 *surface = (IDirectDrawSurface *)&impl->IDirectDrawSurface3_vtbl;
3465 ddraw_set_surface_version(impl, 2);
3466 IDirectDraw7_Release((IDirectDraw7 *)ddraw);
3467 impl->ifaceToRelease = NULL;
3469 return hr;
3472 static HRESULT WINAPI ddraw1_CreateSurface(IDirectDraw *iface,
3473 DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
3475 IDirectDrawImpl *ddraw = ddraw_from_ddraw1(iface);
3476 IDirectDrawSurface7 *surface7;
3477 IDirectDrawSurfaceImpl *impl;
3478 HRESULT hr;
3480 TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3481 iface, surface_desc, surface, outer_unknown);
3483 /* Remove front buffer flag, this causes failure in v7, and its added to normal
3484 * primaries anyway. */
3485 surface_desc->ddsCaps.dwCaps &= ~DDSCAPS_FRONTBUFFER;
3486 hr = ddraw7_CreateSurface((IDirectDraw7 *)ddraw, (DDSURFACEDESC2 *)surface_desc, &surface7, outer_unknown);
3487 if (FAILED(hr))
3489 *surface = NULL;
3490 return hr;
3493 impl = (IDirectDrawSurfaceImpl *)surface7;
3494 *surface = (IDirectDrawSurface *)&impl->IDirectDrawSurface3_vtbl;
3495 ddraw_set_surface_version(impl, 1);
3496 IDirectDraw7_Release((IDirectDraw7 *)ddraw);
3497 impl->ifaceToRelease = NULL;
3499 return hr;
3502 #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST)
3503 #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH)
3505 static BOOL
3506 Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
3507 const DDPIXELFORMAT *provided)
3509 /* Some flags must be present in both or neither for a match. */
3510 static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
3511 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
3512 | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
3514 if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
3515 return FALSE;
3517 if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
3518 return FALSE;
3520 if (requested->dwFlags & DDPF_FOURCC)
3521 if (requested->dwFourCC != provided->dwFourCC)
3522 return FALSE;
3524 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
3525 |DDPF_LUMINANCE|DDPF_BUMPDUDV))
3526 if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
3527 return FALSE;
3529 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
3530 |DDPF_LUMINANCE|DDPF_BUMPDUDV))
3531 if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
3532 return FALSE;
3534 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
3535 if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
3536 return FALSE;
3538 /* I could be wrong about the bumpmapping. MSDN docs are vague. */
3539 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
3540 |DDPF_BUMPDUDV))
3541 if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
3542 return FALSE;
3544 if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
3545 if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
3546 return FALSE;
3548 return TRUE;
3551 static BOOL ddraw_match_surface_desc(const DDSURFACEDESC2 *requested, const DDSURFACEDESC2 *provided)
3553 struct compare_info
3555 DWORD flag;
3556 ptrdiff_t offset;
3557 size_t size;
3560 #define CMP(FLAG, FIELD) \
3561 { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
3562 sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
3564 static const struct compare_info compare[] =
3566 CMP(ALPHABITDEPTH, dwAlphaBitDepth),
3567 CMP(BACKBUFFERCOUNT, dwBackBufferCount),
3568 CMP(CAPS, ddsCaps),
3569 CMP(CKDESTBLT, ddckCKDestBlt),
3570 CMP(CKDESTOVERLAY, u3 /* ddckCKDestOverlay */),
3571 CMP(CKSRCBLT, ddckCKSrcBlt),
3572 CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
3573 CMP(HEIGHT, dwHeight),
3574 CMP(LINEARSIZE, u1 /* dwLinearSize */),
3575 CMP(LPSURFACE, lpSurface),
3576 CMP(MIPMAPCOUNT, u2 /* dwMipMapCount */),
3577 CMP(PITCH, u1 /* lPitch */),
3578 /* PIXELFORMAT: manual */
3579 CMP(REFRESHRATE, u2 /* dwRefreshRate */),
3580 CMP(TEXTURESTAGE, dwTextureStage),
3581 CMP(WIDTH, dwWidth),
3582 /* ZBUFFERBITDEPTH: "obsolete" */
3585 #undef CMP
3587 unsigned int i;
3589 if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
3590 return FALSE;
3592 for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++)
3594 if (requested->dwFlags & compare[i].flag
3595 && memcmp((const char *)provided + compare[i].offset,
3596 (const char *)requested + compare[i].offset,
3597 compare[i].size) != 0)
3598 return FALSE;
3601 if (requested->dwFlags & DDSD_PIXELFORMAT)
3603 if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
3604 &provided->u4.ddpfPixelFormat))
3605 return FALSE;
3608 return TRUE;
3611 #undef DDENUMSURFACES_SEARCHTYPE
3612 #undef DDENUMSURFACES_MATCHTYPE
3614 struct surfacescallback_context
3616 LPDDENUMSURFACESCALLBACK func;
3617 void *context;
3620 static HRESULT CALLBACK EnumSurfacesCallbackThunk(IDirectDrawSurface7 *surface,
3621 DDSURFACEDESC2 *surface_desc, void *context)
3623 struct surfacescallback_context *cbcontext = context;
3625 return cbcontext->func((IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)surface)->IDirectDrawSurface3_vtbl,
3626 (DDSURFACEDESC *)surface_desc, cbcontext->context);
3629 /*****************************************************************************
3630 * IDirectDraw7::EnumSurfaces
3632 * Loops through all surfaces attached to this device and calls the
3633 * application callback. This can't be relayed to WineD3DDevice,
3634 * because some WineD3DSurfaces' parents are IParent objects
3636 * Params:
3637 * Flags: Some filtering flags. See IDirectDrawImpl_EnumSurfacesCallback
3638 * DDSD: Description to filter for
3639 * Context: Application-provided pointer, it's passed unmodified to the
3640 * Callback function
3641 * Callback: Address to call for each surface
3643 * Returns:
3644 * DDERR_INVALIDPARAMS if the callback is NULL
3645 * DD_OK on success
3647 *****************************************************************************/
3648 static HRESULT WINAPI ddraw7_EnumSurfaces(IDirectDraw7 *iface, DWORD Flags,
3649 DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMSURFACESCALLBACK7 Callback)
3651 /* The surface enumeration is handled by WineDDraw,
3652 * because it keeps track of all surfaces attached to
3653 * it. The filtering is done by our callback function,
3654 * because WineDDraw doesn't handle ddraw-like surface
3655 * caps structures
3657 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
3658 IDirectDrawSurfaceImpl *surf;
3659 BOOL all, nomatch;
3660 DDSURFACEDESC2 desc;
3661 struct list *entry, *entry2;
3663 all = Flags & DDENUMSURFACES_ALL;
3664 nomatch = Flags & DDENUMSURFACES_NOMATCH;
3666 TRACE("(%p)->(%x,%p,%p,%p)\n", This, Flags, DDSD, Context, Callback);
3667 EnterCriticalSection(&ddraw_cs);
3669 if(!Callback)
3671 LeaveCriticalSection(&ddraw_cs);
3672 return DDERR_INVALIDPARAMS;
3675 /* Use the _SAFE enumeration, the app may destroy enumerated surfaces */
3676 LIST_FOR_EACH_SAFE(entry, entry2, &This->surface_list)
3678 surf = LIST_ENTRY(entry, IDirectDrawSurfaceImpl, surface_list_entry);
3679 if (all || (nomatch != ddraw_match_surface_desc(DDSD, &surf->surface_desc)))
3681 desc = surf->surface_desc;
3682 IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)surf);
3683 if (Callback((IDirectDrawSurface7 *)surf, &desc, Context) != DDENUMRET_OK)
3685 LeaveCriticalSection(&ddraw_cs);
3686 return DD_OK;
3690 LeaveCriticalSection(&ddraw_cs);
3691 return DD_OK;
3694 static HRESULT WINAPI ddraw4_EnumSurfaces(IDirectDraw4 *iface, DWORD flags,
3695 DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMSURFACESCALLBACK2 callback)
3697 TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3698 iface, flags, surface_desc, context, callback);
3700 return ddraw7_EnumSurfaces((IDirectDraw7 *)ddraw_from_ddraw4(iface),
3701 flags, surface_desc, context, (LPDDENUMSURFACESCALLBACK7)callback);
3704 static HRESULT WINAPI ddraw3_EnumSurfaces(IDirectDraw3 *iface, DWORD flags,
3705 DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3707 struct surfacescallback_context cbcontext;
3709 TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3710 iface, flags, surface_desc, context, callback);
3712 cbcontext.func = callback;
3713 cbcontext.context = context;
3715 return ddraw7_EnumSurfaces((IDirectDraw7 *)ddraw_from_ddraw3(iface), flags,
3716 (DDSURFACEDESC2 *)surface_desc, &cbcontext, EnumSurfacesCallbackThunk);
3719 static HRESULT WINAPI ddraw2_EnumSurfaces(IDirectDraw2 *iface, DWORD flags,
3720 DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3722 struct surfacescallback_context cbcontext;
3724 TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3725 iface, flags, surface_desc, context, callback);
3727 cbcontext.func = callback;
3728 cbcontext.context = context;
3730 return ddraw7_EnumSurfaces((IDirectDraw7 *)ddraw_from_ddraw2(iface), flags,
3731 (DDSURFACEDESC2 *)surface_desc, &cbcontext, EnumSurfacesCallbackThunk);
3734 static HRESULT WINAPI ddraw1_EnumSurfaces(IDirectDraw *iface, DWORD flags,
3735 DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3737 struct surfacescallback_context cbcontext;
3739 TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3740 iface, flags, surface_desc, context, callback);
3742 cbcontext.func = callback;
3743 cbcontext.context = context;
3745 return ddraw7_EnumSurfaces((IDirectDraw7 *)ddraw_from_ddraw1(iface), flags,
3746 (DDSURFACEDESC2 *)surface_desc, &cbcontext, EnumSurfacesCallbackThunk);
3749 /*****************************************************************************
3750 * DirectDrawCreateClipper (DDRAW.@)
3752 * Creates a new IDirectDrawClipper object.
3754 * Params:
3755 * Clipper: Address to write the interface pointer to
3756 * UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3757 * NULL
3759 * Returns:
3760 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
3761 * E_OUTOFMEMORY if allocating the object failed
3763 *****************************************************************************/
3764 HRESULT WINAPI
3765 DirectDrawCreateClipper(DWORD Flags,
3766 LPDIRECTDRAWCLIPPER *Clipper,
3767 IUnknown *UnkOuter)
3769 IDirectDrawClipperImpl* object;
3770 TRACE("(%08x,%p,%p)\n", Flags, Clipper, UnkOuter);
3772 EnterCriticalSection(&ddraw_cs);
3773 if (UnkOuter != NULL)
3775 LeaveCriticalSection(&ddraw_cs);
3776 return CLASS_E_NOAGGREGATION;
3779 if (!LoadWineD3D())
3781 LeaveCriticalSection(&ddraw_cs);
3782 return DDERR_NODIRECTDRAWSUPPORT;
3785 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3786 sizeof(IDirectDrawClipperImpl));
3787 if (object == NULL)
3789 LeaveCriticalSection(&ddraw_cs);
3790 return E_OUTOFMEMORY;
3793 object->lpVtbl = &IDirectDrawClipper_Vtbl;
3794 object->ref = 1;
3795 object->wineD3DClipper = pWineDirect3DCreateClipper((IUnknown *) object);
3796 if(!object->wineD3DClipper)
3798 HeapFree(GetProcessHeap(), 0, object);
3799 LeaveCriticalSection(&ddraw_cs);
3800 return E_OUTOFMEMORY;
3803 *Clipper = (IDirectDrawClipper *) object;
3804 LeaveCriticalSection(&ddraw_cs);
3805 return DD_OK;
3808 /*****************************************************************************
3809 * IDirectDraw7::CreateClipper
3811 * Creates a DDraw clipper. See DirectDrawCreateClipper for details
3813 *****************************************************************************/
3814 static HRESULT WINAPI ddraw7_CreateClipper(IDirectDraw7 *iface, DWORD Flags,
3815 IDirectDrawClipper **Clipper, IUnknown *UnkOuter)
3817 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
3818 TRACE("(%p)->(%x,%p,%p)\n", This, Flags, Clipper, UnkOuter);
3819 return DirectDrawCreateClipper(Flags, Clipper, UnkOuter);
3822 static HRESULT WINAPI ddraw4_CreateClipper(IDirectDraw4 *iface,
3823 DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3825 TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3826 iface, flags, clipper, outer_unknown);
3828 return ddraw7_CreateClipper((IDirectDraw7 *)ddraw_from_ddraw4(iface), flags, clipper, outer_unknown);
3831 static HRESULT WINAPI ddraw3_CreateClipper(IDirectDraw3 *iface,
3832 DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3834 TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3835 iface, flags, clipper, outer_unknown);
3837 return ddraw7_CreateClipper((IDirectDraw7 *)ddraw_from_ddraw3(iface), flags, clipper, outer_unknown);
3840 static HRESULT WINAPI ddraw2_CreateClipper(IDirectDraw2 *iface,
3841 DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3843 TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3844 iface, flags, clipper, outer_unknown);
3846 return ddraw7_CreateClipper((IDirectDraw7 *)ddraw_from_ddraw2(iface), flags, clipper, outer_unknown);
3849 static HRESULT WINAPI ddraw1_CreateClipper(IDirectDraw *iface,
3850 DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3852 TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3853 iface, flags, clipper, outer_unknown);
3855 return ddraw7_CreateClipper((IDirectDraw7 *)ddraw_from_ddraw1(iface), flags, clipper, outer_unknown);
3858 /*****************************************************************************
3859 * IDirectDraw7::CreatePalette
3861 * Creates a new IDirectDrawPalette object
3863 * Params:
3864 * Flags: The flags for the new clipper
3865 * ColorTable: Color table to assign to the new clipper
3866 * Palette: Address to write the interface pointer to
3867 * UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3868 * NULL
3870 * Returns:
3871 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
3872 * E_OUTOFMEMORY if allocating the object failed
3874 *****************************************************************************/
3875 static HRESULT WINAPI ddraw7_CreatePalette(IDirectDraw7 *iface, DWORD Flags,
3876 PALETTEENTRY *ColorTable, IDirectDrawPalette **Palette, IUnknown *pUnkOuter)
3878 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
3879 IDirectDrawPaletteImpl *object;
3880 HRESULT hr = DDERR_GENERIC;
3881 TRACE("(%p)->(%x,%p,%p,%p)\n", This, Flags, ColorTable, Palette, pUnkOuter);
3883 EnterCriticalSection(&ddraw_cs);
3884 if(pUnkOuter != NULL)
3886 WARN("pUnkOuter is %p, returning CLASS_E_NOAGGREGATION\n", pUnkOuter);
3887 LeaveCriticalSection(&ddraw_cs);
3888 return CLASS_E_NOAGGREGATION;
3891 /* The refcount test shows that a cooplevel is required for this */
3892 if(!This->cooperative_level)
3894 WARN("No cooperative level set, returning DDERR_NOCOOPERATIVELEVELSET\n");
3895 LeaveCriticalSection(&ddraw_cs);
3896 return DDERR_NOCOOPERATIVELEVELSET;
3899 object = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectDrawPaletteImpl));
3900 if(!object)
3902 ERR("Out of memory when allocating memory for a palette implementation\n");
3903 LeaveCriticalSection(&ddraw_cs);
3904 return E_OUTOFMEMORY;
3907 object->lpVtbl = &IDirectDrawPalette_Vtbl;
3908 object->ref = 1;
3910 hr = IWineD3DDevice_CreatePalette(This->wineD3DDevice, Flags,
3911 ColorTable, &object->wineD3DPalette, (IUnknown *)object);
3912 if(hr != DD_OK)
3914 HeapFree(GetProcessHeap(), 0, object);
3915 LeaveCriticalSection(&ddraw_cs);
3916 return hr;
3919 IDirectDraw7_AddRef(iface);
3920 object->ifaceToRelease = (IUnknown *) iface;
3921 *Palette = (IDirectDrawPalette *)object;
3922 LeaveCriticalSection(&ddraw_cs);
3923 return DD_OK;
3926 static HRESULT WINAPI ddraw4_CreatePalette(IDirectDraw4 *iface, DWORD flags,
3927 PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3929 IDirectDrawImpl *ddraw = ddraw_from_ddraw4(iface);
3930 HRESULT hr;
3932 TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3933 iface, flags, entries, palette, outer_unknown);
3935 hr = ddraw7_CreatePalette((IDirectDraw7 *)ddraw, flags, entries, palette, outer_unknown);
3936 if (SUCCEEDED(hr) && *palette)
3938 IDirectDrawPaletteImpl *impl = (IDirectDrawPaletteImpl *)*palette;
3939 IDirectDraw7_Release((IDirectDraw7 *)ddraw);
3940 IDirectDraw4_AddRef(iface);
3941 impl->ifaceToRelease = (IUnknown *)iface;
3943 return hr;
3946 static HRESULT WINAPI ddraw3_CreatePalette(IDirectDraw3 *iface, DWORD flags,
3947 PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3949 IDirectDrawImpl *ddraw = ddraw_from_ddraw3(iface);
3950 HRESULT hr;
3952 TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3953 iface, flags, entries, palette, outer_unknown);
3955 hr = ddraw7_CreatePalette((IDirectDraw7 *)ddraw, flags, entries, palette, outer_unknown);
3956 if (SUCCEEDED(hr) && *palette)
3958 IDirectDrawPaletteImpl *impl = (IDirectDrawPaletteImpl *)*palette;
3959 IDirectDraw7_Release((IDirectDraw7 *)ddraw);
3960 IDirectDraw4_AddRef(iface);
3961 impl->ifaceToRelease = (IUnknown *)iface;
3964 return hr;
3967 static HRESULT WINAPI ddraw2_CreatePalette(IDirectDraw2 *iface, DWORD flags,
3968 PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3970 IDirectDrawImpl *ddraw = ddraw_from_ddraw2(iface);
3971 HRESULT hr;
3973 TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3974 iface, flags, entries, palette, outer_unknown);
3976 hr = ddraw7_CreatePalette((IDirectDraw7 *)ddraw, flags, entries, palette, outer_unknown);
3977 if (SUCCEEDED(hr) && *palette)
3979 IDirectDrawPaletteImpl *impl = (IDirectDrawPaletteImpl *)*palette;
3980 IDirectDraw7_Release((IDirectDraw7 *)ddraw);
3981 impl->ifaceToRelease = NULL;
3984 return hr;
3987 static HRESULT WINAPI ddraw1_CreatePalette(IDirectDraw *iface, DWORD flags,
3988 PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3990 IDirectDrawImpl *ddraw = ddraw_from_ddraw1(iface);
3991 HRESULT hr;
3993 TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3994 iface, flags, entries, palette, outer_unknown);
3996 hr = ddraw7_CreatePalette((IDirectDraw7 *)ddraw, flags, entries, palette, outer_unknown);
3997 if (SUCCEEDED(hr) && *palette)
3999 IDirectDrawPaletteImpl *impl = (IDirectDrawPaletteImpl *)*palette;
4000 IDirectDraw7_Release((IDirectDraw7 *)ddraw);
4001 impl->ifaceToRelease = NULL;
4004 return hr;
4007 /*****************************************************************************
4008 * IDirectDraw7::DuplicateSurface
4010 * Duplicates a surface. The surface memory points to the same memory as
4011 * the original surface, and it's released when the last surface referencing
4012 * it is released. I guess that's beyond Wine's surface management right now
4013 * (Idea: create a new DDraw surface with the same WineD3DSurface. I need a
4014 * test application to implement this)
4016 * Params:
4017 * Src: Address of the source surface
4018 * Dest: Address to write the new surface pointer to
4020 * Returns:
4021 * See IDirectDraw7::CreateSurface
4023 *****************************************************************************/
4024 static HRESULT WINAPI ddraw7_DuplicateSurface(IDirectDraw7 *iface,
4025 IDirectDrawSurface7 *Src, IDirectDrawSurface7 **Dest)
4027 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
4028 IDirectDrawSurfaceImpl *Surf = (IDirectDrawSurfaceImpl *)Src;
4030 FIXME("(%p)->(%p,%p)\n", This, Surf, Dest);
4032 /* For now, simply create a new, independent surface */
4033 return IDirectDraw7_CreateSurface(iface,
4034 &Surf->surface_desc,
4035 Dest,
4036 NULL);
4039 static HRESULT WINAPI ddraw4_DuplicateSurface(IDirectDraw4 *iface,
4040 IDirectDrawSurface4 *src, IDirectDrawSurface4 **dst)
4042 TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
4044 return ddraw7_DuplicateSurface((IDirectDraw7 *)ddraw_from_ddraw4(iface),
4045 (IDirectDrawSurface7 *)src, (IDirectDrawSurface7 **)dst);
4048 static HRESULT WINAPI ddraw3_DuplicateSurface(IDirectDraw3 *iface,
4049 IDirectDrawSurface *src, IDirectDrawSurface **dst)
4051 IDirectDrawSurface7 *src7, *dst7;
4052 HRESULT hr;
4054 TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
4056 src7 = src ? (IDirectDrawSurface7 *)surface_from_surface3((IDirectDrawSurface3 *)src) : NULL;
4057 hr = ddraw7_DuplicateSurface((IDirectDraw7 *)ddraw_from_ddraw3(iface), src7, &dst7);
4058 *dst = dst7 ? (IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)dst7)->IDirectDrawSurface3_vtbl : NULL;
4060 return hr;
4063 static HRESULT WINAPI ddraw2_DuplicateSurface(IDirectDraw2 *iface,
4064 IDirectDrawSurface *src, IDirectDrawSurface **dst)
4066 IDirectDrawSurface7 *src7, *dst7;
4067 HRESULT hr;
4069 TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
4071 src7 = src ? (IDirectDrawSurface7 *)surface_from_surface3((IDirectDrawSurface3 *)src) : NULL;
4072 hr = ddraw7_DuplicateSurface((IDirectDraw7 *)ddraw_from_ddraw2(iface), src7, &dst7);
4073 *dst = dst7 ? (IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)dst7)->IDirectDrawSurface3_vtbl : NULL;
4075 return hr;
4078 static HRESULT WINAPI ddraw1_DuplicateSurface(IDirectDraw *iface,
4079 IDirectDrawSurface *src, IDirectDrawSurface **dst)
4081 IDirectDrawSurface7 *src7, *dst7;
4082 HRESULT hr;
4084 TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
4086 src7 = src ? (IDirectDrawSurface7 *)surface_from_surface3((IDirectDrawSurface3 *)src) : NULL;
4087 hr = ddraw7_DuplicateSurface((IDirectDraw7 *)ddraw_from_ddraw1(iface), src7, &dst7);
4088 *dst = dst7 ? (IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)dst7)->IDirectDrawSurface3_vtbl : NULL;
4090 return hr;
4093 /*****************************************************************************
4094 * IDirectDraw7 VTable
4095 *****************************************************************************/
4096 const IDirectDraw7Vtbl IDirectDraw7_Vtbl =
4098 /* IUnknown */
4099 ddraw7_QueryInterface,
4100 ddraw7_AddRef,
4101 ddraw7_Release,
4102 /* IDirectDraw */
4103 ddraw7_Compact,
4104 ddraw7_CreateClipper,
4105 ddraw7_CreatePalette,
4106 ddraw7_CreateSurface,
4107 ddraw7_DuplicateSurface,
4108 ddraw7_EnumDisplayModes,
4109 ddraw7_EnumSurfaces,
4110 ddraw7_FlipToGDISurface,
4111 ddraw7_GetCaps,
4112 ddraw7_GetDisplayMode,
4113 ddraw7_GetFourCCCodes,
4114 ddraw7_GetGDISurface,
4115 ddraw7_GetMonitorFrequency,
4116 ddraw7_GetScanLine,
4117 ddraw7_GetVerticalBlankStatus,
4118 ddraw7_Initialize,
4119 ddraw7_RestoreDisplayMode,
4120 ddraw7_SetCooperativeLevel,
4121 ddraw7_SetDisplayMode,
4122 ddraw7_WaitForVerticalBlank,
4123 /* IDirectDraw2 */
4124 ddraw7_GetAvailableVidMem,
4125 /* IDirectDraw3 */
4126 ddraw7_GetSurfaceFromDC,
4127 /* IDirectDraw4 */
4128 ddraw7_RestoreAllSurfaces,
4129 ddraw7_TestCooperativeLevel,
4130 ddraw7_GetDeviceIdentifier,
4131 /* IDirectDraw7 */
4132 ddraw7_StartModeTest,
4133 ddraw7_EvaluateMode
4136 const struct IDirectDraw4Vtbl IDirectDraw4_Vtbl =
4138 /* IUnknown */
4139 ddraw4_QueryInterface,
4140 ddraw4_AddRef,
4141 ddraw4_Release,
4142 /* IDirectDraw */
4143 ddraw4_Compact,
4144 ddraw4_CreateClipper,
4145 ddraw4_CreatePalette,
4146 ddraw4_CreateSurface,
4147 ddraw4_DuplicateSurface,
4148 ddraw4_EnumDisplayModes,
4149 ddraw4_EnumSurfaces,
4150 ddraw4_FlipToGDISurface,
4151 ddraw4_GetCaps,
4152 ddraw4_GetDisplayMode,
4153 ddraw4_GetFourCCCodes,
4154 ddraw4_GetGDISurface,
4155 ddraw4_GetMonitorFrequency,
4156 ddraw4_GetScanLine,
4157 ddraw4_GetVerticalBlankStatus,
4158 ddraw4_Initialize,
4159 ddraw4_RestoreDisplayMode,
4160 ddraw4_SetCooperativeLevel,
4161 ddraw4_SetDisplayMode,
4162 ddraw4_WaitForVerticalBlank,
4163 /* IDirectDraw2 */
4164 ddraw4_GetAvailableVidMem,
4165 /* IDirectDraw3 */
4166 ddraw4_GetSurfaceFromDC,
4167 /* IDirectDraw4 */
4168 ddraw4_RestoreAllSurfaces,
4169 ddraw4_TestCooperativeLevel,
4170 ddraw4_GetDeviceIdentifier,
4173 const struct IDirectDraw3Vtbl IDirectDraw3_Vtbl =
4175 /* IUnknown */
4176 ddraw3_QueryInterface,
4177 ddraw3_AddRef,
4178 ddraw3_Release,
4179 /* IDirectDraw */
4180 ddraw3_Compact,
4181 ddraw3_CreateClipper,
4182 ddraw3_CreatePalette,
4183 ddraw3_CreateSurface,
4184 ddraw3_DuplicateSurface,
4185 ddraw3_EnumDisplayModes,
4186 ddraw3_EnumSurfaces,
4187 ddraw3_FlipToGDISurface,
4188 ddraw3_GetCaps,
4189 ddraw3_GetDisplayMode,
4190 ddraw3_GetFourCCCodes,
4191 ddraw3_GetGDISurface,
4192 ddraw3_GetMonitorFrequency,
4193 ddraw3_GetScanLine,
4194 ddraw3_GetVerticalBlankStatus,
4195 ddraw3_Initialize,
4196 ddraw3_RestoreDisplayMode,
4197 ddraw3_SetCooperativeLevel,
4198 ddraw3_SetDisplayMode,
4199 ddraw3_WaitForVerticalBlank,
4200 /* IDirectDraw2 */
4201 ddraw3_GetAvailableVidMem,
4202 /* IDirectDraw3 */
4203 ddraw3_GetSurfaceFromDC,
4206 const struct IDirectDraw2Vtbl IDirectDraw2_Vtbl =
4208 /* IUnknown */
4209 ddraw2_QueryInterface,
4210 ddraw2_AddRef,
4211 ddraw2_Release,
4212 /* IDirectDraw */
4213 ddraw2_Compact,
4214 ddraw2_CreateClipper,
4215 ddraw2_CreatePalette,
4216 ddraw2_CreateSurface,
4217 ddraw2_DuplicateSurface,
4218 ddraw2_EnumDisplayModes,
4219 ddraw2_EnumSurfaces,
4220 ddraw2_FlipToGDISurface,
4221 ddraw2_GetCaps,
4222 ddraw2_GetDisplayMode,
4223 ddraw2_GetFourCCCodes,
4224 ddraw2_GetGDISurface,
4225 ddraw2_GetMonitorFrequency,
4226 ddraw2_GetScanLine,
4227 ddraw2_GetVerticalBlankStatus,
4228 ddraw2_Initialize,
4229 ddraw2_RestoreDisplayMode,
4230 ddraw2_SetCooperativeLevel,
4231 ddraw2_SetDisplayMode,
4232 ddraw2_WaitForVerticalBlank,
4233 /* IDirectDraw2 */
4234 ddraw2_GetAvailableVidMem,
4237 const struct IDirectDrawVtbl IDirectDraw1_Vtbl =
4239 /* IUnknown */
4240 ddraw1_QueryInterface,
4241 ddraw1_AddRef,
4242 ddraw1_Release,
4243 /* IDirectDraw */
4244 ddraw1_Compact,
4245 ddraw1_CreateClipper,
4246 ddraw1_CreatePalette,
4247 ddraw1_CreateSurface,
4248 ddraw1_DuplicateSurface,
4249 ddraw1_EnumDisplayModes,
4250 ddraw1_EnumSurfaces,
4251 ddraw1_FlipToGDISurface,
4252 ddraw1_GetCaps,
4253 ddraw1_GetDisplayMode,
4254 ddraw1_GetFourCCCodes,
4255 ddraw1_GetGDISurface,
4256 ddraw1_GetMonitorFrequency,
4257 ddraw1_GetScanLine,
4258 ddraw1_GetVerticalBlankStatus,
4259 ddraw1_Initialize,
4260 ddraw1_RestoreDisplayMode,
4261 ddraw1_SetCooperativeLevel,
4262 ddraw1_SetDisplayMode,
4263 ddraw1_WaitForVerticalBlank,
4266 /*****************************************************************************
4267 * ddraw_find_decl
4269 * Finds the WineD3D vertex declaration for a specific fvf, and creates one
4270 * if none was found.
4272 * This function is in ddraw.c and the DDraw object space because D3D7
4273 * vertex buffers are created using the IDirect3D interface to the ddraw
4274 * object, so they can be valid across D3D devices(theoretically. The ddraw
4275 * object also owns the wined3d device
4277 * Parameters:
4278 * This: Device
4279 * fvf: Fvf to find the decl for
4281 * Returns:
4282 * NULL in case of an error, the IWineD3DVertexDeclaration interface for the
4283 * fvf otherwise.
4285 *****************************************************************************/
4286 IWineD3DVertexDeclaration *ddraw_find_decl(IDirectDrawImpl *This, DWORD fvf)
4288 HRESULT hr;
4289 IWineD3DVertexDeclaration* pDecl = NULL;
4290 int p, low, high; /* deliberately signed */
4291 struct FvfToDecl *convertedDecls = This->decls;
4293 TRACE("Searching for declaration for fvf %08x... ", fvf);
4295 low = 0;
4296 high = This->numConvertedDecls - 1;
4297 while(low <= high) {
4298 p = (low + high) >> 1;
4299 TRACE("%d ", p);
4300 if(convertedDecls[p].fvf == fvf) {
4301 TRACE("found %p\n", convertedDecls[p].decl);
4302 return convertedDecls[p].decl;
4303 } else if(convertedDecls[p].fvf < fvf) {
4304 low = p + 1;
4305 } else {
4306 high = p - 1;
4309 TRACE("not found. Creating and inserting at position %d.\n", low);
4311 hr = IWineD3DDevice_CreateVertexDeclarationFromFVF(This->wineD3DDevice, &pDecl,
4312 (IUnknown *)This, &ddraw_null_wined3d_parent_ops, fvf);
4313 if (hr != S_OK) return NULL;
4315 if(This->declArraySize == This->numConvertedDecls) {
4316 int grow = max(This->declArraySize / 2, 8);
4317 convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls,
4318 sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow));
4319 if(!convertedDecls) {
4320 /* This will destroy it */
4321 IWineD3DVertexDeclaration_Release(pDecl);
4322 return NULL;
4324 This->decls = convertedDecls;
4325 This->declArraySize += grow;
4328 memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(convertedDecls[0]) * (This->numConvertedDecls - low));
4329 convertedDecls[low].decl = pDecl;
4330 convertedDecls[low].fvf = fvf;
4331 This->numConvertedDecls++;
4333 TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls);
4334 return pDecl;
4337 /* IWineD3DDeviceParent IUnknown methods */
4339 static inline struct IDirectDrawImpl *ddraw_from_device_parent(IWineD3DDeviceParent *iface)
4341 return (struct IDirectDrawImpl *)((char*)iface - FIELD_OFFSET(struct IDirectDrawImpl, device_parent_vtbl));
4344 static HRESULT STDMETHODCALLTYPE device_parent_QueryInterface(IWineD3DDeviceParent *iface, REFIID riid, void **object)
4346 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
4347 return ddraw7_QueryInterface((IDirectDraw7 *)This, riid, object);
4350 static ULONG STDMETHODCALLTYPE device_parent_AddRef(IWineD3DDeviceParent *iface)
4352 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
4353 return ddraw7_AddRef((IDirectDraw7 *)This);
4356 static ULONG STDMETHODCALLTYPE device_parent_Release(IWineD3DDeviceParent *iface)
4358 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
4359 return ddraw7_Release((IDirectDraw7 *)This);
4362 /* IWineD3DDeviceParent methods */
4364 static void STDMETHODCALLTYPE device_parent_WineD3DDeviceCreated(IWineD3DDeviceParent *iface, IWineD3DDevice *device)
4366 TRACE("iface %p, device %p\n", iface, device);
4369 static HRESULT STDMETHODCALLTYPE device_parent_CreateSurface(IWineD3DDeviceParent *iface,
4370 IUnknown *superior, UINT width, UINT height, WINED3DFORMAT format, DWORD usage,
4371 WINED3DPOOL pool, UINT level, WINED3DCUBEMAP_FACES face, IWineD3DSurface **surface)
4373 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
4374 IDirectDrawSurfaceImpl *surf = NULL;
4375 UINT i = 0;
4376 DDSCAPS2 searchcaps = This->tex_root->surface_desc.ddsCaps;
4378 TRACE("iface %p, superior %p, width %u, height %u, format %#x, usage %#x,\n"
4379 "\tpool %#x, level %u, face %u, surface %p\n",
4380 iface, superior, width, height, format, usage, pool, level, face, surface);
4382 searchcaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
4383 switch(face)
4385 case WINED3DCUBEMAP_FACE_POSITIVE_X:
4386 TRACE("Asked for positive x\n");
4387 if (searchcaps.dwCaps2 & DDSCAPS2_CUBEMAP)
4389 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
4391 surf = This->tex_root; break;
4392 case WINED3DCUBEMAP_FACE_NEGATIVE_X:
4393 TRACE("Asked for negative x\n");
4394 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEX; break;
4395 case WINED3DCUBEMAP_FACE_POSITIVE_Y:
4396 TRACE("Asked for positive y\n");
4397 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEY; break;
4398 case WINED3DCUBEMAP_FACE_NEGATIVE_Y:
4399 TRACE("Asked for negative y\n");
4400 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEY; break;
4401 case WINED3DCUBEMAP_FACE_POSITIVE_Z:
4402 TRACE("Asked for positive z\n");
4403 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEZ; break;
4404 case WINED3DCUBEMAP_FACE_NEGATIVE_Z:
4405 TRACE("Asked for negative z\n");
4406 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEZ; break;
4407 default: {ERR("Unexpected cube face\n");} /* Stupid compiler */
4410 if (!surf)
4412 IDirectDrawSurface7 *attached;
4413 IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)This->tex_root, &searchcaps, &attached);
4414 surf = (IDirectDrawSurfaceImpl *)attached;
4415 IDirectDrawSurface7_Release(attached);
4417 if (!surf) ERR("root search surface not found\n");
4419 /* Find the wanted mipmap. There are enough mipmaps in the chain */
4420 while (i < level)
4422 IDirectDrawSurface7 *attached;
4423 IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)surf, &searchcaps, &attached);
4424 if(!attached) ERR("Surface not found\n");
4425 surf = (IDirectDrawSurfaceImpl *)attached;
4426 IDirectDrawSurface7_Release(attached);
4427 ++i;
4430 /* Return the surface */
4431 *surface = surf->WineD3DSurface;
4432 IWineD3DSurface_AddRef(*surface);
4434 TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *surface, surf);
4436 return D3D_OK;
4439 static HRESULT WINAPI findRenderTarget(IDirectDrawSurface7 *surface, DDSURFACEDESC2 *surface_desc, void *ctx)
4441 IDirectDrawSurfaceImpl *s = (IDirectDrawSurfaceImpl *)surface;
4442 IDirectDrawSurfaceImpl **target = ctx;
4444 if (!s->isRenderTarget)
4446 *target = s;
4447 IDirectDrawSurface7_Release(surface);
4448 return DDENUMRET_CANCEL;
4451 /* Recurse into the surface tree */
4452 IDirectDrawSurface7_EnumAttachedSurfaces(surface, ctx, findRenderTarget);
4454 IDirectDrawSurface7_Release(surface);
4455 if (*target) return DDENUMRET_CANCEL;
4457 return DDENUMRET_OK;
4460 static HRESULT STDMETHODCALLTYPE device_parent_CreateRenderTarget(IWineD3DDeviceParent *iface,
4461 IUnknown *superior, UINT width, UINT height, WINED3DFORMAT format, WINED3DMULTISAMPLE_TYPE multisample_type,
4462 DWORD multisample_quality, BOOL lockable, IWineD3DSurface **surface)
4464 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
4465 IDirectDrawSurfaceImpl *d3d_surface = This->d3d_target;
4466 IDirectDrawSurfaceImpl *target = NULL;
4468 TRACE("iface %p, superior %p, width %u, height %u, format %#x, multisample_type %#x,\n"
4469 "\tmultisample_quality %u, lockable %u, surface %p\n",
4470 iface, superior, width, height, format, multisample_type, multisample_quality, lockable, surface);
4472 if (d3d_surface->isRenderTarget)
4474 IDirectDrawSurface7_EnumAttachedSurfaces((IDirectDrawSurface7 *)d3d_surface, &target, findRenderTarget);
4476 else
4478 target = d3d_surface;
4481 if (!target)
4483 target = This->d3d_target;
4484 ERR(" (%p) : No DirectDrawSurface found to create the back buffer. Using the front buffer as back buffer. Uncertain consequences\n", This);
4487 /* TODO: Return failure if the dimensions do not match, but this shouldn't happen */
4489 *surface = target->WineD3DSurface;
4490 IWineD3DSurface_AddRef(*surface);
4491 target->isRenderTarget = TRUE;
4493 TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *surface, d3d_surface);
4495 return D3D_OK;
4498 static HRESULT STDMETHODCALLTYPE device_parent_CreateDepthStencilSurface(IWineD3DDeviceParent *iface,
4499 IUnknown *superior, UINT width, UINT height, WINED3DFORMAT format, WINED3DMULTISAMPLE_TYPE multisample_type,
4500 DWORD multisample_quality, BOOL discard, IWineD3DSurface **surface)
4502 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
4503 IDirectDrawSurfaceImpl *ddraw_surface;
4504 DDSURFACEDESC2 ddsd;
4505 HRESULT hr;
4507 TRACE("iface %p, superior %p, width %u, height %u, format %#x, multisample_type %#x,\n"
4508 "\tmultisample_quality %u, discard %u, surface %p\n",
4509 iface, superior, width, height, format, multisample_type, multisample_quality, discard, surface);
4511 *surface = NULL;
4513 /* Create a DirectDraw surface */
4514 memset(&ddsd, 0, sizeof(ddsd));
4515 ddsd.dwSize = sizeof(ddsd);
4516 ddsd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
4517 ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
4518 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
4519 ddsd.dwHeight = height;
4520 ddsd.dwWidth = width;
4521 if (format)
4523 PixelFormat_WineD3DtoDD(&ddsd.u4.ddpfPixelFormat, format);
4525 else
4527 ddsd.dwFlags ^= DDSD_PIXELFORMAT;
4530 This->depthstencil = TRUE;
4531 hr = IDirectDraw7_CreateSurface((IDirectDraw7 *)This, &ddsd, (IDirectDrawSurface7 **)&ddraw_surface, NULL);
4532 This->depthstencil = FALSE;
4533 if(FAILED(hr))
4535 ERR(" (%p) Creating a DepthStencil Surface failed, result = %x\n", This, hr);
4536 return hr;
4539 *surface = ddraw_surface->WineD3DSurface;
4540 IWineD3DSurface_AddRef(*surface);
4541 IDirectDrawSurface7_Release((IDirectDrawSurface7 *)ddraw_surface);
4543 return D3D_OK;
4546 static HRESULT STDMETHODCALLTYPE device_parent_CreateVolume(IWineD3DDeviceParent *iface,
4547 IUnknown *superior, UINT width, UINT height, UINT depth, WINED3DFORMAT format,
4548 WINED3DPOOL pool, DWORD usage, IWineD3DVolume **volume)
4550 TRACE("iface %p, superior %p, width %u, height %u, depth %u, format %#x, pool %#x, usage %#x, volume %p\n",
4551 iface, superior, width, height, depth, format, pool, usage, volume);
4553 ERR("Not implemented!\n");
4555 return E_NOTIMPL;
4558 static HRESULT STDMETHODCALLTYPE device_parent_CreateSwapChain(IWineD3DDeviceParent *iface,
4559 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain)
4561 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
4562 IDirectDrawSurfaceImpl *iterator;
4563 IParentImpl *object;
4564 HRESULT hr;
4566 TRACE("iface %p, present_parameters %p, swapchain %p\n", iface, present_parameters, swapchain);
4568 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IParentImpl));
4569 if (!object)
4571 FIXME("Allocation of memory failed\n");
4572 *swapchain = NULL;
4573 return DDERR_OUTOFVIDEOMEMORY;
4576 object->lpVtbl = &IParent_Vtbl;
4577 object->ref = 1;
4579 hr = IWineD3DDevice_CreateSwapChain(This->wineD3DDevice, present_parameters,
4580 swapchain, (IUnknown *)object, This->ImplType);
4581 if (FAILED(hr))
4583 FIXME("(%p) CreateSwapChain failed, returning %#x\n", iface, hr);
4584 HeapFree(GetProcessHeap(), 0 , object);
4585 *swapchain = NULL;
4586 return hr;
4589 object->child = (IUnknown *)*swapchain;
4590 This->d3d_target->wineD3DSwapChain = *swapchain;
4591 iterator = This->d3d_target->complex_array[0];
4592 while (iterator)
4594 iterator->wineD3DSwapChain = *swapchain;
4595 iterator = iterator->complex_array[0];
4598 return hr;
4601 const IWineD3DDeviceParentVtbl ddraw_wined3d_device_parent_vtbl =
4603 /* IUnknown methods */
4604 device_parent_QueryInterface,
4605 device_parent_AddRef,
4606 device_parent_Release,
4607 /* IWineD3DDeviceParent methods */
4608 device_parent_WineD3DDeviceCreated,
4609 device_parent_CreateSurface,
4610 device_parent_CreateRenderTarget,
4611 device_parent_CreateDepthStencilSurface,
4612 device_parent_CreateVolume,
4613 device_parent_CreateSwapChain,