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
24 #include "wine/port.h"
32 #define NONAMELESSUNION
38 #include "wine/exception.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 =
53 { { 0x00010001, 0x00010001 } },
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 /*****************************************************************************
69 *****************************************************************************/
71 /*****************************************************************************
72 * IDirectDraw7::QueryInterface
74 * Queries different interfaces of the DirectDraw object. It can return
75 * IDirectDraw interfaces in version 1, 2, 4 and 7, and IDirect3D interfaces
76 * in version 1, 2, 3 and 7. An IDirect3DDevice can be created with this
78 * The returned interface is AddRef()-ed before it's returned
80 * Used for version 1, 2, 4 and 7
83 * refiid: Interface ID asked for
84 * obj: Used to return the interface pointer
87 * S_OK if an interface was found
88 * E_NOINTERFACE if the requested interface wasn't found
90 *****************************************************************************/
92 IDirectDrawImpl_QueryInterface(IDirectDraw7 *iface,
96 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
98 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
100 /* Can change surface impl type */
101 EnterCriticalSection(&ddraw_cs);
103 /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
108 LeaveCriticalSection(&ddraw_cs);
109 return DDERR_INVALIDPARAMS;
112 /* Check DirectDraw Interfaces */
113 if ( IsEqualGUID( &IID_IUnknown, refiid ) ||
114 IsEqualGUID( &IID_IDirectDraw7, refiid ) )
117 TRACE("(%p) Returning IDirectDraw7 interface at %p\n", This, *obj);
119 else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
121 *obj = &This->IDirectDraw4_vtbl;
122 TRACE("(%p) Returning IDirectDraw4 interface at %p\n", This, *obj);
124 else if ( IsEqualGUID( &IID_IDirectDraw3, refiid ) )
126 /* This Interface exists in ddrawex.dll, it is implemented in a wrapper */
127 WARN("IDirectDraw3 is not valid in ddraw.dll\n");
129 LeaveCriticalSection(&ddraw_cs);
130 return E_NOINTERFACE;
132 else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
134 *obj = &This->IDirectDraw2_vtbl;
135 TRACE("(%p) Returning IDirectDraw2 interface at %p\n", This, *obj);
137 else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
139 *obj = &This->IDirectDraw_vtbl;
140 TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
144 * The refcount unit test revealed that an IDirect3D7 interface can only be queried
145 * from a DirectDraw object that was created as an IDirectDraw7 interface. No idea
146 * who had this idea and why. The older interfaces can query and IDirect3D version
147 * because they are all created as IDirectDraw(1). This isn't really crucial behavior,
148 * and messy to implement with the common creation function, so it has been left out here.
150 else if ( IsEqualGUID( &IID_IDirect3D , refiid ) ||
151 IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
152 IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
153 IsEqualGUID( &IID_IDirect3D7 , refiid ) )
155 /* Check the surface implementation */
156 if(This->ImplType == SURFACE_UNKNOWN)
158 /* Apps may create the IDirect3D Interface before the primary surface.
159 * set the surface implementation */
160 This->ImplType = SURFACE_OPENGL;
161 TRACE("(%p) Choosing OpenGL surfaces because a Direct3D interface was requested\n", This);
163 else if(This->ImplType != SURFACE_OPENGL && DefaultSurfaceType == SURFACE_UNKNOWN)
165 ERR("(%p) The App is requesting a D3D device, but a non-OpenGL surface type was choosen. Prepare for trouble!\n", This);
166 ERR(" (%p) You may want to contact wine-devel for help\n", This);
167 /* Should I assert(0) here??? */
169 else if(This->ImplType != SURFACE_OPENGL)
171 WARN("The app requests a Direct3D interface, but non-opengl surfaces where set in winecfg\n");
172 /* Do not abort here, only reject 3D Device creation */
175 if ( IsEqualGUID( &IID_IDirect3D , refiid ) )
177 This->d3dversion = 1;
178 *obj = &This->IDirect3D_vtbl;
179 TRACE(" returning Direct3D interface at %p.\n", *obj);
181 else if ( IsEqualGUID( &IID_IDirect3D2 , refiid ) )
183 This->d3dversion = 2;
184 *obj = &This->IDirect3D2_vtbl;
185 TRACE(" returning Direct3D2 interface at %p.\n", *obj);
187 else if ( IsEqualGUID( &IID_IDirect3D3 , refiid ) )
189 This->d3dversion = 3;
190 *obj = &This->IDirect3D3_vtbl;
191 TRACE(" returning Direct3D3 interface at %p.\n", *obj);
193 else if(IsEqualGUID( &IID_IDirect3D7 , refiid ))
195 This->d3dversion = 7;
196 *obj = &This->IDirect3D7_vtbl;
197 TRACE(" returning Direct3D7 interface at %p.\n", *obj);
200 else if (IsEqualGUID(refiid, &IID_IWineD3DDeviceParent))
202 *obj = &This->device_parent_vtbl;
205 /* Unknown interface */
208 ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
209 LeaveCriticalSection(&ddraw_cs);
210 return E_NOINTERFACE;
213 IUnknown_AddRef( (IUnknown *) *obj );
214 LeaveCriticalSection(&ddraw_cs);
218 /*****************************************************************************
219 * IDirectDraw7::AddRef
221 * Increases the interfaces refcount, basically
223 * DDraw refcounting is a bit tricky. The different DirectDraw interface
224 * versions have individual refcounts, but the IDirect3D interfaces do not.
225 * All interfaces are from one object, that means calling QueryInterface on an
226 * IDirectDraw7 interface for an IDirectDraw4 interface does not create a new
227 * IDirectDrawImpl object.
229 * That means all AddRef and Release implementations of IDirectDrawX work
230 * with their own counter, and IDirect3DX::AddRef thunk to IDirectDraw (1),
231 * except of IDirect3D7 which thunks to IDirectDraw7
233 * Returns: The new refcount
235 *****************************************************************************/
237 IDirectDrawImpl_AddRef(IDirectDraw7 *iface)
239 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
240 ULONG ref = InterlockedIncrement(&This->ref7);
242 TRACE("(%p) : incrementing IDirectDraw7 refcount from %u.\n", This, ref -1);
244 if(ref == 1) InterlockedIncrement(&This->numIfaces);
249 /*****************************************************************************
250 * IDirectDrawImpl_Destroy
252 * Destroys a ddraw object if all refcounts are 0. This is to share code
253 * between the IDirectDrawX::Release functions
256 * This: DirectDraw object to destroy
258 *****************************************************************************/
260 IDirectDrawImpl_Destroy(IDirectDrawImpl *This)
262 IDirectDraw7_SetCooperativeLevel((IDirectDraw7 *)This, NULL, DDSCL_NORMAL);
263 IDirectDraw7_RestoreDisplayMode((IDirectDraw7 *)This);
265 /* Destroy the device window if we created one */
266 if(This->devicewindow != 0)
268 TRACE(" (%p) Destroying the device window %p\n", This, This->devicewindow);
269 DestroyWindow(This->devicewindow);
270 This->devicewindow = 0;
273 EnterCriticalSection(&ddraw_cs);
274 list_remove(&This->ddraw_list_entry);
275 LeaveCriticalSection(&ddraw_cs);
277 /* Release the attached WineD3D stuff */
278 IWineD3DDevice_Release(This->wineD3DDevice);
279 IWineD3D_Release(This->wineD3D);
281 /* Now free the object */
282 HeapFree(GetProcessHeap(), 0, This);
285 /*****************************************************************************
286 * IDirectDraw7::Release
288 * Decreases the refcount. If the refcount falls to 0, the object is destroyed
290 * Returns: The new refcount
291 *****************************************************************************/
293 IDirectDrawImpl_Release(IDirectDraw7 *iface)
295 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
296 ULONG ref = InterlockedDecrement(&This->ref7);
298 TRACE("(%p)->() decrementing IDirectDraw7 refcount from %u.\n", This, ref +1);
302 ULONG ifacecount = InterlockedDecrement(&This->numIfaces);
303 if(ifacecount == 0) IDirectDrawImpl_Destroy(This);
309 /*****************************************************************************
310 * IDirectDraw methods
311 *****************************************************************************/
313 /*****************************************************************************
314 * IDirectDraw7::SetCooperativeLevel
316 * Sets the cooperative level for the DirectDraw object, and the window
317 * assigned to it. The cooperative level determines the general behavior
318 * of the DirectDraw application
320 * Warning: This is quite tricky, as it's not really documented which
321 * cooperative levels can be combined with each other. If a game fails
322 * after this function, try to check the cooperative levels passed on
323 * Windows, and if it returns something different.
325 * If you think that this function caused the failure because it writes a
326 * fixme, be sure to run again with a +ddraw trace.
328 * What is known about cooperative levels (See the ddraw modes test):
329 * DDSCL_EXCLUSIVE and DDSCL_FULLSCREEN must be used with each other
330 * DDSCL_NORMAL is not compatible with DDSCL_EXCLUSIVE or DDSCL_FULLSCREEN
331 * DDSCL_SETFOCUSWINDOW can be passed only in DDSCL_NORMAL mode, but after that
332 * DDSCL_FULLSCREEN can be activated
333 * DDSCL_SETFOCUSWINDOW may only be used with DDSCL_NOWINDOWCHANGES
335 * Handled flags: DDSCL_NORMAL, DDSCL_FULLSCREEN, DDSCL_EXCLUSIVE,
336 * DDSCL_SETFOCUSWINDOW (partially),
337 * DDSCL_MULTITHREADED (work in progress)
339 * Unhandled flags, which should be implemented
340 * DDSCL_SETDEVICEWINDOW: Sets a window specially used for rendering (I don't
341 * expect any difference to a normal window for wine)
342 * DDSCL_CREATEDEVICEWINDOW: Tells ddraw to create its own window for
343 * rendering (Possible test case: Half-Life)
345 * Unsure about these: DDSCL_FPUSETUP DDSCL_FPURESERVE
347 * These don't seem very important for wine:
348 * DDSCL_ALLOWREBOOT, DDSCL_NOWINDOWCHANGES, DDSCL_ALLOWMODEX
351 * DD_OK if the cooperative level was set successfully
352 * DDERR_INVALIDPARAMS if the passed cooperative level combination is invalid
353 * DDERR_HWNDALREADYSET if DDSCL_SETFOCUSWINDOW is passed in exclusive mode
354 * (Probably others too, have to investigate)
356 *****************************************************************************/
357 static HRESULT WINAPI
358 IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
362 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
365 TRACE("(%p)->(%p,%08x)\n",This,hwnd,cooplevel);
366 DDRAW_dump_cooperativelevel(cooplevel);
368 EnterCriticalSection(&ddraw_cs);
370 /* Get the old window */
371 window = This->dest_window;
373 /* Tests suggest that we need one of them: */
374 if(!(cooplevel & (DDSCL_SETFOCUSWINDOW |
378 TRACE("Incorrect cooplevel flags, returning DDERR_INVALIDPARAMS\n");
379 LeaveCriticalSection(&ddraw_cs);
380 return DDERR_INVALIDPARAMS;
383 /* Handle those levels first which set various hwnds */
384 if(cooplevel & DDSCL_SETFOCUSWINDOW)
386 /* This isn't compatible with a lot of flags */
387 if(cooplevel & ( DDSCL_MULTITHREADED |
392 DDSCL_SETDEVICEWINDOW |
397 TRACE("Called with incompatible flags, returning DDERR_INVALIDPARAMS\n");
398 LeaveCriticalSection(&ddraw_cs);
399 return DDERR_INVALIDPARAMS;
401 else if( (This->cooperative_level & DDSCL_FULLSCREEN) && window)
403 TRACE("Setting DDSCL_SETFOCUSWINDOW with an already set window, returning DDERR_HWNDALREADYSET\n");
404 LeaveCriticalSection(&ddraw_cs);
405 return DDERR_HWNDALREADYSET;
408 This->focuswindow = hwnd;
409 /* Won't use the hwnd param for anything else */
412 /* Use the focus window for drawing too */
413 This->dest_window = This->focuswindow;
415 /* Destroy the device window, if we have one */
416 if(This->devicewindow)
418 DestroyWindow(This->devicewindow);
419 This->devicewindow = NULL;
422 /* DDSCL_NORMAL or DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE */
423 if(cooplevel & DDSCL_NORMAL)
425 /* Can't coexist with fullscreen or exclusive */
426 if(cooplevel & (DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) )
428 TRACE("(%p) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE\n", This);
429 LeaveCriticalSection(&ddraw_cs);
430 return DDERR_INVALIDPARAMS;
433 /* Switching from fullscreen? */
434 if(This->cooperative_level & DDSCL_FULLSCREEN)
436 This->cooperative_level &= ~DDSCL_FULLSCREEN;
437 This->cooperative_level &= ~DDSCL_EXCLUSIVE;
438 This->cooperative_level &= ~DDSCL_ALLOWMODEX;
440 IWineD3DDevice_ReleaseFocusWindow(This->wineD3DDevice);
443 /* Don't override focus windows or private device windows */
445 !(This->focuswindow) &&
446 !(This->devicewindow) &&
449 This->dest_window = hwnd;
452 else if(cooplevel & DDSCL_FULLSCREEN)
454 /* Needs DDSCL_EXCLUSIVE */
455 if(!(cooplevel & DDSCL_EXCLUSIVE) )
457 TRACE("(%p) DDSCL_FULLSCREEN needs DDSCL_EXCLUSIVE\n", This);
458 LeaveCriticalSection(&ddraw_cs);
459 return DDERR_INVALIDPARAMS;
464 TRACE("(%p) DDSCL_FULLSCREEN needs a HWND\n", This);
465 return DDERR_INVALIDPARAMS;
469 This->cooperative_level &= ~DDSCL_NORMAL;
471 /* Don't override focus windows or private device windows */
473 !(This->focuswindow) &&
474 !(This->devicewindow) &&
477 HRESULT hr = IWineD3DDevice_AcquireFocusWindow(This->wineD3DDevice, hwnd);
480 ERR("Failed to acquire focus window, hr %#x.\n", hr);
481 LeaveCriticalSection(&ddraw_cs);
484 This->dest_window = hwnd;
487 else if(cooplevel & DDSCL_EXCLUSIVE)
489 TRACE("(%p) DDSCL_EXCLUSIVE needs DDSCL_FULLSCREEN\n", This);
490 LeaveCriticalSection(&ddraw_cs);
491 return DDERR_INVALIDPARAMS;
494 if(cooplevel & DDSCL_CREATEDEVICEWINDOW)
496 /* Don't create a device window if a focus window is set */
497 if( !(This->focuswindow) )
499 HWND devicewindow = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "DDraw device window",
500 WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
501 NULL, NULL, NULL, NULL);
504 ERR("Failed to create window, last error %#x.\n", GetLastError());
505 LeaveCriticalSection(&ddraw_cs);
509 ShowWindow(devicewindow, SW_SHOW); /* Just to be sure */
510 TRACE("(%p) Created a DDraw device window. HWND=%p\n", This, devicewindow);
512 This->devicewindow = devicewindow;
513 This->dest_window = devicewindow;
517 if(cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED))
519 /* Enable thread safety in wined3d */
520 IWineD3DDevice_SetMultithreaded(This->wineD3DDevice);
523 /* Unhandled flags */
524 if(cooplevel & DDSCL_ALLOWREBOOT)
525 WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This);
526 if(cooplevel & DDSCL_ALLOWMODEX)
527 WARN("(%p) Unhandled flag DDSCL_ALLOWMODEX, harmless\n", This);
528 if(cooplevel & DDSCL_FPUSETUP)
529 WARN("(%p) Unhandled flag DDSCL_FPUSETUP, harmless\n", This);
531 /* Store the cooperative_level */
532 This->cooperative_level |= cooplevel;
533 TRACE("SetCooperativeLevel retuning DD_OK\n");
534 LeaveCriticalSection(&ddraw_cs);
538 /*****************************************************************************
540 * Helper function for SetDisplayMode and RestoreDisplayMode
542 * Implements DirectDraw's SetDisplayMode, but ignores the value of
543 * ForceRefreshRate, since it is already handled by
544 * IDirectDrawImpl_SetDisplayMode. RestoreDisplayMode can use this function
545 * without worrying that ForceRefreshRate will override the refresh rate. For
546 * argument and return value documentation, see
547 * IDirectDrawImpl_SetDisplayMode.
549 *****************************************************************************/
551 IDirectDrawImpl_SetDisplayModeNoOverride(IDirectDraw7 *iface,
558 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
559 WINED3DDISPLAYMODE Mode;
561 TRACE("(%p)->(%d,%d,%d,%d,%x): Relay!\n", This, Width, Height, BPP, RefreshRate, Flags);
563 EnterCriticalSection(&ddraw_cs);
564 if( !Width || !Height )
566 ERR("Width=%d, Height=%d, what to do?\n", Width, Height);
567 /* It looks like Need for Speed Porsche Unleashed expects DD_OK here */
568 LeaveCriticalSection(&ddraw_cs);
572 /* Check the exclusive mode
573 if(!(This->cooperative_level & DDSCL_EXCLUSIVE))
574 return DDERR_NOEXCLUSIVEMODE;
575 * This is WRONG. Don't know if the SDK is completely
576 * wrong and if there are any conditions when DDERR_NOEXCLUSIVE
577 * is returned, but Half-Life 1.1.1.1 (Steam version)
582 Mode.Height = Height;
583 Mode.RefreshRate = RefreshRate;
586 case 8: Mode.Format = WINED3DFMT_P8_UINT; break;
587 case 15: Mode.Format = WINED3DFMT_B5G5R5X1_UNORM; break;
588 case 16: Mode.Format = WINED3DFMT_B5G6R5_UNORM; break;
589 case 24: Mode.Format = WINED3DFMT_B8G8R8_UNORM; break;
590 case 32: Mode.Format = WINED3DFMT_B8G8R8X8_UNORM; break;
593 /* TODO: The possible return values from msdn suggest that
594 * the screen mode can't be changed if a surface is locked
595 * or some drawing is in progress
598 /* TODO: Lose the primary surface */
599 hr = IWineD3DDevice_SetDisplayMode(This->wineD3DDevice,
600 0, /* First swapchain */
602 LeaveCriticalSection(&ddraw_cs);
605 case WINED3DERR_NOTAVAILABLE: return DDERR_UNSUPPORTED;
610 /*****************************************************************************
611 * IDirectDraw7::SetDisplayMode
613 * Sets the display screen resolution, color depth and refresh frequency
614 * when in fullscreen mode (in theory).
615 * Possible return values listed in the SDK suggest that this method fails
616 * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets
617 * the display mode in DDSCL_NORMAL mode without an hwnd specified.
618 * It seems to be valid to pass 0 for With and Height, this has to be tested
619 * It could mean that the current video mode should be left as-is. (But why
623 * Height, Width: Screen dimension
624 * BPP: Color depth in Bits per pixel
625 * Refreshrate: Screen refresh rate
631 *****************************************************************************/
632 static HRESULT WINAPI
633 IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface,
640 if (force_refresh_rate != 0)
642 TRACE("ForceRefreshRate overriding passed-in refresh rate (%d Hz) to %d Hz\n", RefreshRate, force_refresh_rate);
643 RefreshRate = force_refresh_rate;
646 return IDirectDrawImpl_SetDisplayModeNoOverride(iface, Width, Height, BPP,
650 /*****************************************************************************
651 * IDirectDraw7::RestoreDisplayMode
653 * Restores the display mode to what it was at creation time. Basically.
655 * A problem arises when there are 2 DirectDraw objects using the same hwnd:
656 * -> DD_1 finds the screen at 1400x1050x32 when created, sets it to 640x480x16
657 * -> DD_2 is created, finds the screen at 640x480x16, sets it to 1024x768x32
658 * -> DD_1 is released. The screen should be left at 1024x768x32.
659 * -> DD_2 is released. The screen should be set to 1400x1050x32
660 * This case is unhandled right now, but Empire Earth does it this way.
661 * (But perhaps there is something in SetCooperativeLevel to prevent this)
663 * The msdn says that this method resets the display mode to what it was before
664 * SetDisplayMode was called. What if SetDisplayModes is called 2 times??
668 * DDERR_NOEXCLUSIVE mode if the device isn't in fullscreen mode
670 *****************************************************************************/
671 static HRESULT WINAPI
672 IDirectDrawImpl_RestoreDisplayMode(IDirectDraw7 *iface)
674 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
675 TRACE("(%p)\n", This);
677 return IDirectDrawImpl_SetDisplayModeNoOverride(iface,
678 This->orig_width, This->orig_height, This->orig_bpp, 0, 0);
681 /*****************************************************************************
682 * IDirectDraw7::GetCaps
684 * Returns the drives capabilities
686 * Used for version 1, 2, 4 and 7
689 * DriverCaps: Structure to write the Hardware accelerated caps to
690 * HelCaps: Structure to write the emulation caps to
693 * This implementation returns DD_OK only
695 *****************************************************************************/
696 static HRESULT WINAPI
697 IDirectDrawImpl_GetCaps(IDirectDraw7 *iface,
701 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
703 WINED3DCAPS winecaps;
705 DDSCAPS2 ddscaps = {0, 0, 0, 0};
706 TRACE("(%p)->(%p,%p)\n", This, DriverCaps, HELCaps);
708 /* One structure must be != NULL */
709 if( (!DriverCaps) && (!HELCaps) )
711 ERR("(%p) Invalid params to IDirectDrawImpl_GetCaps\n", This);
712 return DDERR_INVALIDPARAMS;
715 memset(&caps, 0, sizeof(caps));
716 memset(&winecaps, 0, sizeof(winecaps));
717 caps.dwSize = sizeof(caps);
718 EnterCriticalSection(&ddraw_cs);
719 hr = IWineD3DDevice_GetDeviceCaps(This->wineD3DDevice, &winecaps);
721 WARN("IWineD3DDevice::GetDeviceCaps failed\n");
722 LeaveCriticalSection(&ddraw_cs);
726 hr = IDirectDraw7_GetAvailableVidMem(iface, &ddscaps, &caps.dwVidMemTotal, &caps.dwVidMemFree);
727 LeaveCriticalSection(&ddraw_cs);
729 WARN("IDirectDraw7::GetAvailableVidMem failed\n");
733 caps.dwCaps = winecaps.DirectDrawCaps.Caps;
734 caps.dwCaps2 = winecaps.DirectDrawCaps.Caps2;
735 caps.dwCKeyCaps = winecaps.DirectDrawCaps.CKeyCaps;
736 caps.dwFXCaps = winecaps.DirectDrawCaps.FXCaps;
737 caps.dwPalCaps = winecaps.DirectDrawCaps.PalCaps;
738 caps.ddsCaps.dwCaps = winecaps.DirectDrawCaps.ddsCaps;
739 caps.dwSVBCaps = winecaps.DirectDrawCaps.SVBCaps;
740 caps.dwSVBCKeyCaps = winecaps.DirectDrawCaps.SVBCKeyCaps;
741 caps.dwSVBFXCaps = winecaps.DirectDrawCaps.SVBFXCaps;
742 caps.dwVSBCaps = winecaps.DirectDrawCaps.VSBCaps;
743 caps.dwVSBCKeyCaps = winecaps.DirectDrawCaps.VSBCKeyCaps;
744 caps.dwVSBFXCaps = winecaps.DirectDrawCaps.VSBFXCaps;
745 caps.dwSSBCaps = winecaps.DirectDrawCaps.SSBCaps;
746 caps.dwSSBCKeyCaps = winecaps.DirectDrawCaps.SSBCKeyCaps;
747 caps.dwSSBFXCaps = winecaps.DirectDrawCaps.SSBFXCaps;
749 /* Even if WineD3D supports 3D rendering, remove the cap if ddraw is configured
752 if(DefaultSurfaceType == SURFACE_GDI) {
753 caps.dwCaps &= ~DDCAPS_3D;
754 caps.ddsCaps.dwCaps &= ~(DDSCAPS_3DDEVICE | DDSCAPS_MIPMAP | DDSCAPS_TEXTURE | DDSCAPS_ZBUFFER);
756 if(winecaps.DirectDrawCaps.StrideAlign != 0) {
757 caps.dwCaps |= DDCAPS_ALIGNSTRIDE;
758 caps.dwAlignStrideAlign = winecaps.DirectDrawCaps.StrideAlign;
763 DD_STRUCT_COPY_BYSIZE(DriverCaps, &caps);
766 TRACE("Driver Caps :\n");
767 DDRAW_dump_DDCAPS(DriverCaps);
773 DD_STRUCT_COPY_BYSIZE(HELCaps, &caps);
776 TRACE("HEL Caps :\n");
777 DDRAW_dump_DDCAPS(HELCaps);
784 /*****************************************************************************
785 * IDirectDraw7::Compact
787 * No idea what it does, MSDN says it's not implemented.
790 * DD_OK, but this is unchecked
792 *****************************************************************************/
793 static HRESULT WINAPI
794 IDirectDrawImpl_Compact(IDirectDraw7 *iface)
796 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
797 TRACE("(%p)\n", This);
802 /*****************************************************************************
803 * IDirectDraw7::GetDisplayMode
805 * Returns information about the current display mode
807 * Exists in Version 1, 2, 4 and 7
810 * DDSD: Address of a surface description structure to write the info to
815 *****************************************************************************/
816 static HRESULT WINAPI
817 IDirectDrawImpl_GetDisplayMode(IDirectDraw7 *iface,
818 DDSURFACEDESC2 *DDSD)
820 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
822 WINED3DDISPLAYMODE Mode;
824 TRACE("(%p)->(%p): Relay\n", This, DDSD);
826 EnterCriticalSection(&ddraw_cs);
827 /* This seems sane */
830 LeaveCriticalSection(&ddraw_cs);
831 return DDERR_INVALIDPARAMS;
834 /* The necessary members of LPDDSURFACEDESC and LPDDSURFACEDESC2 are equal,
835 * so one method can be used for all versions (Hopefully)
837 hr = IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
842 ERR(" (%p) IWineD3DDevice::GetDisplayMode returned %08x\n", This, hr);
843 LeaveCriticalSection(&ddraw_cs);
848 memset(DDSD, 0, Size);
851 DDSD->dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_REFRESHRATE;
852 DDSD->dwWidth = Mode.Width;
853 DDSD->dwHeight = Mode.Height;
854 DDSD->u2.dwRefreshRate = 60;
855 DDSD->ddsCaps.dwCaps = 0;
856 DDSD->u4.ddpfPixelFormat.dwSize = sizeof(DDSD->u4.ddpfPixelFormat);
857 PixelFormat_WineD3DtoDD(&DDSD->u4.ddpfPixelFormat, Mode.Format);
858 DDSD->u1.lPitch = Mode.Width * DDSD->u4.ddpfPixelFormat.u1.dwRGBBitCount / 8;
862 TRACE("Returning surface desc :\n");
863 DDRAW_dump_surface_desc(DDSD);
866 LeaveCriticalSection(&ddraw_cs);
870 /*****************************************************************************
871 * IDirectDraw7::GetFourCCCodes
873 * Returns an array of supported FourCC codes.
875 * Exists in Version 1, 2, 4 and 7
878 * NumCodes: Contains the number of Codes that Codes can carry. Returns the number
879 * of enumerated codes
880 * Codes: Pointer to an array of DWORDs where the supported codes are written
884 * Always returns DD_OK, as it's a stub for now
886 *****************************************************************************/
887 static HRESULT WINAPI
888 IDirectDrawImpl_GetFourCCCodes(IDirectDraw7 *iface,
889 DWORD *NumCodes, DWORD *Codes)
891 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
892 WINED3DFORMAT formats[] = {
893 WINED3DFMT_YUY2, WINED3DFMT_UYVY, WINED3DFMT_YV12,
894 WINED3DFMT_DXT1, WINED3DFMT_DXT2, WINED3DFMT_DXT3, WINED3DFMT_DXT4, WINED3DFMT_DXT5,
895 WINED3DFMT_ATI2N, WINED3DFMT_NVHU, WINED3DFMT_NVHS
897 DWORD count = 0, i, outsize;
899 WINED3DDISPLAYMODE d3ddm;
900 WINED3DSURFTYPE type = This->ImplType;
901 TRACE("(%p)->(%p, %p)\n", This, NumCodes, Codes);
903 IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
907 outsize = NumCodes && Codes ? *NumCodes : 0;
909 if(type == SURFACE_UNKNOWN) type = SURFACE_GDI;
911 for(i = 0; i < (sizeof(formats) / sizeof(formats[0])); i++) {
912 hr = IWineD3D_CheckDeviceFormat(This->wineD3D,
913 WINED3DADAPTER_DEFAULT,
915 d3ddm.Format /* AdapterFormat */,
917 WINED3DRTYPE_SURFACE,
921 if(count < outsize) {
922 Codes[count] = formats[i];
928 TRACE("Returning %u FourCC codes\n", count);
935 /*****************************************************************************
936 * IDirectDraw7::GetMonitorFrequency
938 * Returns the monitor's frequency
940 * Exists in Version 1, 2, 4 and 7
943 * Freq: Pointer to a DWORD to write the frequency to
946 * Always returns DD_OK
948 *****************************************************************************/
949 static HRESULT WINAPI
950 IDirectDrawImpl_GetMonitorFrequency(IDirectDraw7 *iface,
953 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
954 TRACE("(%p)->(%p)\n", This, Freq);
956 /* Ideally this should be in WineD3D, as it concerns the screen setup,
957 * but for now this should make the games happy
963 /*****************************************************************************
964 * IDirectDraw7::GetVerticalBlankStatus
966 * Returns the Vertical blank status of the monitor. This should be in WineD3D
967 * too basically, but as it's a semi stub, I didn't create a function there
970 * status: Pointer to a BOOL to be filled with the vertical blank status
974 * DDERR_INVALIDPARAMS if status is NULL
976 *****************************************************************************/
977 static HRESULT WINAPI
978 IDirectDrawImpl_GetVerticalBlankStatus(IDirectDraw7 *iface,
981 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
982 TRACE("(%p)->(%p)\n", This, status);
984 /* This looks sane, the MSDN suggests it too */
985 EnterCriticalSection(&ddraw_cs);
988 LeaveCriticalSection(&ddraw_cs);
989 return DDERR_INVALIDPARAMS;
992 *status = This->fake_vblank;
993 This->fake_vblank = !This->fake_vblank;
994 LeaveCriticalSection(&ddraw_cs);
998 /*****************************************************************************
999 * IDirectDraw7::GetAvailableVidMem
1001 * Returns the total and free video memory
1004 * Caps: Specifies the memory type asked for
1005 * total: Pointer to a DWORD to be filled with the total memory
1006 * free: Pointer to a DWORD to be filled with the free memory
1010 * DDERR_INVALIDPARAMS of free and total are NULL
1012 *****************************************************************************/
1013 static HRESULT WINAPI
1014 IDirectDrawImpl_GetAvailableVidMem(IDirectDraw7 *iface, DDSCAPS2 *Caps, DWORD *total, DWORD *free)
1016 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1017 TRACE("(%p)->(%p, %p, %p)\n", This, Caps, total, free);
1021 TRACE("(%p) Asked for memory with description: ", This);
1022 DDRAW_dump_DDSCAPS2(Caps);
1024 EnterCriticalSection(&ddraw_cs);
1026 /* Todo: System memory vs local video memory vs non-local video memory
1027 * The MSDN also mentions differences between texture memory and other
1028 * resources, but that's not important
1031 if( (!total) && (!free) )
1033 LeaveCriticalSection(&ddraw_cs);
1034 return DDERR_INVALIDPARAMS;
1037 if(total) *total = This->total_vidmem;
1038 if(free) *free = IWineD3DDevice_GetAvailableTextureMem(This->wineD3DDevice);
1040 LeaveCriticalSection(&ddraw_cs);
1044 /*****************************************************************************
1045 * IDirectDraw7::Initialize
1047 * Initializes a DirectDraw interface.
1050 * GUID: Interface identifier. Well, don't know what this is really good
1054 * Returns DD_OK on the first call,
1055 * DDERR_ALREADYINITIALIZED on repeated calls
1057 *****************************************************************************/
1058 static HRESULT WINAPI
1059 IDirectDrawImpl_Initialize(IDirectDraw7 *iface,
1062 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1063 TRACE("(%p)->(%s): No-op\n", This, debugstr_guid(Guid));
1065 if(This->initialized)
1067 return DDERR_ALREADYINITIALIZED;
1075 /*****************************************************************************
1076 * IDirectDraw7::FlipToGDISurface
1078 * "Makes the surface that the GDI writes to the primary surface"
1079 * Looks like some windows specific thing we don't have to care about.
1080 * According to MSDN it permits GDI dialog boxes in FULLSCREEN mode. Good to
1081 * show error boxes ;)
1082 * Well, just return DD_OK.
1085 * Always returns DD_OK
1087 *****************************************************************************/
1088 static HRESULT WINAPI
1089 IDirectDrawImpl_FlipToGDISurface(IDirectDraw7 *iface)
1091 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1092 TRACE("(%p)\n", This);
1097 /*****************************************************************************
1098 * IDirectDraw7::WaitForVerticalBlank
1100 * This method allows applications to get in sync with the vertical blank
1102 * The wormhole demo in the DirectX 7 sdk uses this call, and it doesn't
1103 * redraw the screen, most likely because of this stub
1106 * Flags: one of DDWAITVB_BLOCKBEGIN, DDWAITVB_BLOCKBEGINEVENT
1107 * or DDWAITVB_BLOCKEND
1108 * h: Not used, according to MSDN
1111 * Always returns DD_OK
1113 *****************************************************************************/
1114 static HRESULT WINAPI
1115 IDirectDrawImpl_WaitForVerticalBlank(IDirectDraw7 *iface,
1119 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1120 static BOOL hide = FALSE;
1122 /* This function is called often, so print the fixme only once */
1125 FIXME("(%p)->(%x,%p): Stub\n", This, Flags, h);
1129 /* MSDN says DDWAITVB_BLOCKBEGINEVENT is not supported */
1130 if(Flags & DDWAITVB_BLOCKBEGINEVENT)
1131 return DDERR_UNSUPPORTED; /* unchecked */
1136 /*****************************************************************************
1137 * IDirectDraw7::GetScanLine
1139 * Returns the scan line that is being drawn on the monitor
1142 * Scanline: Address to write the scan line value to
1145 * Always returns DD_OK
1147 *****************************************************************************/
1148 static HRESULT WINAPI IDirectDrawImpl_GetScanLine(IDirectDraw7 *iface, DWORD *Scanline)
1150 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1151 static BOOL hide = FALSE;
1152 WINED3DDISPLAYMODE Mode;
1154 /* This function is called often, so print the fixme only once */
1155 EnterCriticalSection(&ddraw_cs);
1158 FIXME("(%p)->(%p): Semi-Stub\n", This, Scanline);
1162 IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
1166 /* Fake the line sweeping of the monitor */
1167 /* FIXME: We should synchronize with a source to keep the refresh rate */
1168 *Scanline = This->cur_scanline++;
1169 /* Assume 20 scan lines in the vertical blank */
1170 if (This->cur_scanline >= Mode.Height + 20)
1171 This->cur_scanline = 0;
1173 LeaveCriticalSection(&ddraw_cs);
1177 /*****************************************************************************
1178 * IDirectDraw7::TestCooperativeLevel
1180 * Informs the application about the state of the video adapter, depending
1181 * on the cooperative level
1184 * DD_OK if the device is in a sane state
1185 * DDERR_NOEXCLUSIVEMODE or DDERR_EXCLUSIVEMODEALREADYSET
1186 * if the state is not correct(See below)
1188 *****************************************************************************/
1189 static HRESULT WINAPI
1190 IDirectDrawImpl_TestCooperativeLevel(IDirectDraw7 *iface)
1192 TRACE("iface %p.\n", iface);
1197 /*****************************************************************************
1198 * IDirectDraw7::GetGDISurface
1200 * Returns the surface that GDI is treating as the primary surface.
1201 * For Wine this is the front buffer
1204 * GDISurface: Address to write the surface pointer to
1207 * DD_OK if the surface was found
1208 * DDERR_NOTFOUND if the GDI surface wasn't found
1210 *****************************************************************************/
1211 static HRESULT WINAPI
1212 IDirectDrawImpl_GetGDISurface(IDirectDraw7 *iface,
1213 IDirectDrawSurface7 **GDISurface)
1215 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1216 IWineD3DSurface *Surf;
1217 IDirectDrawSurface7 *ddsurf;
1220 TRACE("(%p)->(%p)\n", This, GDISurface);
1222 /* Get the back buffer from the wineD3DDevice and search its
1223 * attached surfaces for the front buffer
1225 EnterCriticalSection(&ddraw_cs);
1226 hr = IWineD3DDevice_GetBackBuffer(This->wineD3DDevice,
1228 0, /* first back buffer*/
1229 WINED3DBACKBUFFER_TYPE_MONO,
1232 if( (hr != D3D_OK) ||
1235 ERR("IWineD3DDevice::GetBackBuffer failed\n");
1236 LeaveCriticalSection(&ddraw_cs);
1237 return DDERR_NOTFOUND;
1240 /* GetBackBuffer AddRef()ed the surface, release it */
1241 IWineD3DSurface_Release(Surf);
1243 IWineD3DSurface_GetParent(Surf,
1244 (IUnknown **) &ddsurf);
1245 IDirectDrawSurface7_Release(ddsurf); /* For the GetParent */
1247 /* Find the front buffer */
1248 ddsCaps.dwCaps = DDSCAPS_FRONTBUFFER;
1249 hr = IDirectDrawSurface7_GetAttachedSurface(ddsurf,
1254 ERR("IDirectDrawSurface7::GetAttachedSurface failed, hr = %x\n", hr);
1257 /* The AddRef is OK this time */
1258 LeaveCriticalSection(&ddraw_cs);
1262 /*****************************************************************************
1263 * IDirectDraw7::EnumDisplayModes
1265 * Enumerates the supported Display modes. The modes can be filtered with
1266 * the DDSD parameter.
1269 * Flags: can be DDEDM_REFRESHRATES and DDEDM_STANDARDVGAMODES
1270 * DDSD: Surface description to filter the modes
1271 * Context: Pointer passed back to the callback function
1272 * cb: Application-provided callback function
1276 * DDERR_INVALIDPARAMS if the callback wasn't set
1278 *****************************************************************************/
1279 static HRESULT WINAPI
1280 IDirectDrawImpl_EnumDisplayModes(IDirectDraw7 *iface,
1282 DDSURFACEDESC2 *DDSD,
1284 LPDDENUMMODESCALLBACK2 cb)
1286 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1287 unsigned int modenum, fmt;
1288 WINED3DFORMAT pixelformat = WINED3DFMT_UNKNOWN;
1289 WINED3DDISPLAYMODE mode;
1290 DDSURFACEDESC2 callback_sd;
1291 WINED3DDISPLAYMODE *enum_modes = NULL;
1292 unsigned enum_mode_count = 0, enum_mode_array_size = 0;
1294 WINED3DFORMAT checkFormatList[] =
1296 WINED3DFMT_B8G8R8X8_UNORM,
1297 WINED3DFMT_B5G6R5_UNORM,
1301 TRACE("(%p)->(%p,%p,%p): Relay\n", This, DDSD, Context, cb);
1303 EnterCriticalSection(&ddraw_cs);
1304 /* This looks sane */
1307 LeaveCriticalSection(&ddraw_cs);
1308 return DDERR_INVALIDPARAMS;
1313 if ((DDSD->dwFlags & DDSD_PIXELFORMAT) && (DDSD->u4.ddpfPixelFormat.dwFlags & DDPF_RGB) )
1314 pixelformat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
1317 if(!(Flags & DDEDM_REFRESHRATES))
1319 enum_mode_array_size = 16;
1320 enum_modes = HeapAlloc(GetProcessHeap(), 0, sizeof(WINED3DDISPLAYMODE) * enum_mode_array_size);
1323 ERR("Out of memory\n");
1324 LeaveCriticalSection(&ddraw_cs);
1325 return DDERR_OUTOFMEMORY;
1329 for(fmt = 0; fmt < (sizeof(checkFormatList) / sizeof(checkFormatList[0])); fmt++)
1331 if(pixelformat != WINED3DFMT_UNKNOWN && checkFormatList[fmt] != pixelformat)
1337 while(IWineD3D_EnumAdapterModes(This->wineD3D,
1338 WINED3DADAPTER_DEFAULT,
1339 checkFormatList[fmt],
1341 &mode) == WINED3D_OK)
1345 if(DDSD->dwFlags & DDSD_WIDTH && mode.Width != DDSD->dwWidth) continue;
1346 if(DDSD->dwFlags & DDSD_HEIGHT && mode.Height != DDSD->dwHeight) continue;
1349 if(!(Flags & DDEDM_REFRESHRATES))
1351 /* DX docs state EnumDisplayMode should return only unique modes. If DDEDM_REFRESHRATES is not set, refresh
1352 * rate doesn't matter when determining if the mode is unique. So modes only differing in refresh rate have
1353 * to be reduced to a single unique result in such case.
1358 for (i = 0; i < enum_mode_count; i++)
1360 if(enum_modes[i].Width == mode.Width && enum_modes[i].Height == mode.Height &&
1361 enum_modes[i].Format == mode.Format)
1371 memset(&callback_sd, 0, sizeof(callback_sd));
1372 callback_sd.dwSize = sizeof(callback_sd);
1373 callback_sd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1375 callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH;
1376 if(Flags & DDEDM_REFRESHRATES)
1378 callback_sd.dwFlags |= DDSD_REFRESHRATE;
1379 callback_sd.u2.dwRefreshRate = mode.RefreshRate;
1382 callback_sd.dwWidth = mode.Width;
1383 callback_sd.dwHeight = mode.Height;
1385 PixelFormat_WineD3DtoDD(&callback_sd.u4.ddpfPixelFormat, mode.Format);
1387 /* Calc pitch and DWORD align like MSDN says */
1388 callback_sd.u1.lPitch = (callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount / 8) * mode.Width;
1389 callback_sd.u1.lPitch = (callback_sd.u1.lPitch + 3) & ~3;
1391 TRACE("Enumerating %dx%dx%d @%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
1392 callback_sd.u2.dwRefreshRate);
1394 if(cb(&callback_sd, Context) == DDENUMRET_CANCEL)
1396 TRACE("Application asked to terminate the enumeration\n");
1397 HeapFree(GetProcessHeap(), 0, enum_modes);
1398 LeaveCriticalSection(&ddraw_cs);
1402 if(!(Flags & DDEDM_REFRESHRATES))
1404 if (enum_mode_count == enum_mode_array_size)
1406 WINED3DDISPLAYMODE *new_enum_modes;
1408 enum_mode_array_size *= 2;
1409 new_enum_modes = HeapReAlloc(GetProcessHeap(), 0, enum_modes, sizeof(WINED3DDISPLAYMODE) * enum_mode_array_size);
1411 if (!new_enum_modes)
1413 ERR("Out of memory\n");
1414 HeapFree(GetProcessHeap(), 0, enum_modes);
1415 LeaveCriticalSection(&ddraw_cs);
1416 return DDERR_OUTOFMEMORY;
1419 enum_modes = new_enum_modes;
1422 enum_modes[enum_mode_count++] = mode;
1427 TRACE("End of enumeration\n");
1428 HeapFree(GetProcessHeap(), 0, enum_modes);
1429 LeaveCriticalSection(&ddraw_cs);
1433 /*****************************************************************************
1434 * IDirectDraw7::EvaluateMode
1436 * Used with IDirectDraw7::StartModeTest to test video modes.
1437 * EvaluateMode is used to pass or fail a mode, and continue with the next
1441 * Flags: DDEM_MODEPASSED or DDEM_MODEFAILED
1442 * Timeout: Returns the amount of seconds left before the mode would have
1443 * been failed automatically
1446 * This implementation always DD_OK, because it's a stub
1448 *****************************************************************************/
1449 static HRESULT WINAPI
1450 IDirectDrawImpl_EvaluateMode(IDirectDraw7 *iface,
1454 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1455 FIXME("(%p)->(%d,%p): Stub!\n", This, Flags, Timeout);
1457 /* When implementing this, implement it in WineD3D */
1462 /*****************************************************************************
1463 * IDirectDraw7::GetDeviceIdentifier
1465 * Returns the device identifier, which gives information about the driver
1466 * Our device identifier is defined at the beginning of this file.
1469 * DDDI: Address for the returned structure
1470 * Flags: Can be DDGDI_GETHOSTIDENTIFIER
1473 * On success it returns DD_OK
1474 * DDERR_INVALIDPARAMS if DDDI is NULL
1476 *****************************************************************************/
1477 static HRESULT WINAPI
1478 IDirectDrawImpl_GetDeviceIdentifier(IDirectDraw7 *iface,
1479 DDDEVICEIDENTIFIER2 *DDDI,
1482 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1483 TRACE("(%p)->(%p,%08x)\n", This, DDDI, Flags);
1486 return DDERR_INVALIDPARAMS;
1488 /* The DDGDI_GETHOSTIDENTIFIER returns the information about the 2D
1489 * host adapter, if there's a secondary 3D adapter. This doesn't apply
1490 * to any modern hardware, nor is it interesting for Wine, so ignore it.
1491 * Size of DDDEVICEIDENTIFIER2 may be aligned to 8 bytes and thus 4
1492 * bytes too long. So only copy the relevant part of the structure
1495 memcpy(DDDI, &deviceidentifier, FIELD_OFFSET(DDDEVICEIDENTIFIER2, dwWHQLLevel) + sizeof(DWORD));
1499 /*****************************************************************************
1500 * IDirectDraw7::GetSurfaceFromDC
1502 * Returns the Surface for a GDI device context handle.
1503 * Is this related to IDirectDrawSurface::GetDC ???
1506 * hdc: hdc to return the surface for
1507 * Surface: Address to write the surface pointer to
1510 * Always returns DD_OK because it's a stub
1512 *****************************************************************************/
1513 static HRESULT WINAPI
1514 IDirectDrawImpl_GetSurfaceFromDC(IDirectDraw7 *iface,
1516 IDirectDrawSurface7 **Surface)
1518 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1519 IWineD3DSurface *wined3d_surface;
1522 TRACE("iface %p, dc %p, surface %p.\n", iface, hdc, Surface);
1524 if (!Surface) return E_INVALIDARG;
1526 hr = IWineD3DDevice_GetSurfaceFromDC(This->wineD3DDevice, hdc, &wined3d_surface);
1529 TRACE("No surface found for dc %p.\n", hdc);
1531 return DDERR_NOTFOUND;
1534 IWineD3DSurface_GetParent(wined3d_surface, (IUnknown **)Surface);
1535 TRACE("Returning surface %p.\n", Surface);
1539 /*****************************************************************************
1540 * IDirectDraw7::RestoreAllSurfaces
1542 * Calls the restore method of all surfaces
1547 * Always returns DD_OK because it's a stub
1549 *****************************************************************************/
1550 static HRESULT WINAPI
1551 IDirectDrawImpl_RestoreAllSurfaces(IDirectDraw7 *iface)
1553 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1554 FIXME("(%p): Stub\n", This);
1556 /* This isn't hard to implement: Enumerate all WineD3D surfaces,
1557 * get their parent and call their restore method. Do not implement
1558 * it in WineD3D, as restoring a surface means re-creating the
1564 /*****************************************************************************
1565 * IDirectDraw7::StartModeTest
1567 * Tests the specified video modes to update the system registry with
1568 * refresh rate information. StartModeTest starts the mode test,
1569 * EvaluateMode is used to fail or pass a mode. If EvaluateMode
1570 * isn't called within 15 seconds, the mode is failed automatically
1572 * As refresh rates are handled by the X server, I don't think this
1573 * Method is important
1576 * Modes: An array of mode specifications
1577 * NumModes: The number of modes in Modes
1578 * Flags: Some flags...
1581 * Returns DDERR_TESTFINISHED if flags contains DDSMT_ISTESTREQUIRED,
1582 * if no modes are passed, DDERR_INVALIDPARAMS is returned,
1585 *****************************************************************************/
1586 static HRESULT WINAPI
1587 IDirectDrawImpl_StartModeTest(IDirectDraw7 *iface,
1592 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
1593 WARN("(%p)->(%p, %d, %x): Semi-Stub, most likely harmless\n", This, Modes, NumModes, Flags);
1595 /* This looks sane */
1596 if( (!Modes) || (NumModes == 0) ) return DDERR_INVALIDPARAMS;
1598 /* DDSMT_ISTESTREQUIRED asks if a mode test is necessary.
1599 * As it is not, DDERR_TESTFINISHED is returned
1600 * (hopefully that's correct
1602 if(Flags & DDSMT_ISTESTREQUIRED) return DDERR_TESTFINISHED;
1603 * well, that value doesn't (yet) exist in the wine headers, so ignore it
1609 /*****************************************************************************
1610 * IDirectDrawImpl_RecreateSurfacesCallback
1612 * Enumeration callback for IDirectDrawImpl_RecreateAllSurfaces.
1613 * It re-recreates the WineD3DSurface. It's pretty straightforward
1615 *****************************************************************************/
1617 IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf,
1618 DDSURFACEDESC2 *desc,
1621 IDirectDrawSurfaceImpl *surfImpl = (IDirectDrawSurfaceImpl *)surf;
1622 IDirectDrawImpl *This = surfImpl->ddraw;
1624 IWineD3DSurface *wineD3DSurface;
1625 IWineD3DSwapChain *swapchain;
1627 IWineD3DClipper *clipper = NULL;
1629 WINED3DSURFACE_DESC Desc;
1630 WINED3DFORMAT Format;
1634 WINED3DMULTISAMPLE_TYPE MultiSampleType;
1635 DWORD MultiSampleQuality;
1639 TRACE("(%p): Enumerated Surface %p\n", This, surfImpl);
1641 /* For the enumeration */
1642 IDirectDrawSurface7_Release(surf);
1644 if(surfImpl->ImplType == This->ImplType) return DDENUMRET_OK; /* Continue */
1646 /* Get the objects */
1647 swapchain = surfImpl->wineD3DSwapChain;
1648 surfImpl->wineD3DSwapChain = NULL;
1649 wineD3DSurface = surfImpl->WineD3DSurface;
1651 /* get the clipper */
1652 IWineD3DSurface_GetClipper(wineD3DSurface, &clipper);
1654 /* Get the surface properties */
1655 hr = IWineD3DSurface_GetDesc(wineD3DSurface, &Desc);
1656 if(hr != D3D_OK) return hr;
1658 Format = Desc.format;
1661 MultiSampleType = Desc.multisample_type;
1662 MultiSampleQuality = Desc.multisample_quality;
1664 Height = Desc.height;
1666 IWineD3DSurface_GetParent(wineD3DSurface, &Parent);
1668 /* Create the new surface */
1669 hr = IWineD3DDevice_CreateSurface(This->wineD3DDevice, Width, Height, Format,
1670 TRUE /* Lockable */, FALSE /* Discard */, surfImpl->mipmap_level, &surfImpl->WineD3DSurface, Usage, Pool,
1671 MultiSampleType, MultiSampleQuality, This->ImplType, Parent, &ddraw_null_wined3d_parent_ops);
1672 IUnknown_Release(Parent);
1675 surfImpl->WineD3DSurface = wineD3DSurface;
1679 IWineD3DSurface_SetClipper(surfImpl->WineD3DSurface, clipper);
1681 /* TODO: Copy the surface content, except for render targets */
1683 /* If there's a swapchain, it owns the wined3d surfaces. So Destroy
1687 /* The backbuffers have the swapchain set as well, but the primary
1688 * owns it and destroys it
1690 if(surfImpl->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) {
1691 IWineD3DDevice_UninitGDI(This->wineD3DDevice, D3D7CB_DestroySwapChain);
1693 surfImpl->isRenderTarget = FALSE;
1695 if(IWineD3DSurface_Release(wineD3DSurface) == 0)
1696 TRACE("Surface released successful, next surface\n");
1698 ERR("Something's still holding the old WineD3DSurface\n");
1701 surfImpl->ImplType = This->ImplType;
1705 IWineD3DClipper_Release(clipper);
1707 return DDENUMRET_OK;
1710 /*****************************************************************************
1711 * IDirectDrawImpl_RecreateAllSurfaces
1713 * A function, that converts all wineD3DSurfaces to the new implementation type
1714 * It enumerates all surfaces with IWineD3DDevice::EnumSurfaces, creates a
1715 * new WineD3DSurface, copies the content and releases the old surface
1717 *****************************************************************************/
1719 IDirectDrawImpl_RecreateAllSurfaces(IDirectDrawImpl *This)
1721 DDSURFACEDESC2 desc;
1722 TRACE("(%p): Switch to implementation %d\n", This, This->ImplType);
1724 if(This->ImplType != SURFACE_OPENGL && This->d3d_initialized)
1726 /* Should happen almost never */
1727 FIXME("(%p) Switching to non-opengl surfaces with d3d started. Is this a bug?\n", This);
1729 IWineD3DDevice_Uninit3D(This->wineD3DDevice, D3D7CB_DestroySwapChain);
1731 /* Contrary: D3D starting is handled by the caller, because it knows the render target */
1733 memset(&desc, 0, sizeof(desc));
1734 desc.dwSize = sizeof(desc);
1736 return IDirectDraw7_EnumSurfaces((IDirectDraw7 *)This, 0, &desc, This, IDirectDrawImpl_RecreateSurfacesCallback);
1739 ULONG WINAPI D3D7CB_DestroySwapChain(IWineD3DSwapChain *pSwapChain) {
1740 IUnknown* swapChainParent;
1741 TRACE("(%p) call back\n", pSwapChain);
1743 IWineD3DSwapChain_GetParent(pSwapChain, &swapChainParent);
1744 IUnknown_Release(swapChainParent);
1745 return IUnknown_Release(swapChainParent);
1748 /*****************************************************************************
1749 * IDirectDrawImpl_CreateNewSurface
1751 * A helper function for IDirectDraw7::CreateSurface. It creates a new surface
1752 * with the passed parameters.
1755 * DDSD: Description of the surface to create
1756 * Surf: Address to store the interface pointer at
1761 *****************************************************************************/
1763 IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
1764 DDSURFACEDESC2 *pDDSD,
1765 IDirectDrawSurfaceImpl **ppSurf,
1770 WINED3DFORMAT Format = WINED3DFMT_UNKNOWN;
1772 WINED3DSURFTYPE ImplType = This->ImplType;
1773 WINED3DSURFACE_DESC Desc;
1774 WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
1776 if (TRACE_ON(ddraw))
1778 TRACE(" (%p) Requesting surface desc :\n", This);
1779 DDRAW_dump_surface_desc(pDDSD);
1782 /* Select the surface type, if it wasn't choosen yet */
1783 if(ImplType == SURFACE_UNKNOWN)
1785 /* Use GL Surfaces if a D3DDEVICE Surface is requested */
1786 if(pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
1788 TRACE("(%p) Choosing GL surfaces because a 3DDEVICE Surface was requested\n", This);
1789 ImplType = SURFACE_OPENGL;
1792 /* Otherwise use GDI surfaces for now */
1795 TRACE("(%p) Choosing GDI surfaces for 2D rendering\n", This);
1796 ImplType = SURFACE_GDI;
1799 /* Policy if all surface implementations are available:
1800 * First, check if a default type was set with winecfg. If not,
1801 * try Xrender surfaces, and use them if they work. Next, check if
1802 * accelerated OpenGL is available, and use GL surfaces in this
1803 * case. If all else fails, use GDI surfaces. If a 3DDEVICE surface
1804 * was created, always use OpenGL surfaces.
1806 * (Note: Xrender surfaces are not implemented for now, the
1807 * unaccelerated implementation uses GDI to render in Software)
1810 /* Store the type. If it needs to be changed, all WineD3DSurfaces have to
1811 * be re-created. This could be done with IDirectDrawSurface7::Restore
1813 This->ImplType = ImplType;
1817 if ((pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
1818 && (This->ImplType != SURFACE_OPENGL)
1819 && DefaultSurfaceType == SURFACE_UNKNOWN)
1821 /* We have to change to OpenGL,
1822 * and re-create all WineD3DSurfaces
1824 ImplType = SURFACE_OPENGL;
1825 This->ImplType = ImplType;
1826 TRACE("(%p) Re-creating all surfaces\n", This);
1827 IDirectDrawImpl_RecreateAllSurfaces(This);
1828 TRACE("(%p) Done recreating all surfaces\n", This);
1830 else if(This->ImplType != SURFACE_OPENGL && pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
1832 WARN("The application requests a 3D capable surface, but a non-opengl surface was set in the registry\n");
1833 /* Do not fail surface creation, only fail 3D device creation */
1837 if (!(pDDSD->ddsCaps.dwCaps & (DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY)) &&
1838 !((pDDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE) && (pDDSD->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) )
1840 /* Tests show surfaces without memory flags get these flags added right after creation. */
1841 pDDSD->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
1843 /* Get the correct wined3d usage */
1844 if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
1845 DDSCAPS_3DDEVICE ) )
1847 Usage |= WINED3DUSAGE_RENDERTARGET;
1849 pDDSD->ddsCaps.dwCaps |= DDSCAPS_VISIBLE;
1851 if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_OVERLAY))
1853 Usage |= WINED3DUSAGE_OVERLAY;
1855 if(This->depthstencil || (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) )
1857 /* The depth stencil creation callback sets this flag.
1858 * Set the WineD3D usage to let it know that it's a depth
1861 Usage |= WINED3DUSAGE_DEPTHSTENCIL;
1863 if(pDDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
1865 Pool = WINED3DPOOL_SYSTEMMEM;
1867 else if(pDDSD->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
1869 Pool = WINED3DPOOL_MANAGED;
1870 /* Managed textures have the system memory flag set */
1871 pDDSD->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
1873 else if(pDDSD->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
1875 /* Videomemory adds localvidmem, this is mutually exclusive with systemmemory
1878 pDDSD->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM;
1881 Format = PixelFormat_DD2WineD3D(&pDDSD->u4.ddpfPixelFormat);
1882 if(Format == WINED3DFMT_UNKNOWN)
1884 ERR("Unsupported / Unknown pixelformat\n");
1885 return DDERR_INVALIDPIXELFORMAT;
1888 /* Create the Surface object */
1889 *ppSurf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectDrawSurfaceImpl));
1892 ERR("(%p) Error allocating memory for a surface\n", This);
1893 return DDERR_OUTOFVIDEOMEMORY;
1895 (*ppSurf)->lpVtbl = &IDirectDrawSurface7_Vtbl;
1896 (*ppSurf)->IDirectDrawSurface3_vtbl = &IDirectDrawSurface3_Vtbl;
1897 (*ppSurf)->IDirectDrawGammaControl_vtbl = &IDirectDrawGammaControl_Vtbl;
1898 (*ppSurf)->IDirect3DTexture2_vtbl = &IDirect3DTexture2_Vtbl;
1899 (*ppSurf)->IDirect3DTexture_vtbl = &IDirect3DTexture1_Vtbl;
1901 (*ppSurf)->version = 7;
1902 TRACE("%p->version = %d\n", (*ppSurf), (*ppSurf)->version);
1903 (*ppSurf)->ddraw = This;
1904 (*ppSurf)->surface_desc.dwSize = sizeof(DDSURFACEDESC2);
1905 (*ppSurf)->surface_desc.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1906 DD_STRUCT_COPY_BYSIZE(&(*ppSurf)->surface_desc, pDDSD);
1908 /* Surface attachments */
1909 (*ppSurf)->next_attached = NULL;
1910 (*ppSurf)->first_attached = *ppSurf;
1912 /* Needed to re-create the surface on an implementation change */
1913 (*ppSurf)->ImplType = ImplType;
1915 /* For D3DDevice creation */
1916 (*ppSurf)->isRenderTarget = FALSE;
1918 /* A trace message for debugging */
1919 TRACE("(%p) Created IDirectDrawSurface implementation structure at %p\n", This, *ppSurf);
1921 /* Now create the WineD3D Surface */
1922 hr = IWineD3DDevice_CreateSurface(This->wineD3DDevice, pDDSD->dwWidth, pDDSD->dwHeight, Format,
1923 TRUE /* Lockable */, FALSE /* Discard */, level, &(*ppSurf)->WineD3DSurface,
1924 Usage, Pool, WINED3DMULTISAMPLE_NONE, 0 /* MultiSampleQuality */, ImplType,
1925 (IUnknown *)*ppSurf, &ddraw_null_wined3d_parent_ops);
1929 ERR("IWineD3DDevice::CreateSurface failed. hr = %08x\n", hr);
1933 /* Increase the surface counter, and attach the surface */
1934 InterlockedIncrement(&This->surfaces);
1935 list_add_head(&This->surface_list, &(*ppSurf)->surface_list_entry);
1937 /* Here we could store all created surfaces in the DirectDrawImpl structure,
1938 * But this could also be delegated to WineDDraw, as it keeps track of all its
1939 * resources. Not implemented for now, as there are more important things ;)
1942 /* Get the pixel format of the WineD3DSurface and store it.
1943 * Don't use the Format choosen above, WineD3D might have
1946 (*ppSurf)->surface_desc.dwFlags |= DDSD_PIXELFORMAT;
1947 hr = IWineD3DSurface_GetDesc((*ppSurf)->WineD3DSurface, &Desc);
1950 ERR("IWineD3DSurface::GetDesc failed\n");
1951 IDirectDrawSurface7_Release( (IDirectDrawSurface7 *) *ppSurf);
1955 Format = Desc.format;
1957 Height = Desc.height;
1959 if(Format == WINED3DFMT_UNKNOWN)
1961 FIXME("IWineD3DSurface::GetDesc returned WINED3DFMT_UNKNOWN\n");
1963 PixelFormat_WineD3DtoDD( &(*ppSurf)->surface_desc.u4.ddpfPixelFormat, Format);
1965 /* Anno 1602 stores the pitch right after surface creation, so make sure it's there.
1966 * I can't LockRect() the surface here because if OpenGL surfaces are in use, the
1967 * WineD3DDevice might not be usable for 3D yet, so an extra method was created.
1968 * TODO: Test other fourcc formats
1970 if(Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
1971 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5)
1973 (*ppSurf)->surface_desc.dwFlags |= DDSD_LINEARSIZE;
1974 if(Format == WINED3DFMT_DXT1)
1976 (*ppSurf)->surface_desc.u1.dwLinearSize = max(4, Width) * max(4, Height) / 2;
1980 (*ppSurf)->surface_desc.u1.dwLinearSize = max(4, Width) * max(4, Height);
1985 (*ppSurf)->surface_desc.dwFlags |= DDSD_PITCH;
1986 (*ppSurf)->surface_desc.u1.lPitch = IWineD3DSurface_GetPitch((*ppSurf)->WineD3DSurface);
1989 /* Application passed a color key? Set it! */
1990 if(pDDSD->dwFlags & DDSD_CKDESTOVERLAY)
1992 IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
1994 (WINEDDCOLORKEY *) &pDDSD->u3.ddckCKDestOverlay);
1996 if(pDDSD->dwFlags & DDSD_CKDESTBLT)
1998 IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2000 (WINEDDCOLORKEY *) &pDDSD->ddckCKDestBlt);
2002 if(pDDSD->dwFlags & DDSD_CKSRCOVERLAY)
2004 IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2006 (WINEDDCOLORKEY *) &pDDSD->ddckCKSrcOverlay);
2008 if(pDDSD->dwFlags & DDSD_CKSRCBLT)
2010 IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2012 (WINEDDCOLORKEY *) &pDDSD->ddckCKSrcBlt);
2014 if ( pDDSD->dwFlags & DDSD_LPSURFACE)
2016 hr = IWineD3DSurface_SetMem((*ppSurf)->WineD3DSurface, pDDSD->lpSurface);
2017 if(hr != WINED3D_OK)
2019 /* No need for a trace here, wined3d does that for us */
2020 IDirectDrawSurface7_Release((IDirectDrawSurface7 *)*ppSurf);
2027 /*****************************************************************************
2028 * CreateAdditionalSurfaces
2030 * Creates a new mipmap chain.
2033 * root: Root surface to attach the newly created chain to
2034 * count: number of surfaces to create
2035 * DDSD: Description of the surface. Intentionally not a pointer to avoid side
2036 * effects on the caller
2037 * CubeFaceRoot: Whether the new surface is a root of a cube map face. This
2038 * creates an additional surface without the mipmapping flags
2040 *****************************************************************************/
2042 CreateAdditionalSurfaces(IDirectDrawImpl *This,
2043 IDirectDrawSurfaceImpl *root,
2045 DDSURFACEDESC2 DDSD,
2048 UINT i, j, level = 0;
2050 IDirectDrawSurfaceImpl *last = root;
2052 for(i = 0; i < count; i++)
2054 IDirectDrawSurfaceImpl *object2 = NULL;
2056 /* increase the mipmap level, but only if a mipmap is created
2057 * In this case, also halve the size
2059 if(DDSD.ddsCaps.dwCaps & DDSCAPS_MIPMAP && !CubeFaceRoot)
2062 if(DDSD.dwWidth > 1) DDSD.dwWidth /= 2;
2063 if(DDSD.dwHeight > 1) DDSD.dwHeight /= 2;
2064 /* Set the mipmap sublevel flag according to msdn */
2065 DDSD.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
2069 DDSD.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
2071 CubeFaceRoot = FALSE;
2073 hr = IDirectDrawImpl_CreateNewSurface(This,
2082 /* Add the new surface to the complex attachment array */
2083 for(j = 0; j < MAX_COMPLEX_ATTACHED; j++)
2085 if(last->complex_array[j]) continue;
2086 last->complex_array[j] = object2;
2091 /* Remove the (possible) back buffer cap from the new surface description,
2092 * because only one surface in the flipping chain is a back buffer, one
2093 * is a front buffer, the others are just primary surfaces.
2095 DDSD.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
2100 /*****************************************************************************
2101 * IDirectDrawImpl_AttachD3DDevice
2103 * Initializes the D3D capabilities of WineD3D
2106 * primary: The primary surface for D3D
2112 *****************************************************************************/
2113 static HRESULT IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *primary)
2115 WINED3DPRESENT_PARAMETERS localParameters;
2116 HWND window = ddraw->dest_window;
2119 TRACE("ddraw %p, primary %p.\n", ddraw, primary);
2121 if (!window || window == GetDesktopWindow())
2123 window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "Hidden D3D Window",
2124 WS_DISABLED, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
2125 NULL, NULL, NULL, NULL);
2128 ERR("Failed to create window, last error %#x.\n", GetLastError());
2132 ShowWindow(window, SW_HIDE); /* Just to be sure */
2133 WARN("No window for the Direct3DDevice, created hidden window %p.\n", window);
2137 TRACE("Using existing window %p for Direct3D rendering.\n", window);
2139 ddraw->d3d_window = window;
2141 /* Store the future Render Target surface */
2142 ddraw->d3d_target = primary;
2144 /* Use the surface description for the device parameters, not the device
2145 * settings. The application might render to an offscreen surface. */
2146 localParameters.BackBufferWidth = primary->surface_desc.dwWidth;
2147 localParameters.BackBufferHeight = primary->surface_desc.dwHeight;
2148 localParameters.BackBufferFormat = PixelFormat_DD2WineD3D(&primary->surface_desc.u4.ddpfPixelFormat);
2149 localParameters.BackBufferCount = (primary->surface_desc.dwFlags & DDSD_BACKBUFFERCOUNT)
2150 ? primary->surface_desc.dwBackBufferCount : 0;
2151 localParameters.MultiSampleType = WINED3DMULTISAMPLE_NONE;
2152 localParameters.MultiSampleQuality = 0;
2153 localParameters.SwapEffect = WINED3DSWAPEFFECT_COPY;
2154 localParameters.hDeviceWindow = window;
2155 localParameters.Windowed = !(ddraw->cooperative_level & DDSCL_FULLSCREEN);
2156 localParameters.EnableAutoDepthStencil = TRUE;
2157 localParameters.AutoDepthStencilFormat = WINED3DFMT_D16_UNORM;
2158 localParameters.Flags = 0;
2159 localParameters.FullScreen_RefreshRateInHz = WINED3DPRESENT_RATE_DEFAULT;
2160 localParameters.PresentationInterval = WINED3DPRESENT_INTERVAL_DEFAULT;
2162 /* Set this NOW, otherwise creating the depth stencil surface will cause a
2163 * recursive loop until ram or emulated video memory is full. */
2164 ddraw->d3d_initialized = TRUE;
2165 hr = IWineD3DDevice_Init3D(ddraw->wineD3DDevice, &localParameters);
2168 ddraw->d3d_target = NULL;
2169 ddraw->d3d_initialized = FALSE;
2173 ddraw->declArraySize = 2;
2174 ddraw->decls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw->decls) * ddraw->declArraySize);
2177 ERR("Error allocating an array for the converted vertex decls.\n");
2178 ddraw->declArraySize = 0;
2179 hr = IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroySwapChain);
2180 return E_OUTOFMEMORY;
2183 TRACE("Successfully initialized 3D.\n");
2188 static HRESULT IDirectDrawImpl_CreateGDISwapChain(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *primary)
2190 WINED3DPRESENT_PARAMETERS presentation_parameters;
2194 window = ddraw->dest_window;
2196 memset(&presentation_parameters, 0, sizeof(presentation_parameters));
2198 /* Use the surface description for the device parameters, not the device
2199 * settings. The application might render to an offscreen surface. */
2200 presentation_parameters.BackBufferWidth = primary->surface_desc.dwWidth;
2201 presentation_parameters.BackBufferHeight = primary->surface_desc.dwHeight;
2202 presentation_parameters.BackBufferFormat = PixelFormat_DD2WineD3D(&primary->surface_desc.u4.ddpfPixelFormat);
2203 presentation_parameters.BackBufferCount = (primary->surface_desc.dwFlags & DDSD_BACKBUFFERCOUNT)
2204 ? primary->surface_desc.dwBackBufferCount : 0;
2205 presentation_parameters.MultiSampleType = WINED3DMULTISAMPLE_NONE;
2206 presentation_parameters.MultiSampleQuality = 0;
2207 presentation_parameters.SwapEffect = WINED3DSWAPEFFECT_FLIP;
2208 presentation_parameters.hDeviceWindow = window;
2209 presentation_parameters.Windowed = !(ddraw->cooperative_level & DDSCL_FULLSCREEN);
2210 presentation_parameters.EnableAutoDepthStencil = FALSE; /* Not on GDI swapchains */
2211 presentation_parameters.AutoDepthStencilFormat = 0;
2212 presentation_parameters.Flags = 0;
2213 presentation_parameters.FullScreen_RefreshRateInHz = WINED3DPRESENT_RATE_DEFAULT;
2214 presentation_parameters.PresentationInterval = WINED3DPRESENT_INTERVAL_DEFAULT;
2216 ddraw->d3d_target = primary;
2217 hr = IWineD3DDevice_InitGDI(ddraw->wineD3DDevice, &presentation_parameters);
2218 ddraw->d3d_target = NULL;
2221 WARN("Failed to initialize GDI ddraw implementation, hr %#x.\n", hr);
2222 primary->wineD3DSwapChain = NULL;
2228 /*****************************************************************************
2229 * IDirectDraw7::CreateSurface
2231 * Creates a new IDirectDrawSurface object and returns its interface.
2233 * The surface connections with wined3d are a bit tricky. Basically it works
2236 * |------------------------| |-----------------|
2237 * | DDraw surface | | WineD3DSurface |
2239 * | WineD3DSurface |-------------->| |
2240 * | Child |<------------->| Parent |
2241 * |------------------------| |-----------------|
2243 * The DDraw surface is the parent of the wined3d surface, and it releases
2244 * the WineD3DSurface when the ddraw surface is destroyed.
2246 * However, for all surfaces which can be in a container in WineD3D,
2247 * we have to do this. These surfaces are usually complex surfaces,
2248 * so this concerns primary surfaces with a front and a back buffer,
2251 * |------------------------| |-----------------|
2252 * | DDraw surface | | Container |
2254 * | Child |<------------->| Parent |
2255 * | Texture |<------------->| |
2256 * | WineD3DSurface |<----| | Levels |<--|
2257 * | Complex connection | | | | |
2258 * |------------------------| | |-----------------| |
2262 * | |------------------| | |-----------------| |
2263 * | | IParent | |-------->| WineD3DSurface | |
2265 * | | Child |<------------->| Parent | |
2266 * | | | | Container |<--|
2267 * | |------------------| |-----------------| |
2269 * | |----------------------| |
2270 * | | DDraw surface 2 | |
2272 * |<->| Complex root Child | |
2274 * | | WineD3DSurface |<----| |
2275 * | |----------------------| | |
2277 * | |---------------------| | |-----------------| |
2278 * | | IParent | |----->| WineD3DSurface | |
2280 * | | Child |<---------->| Parent | |
2281 * | |---------------------| | Container |<--|
2282 * | |-----------------| |
2284 * | ---More surfaces can follow--- |
2286 * The reason is that the IWineD3DSwapchain(render target container)
2287 * and the IWineD3DTexure(Texture container) release the parents
2288 * of their surface's children, but by releasing the complex root
2289 * the surfaces which are complexly attached to it are destroyed
2290 * too. See IDirectDrawSurface::Release for a more detailed
2294 * DDSD: Description of the surface to create
2295 * Surf: Address to store the interface pointer at
2296 * UnkOuter: Basically for aggregation support, but ddraw doesn't support
2297 * aggregation, so it has to be NULL
2301 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
2302 * DDERR_* if an error occurs
2304 *****************************************************************************/
2305 static HRESULT WINAPI
2306 IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
2307 DDSURFACEDESC2 *DDSD,
2308 IDirectDrawSurface7 **Surf,
2311 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2312 IDirectDrawSurfaceImpl *object = NULL;
2314 LONG extra_surfaces = 0;
2315 DDSURFACEDESC2 desc2;
2316 WINED3DDISPLAYMODE Mode;
2317 const DWORD sysvidmem = DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
2319 TRACE("(%p)->(%p,%p,%p)\n", This, DDSD, Surf, UnkOuter);
2321 /* Some checks before we start */
2322 if (TRACE_ON(ddraw))
2324 TRACE(" (%p) Requesting surface desc :\n", This);
2325 DDRAW_dump_surface_desc(DDSD);
2327 EnterCriticalSection(&ddraw_cs);
2329 if (UnkOuter != NULL)
2331 FIXME("(%p) : outer != NULL?\n", This);
2332 LeaveCriticalSection(&ddraw_cs);
2333 return CLASS_E_NOAGGREGATION; /* unchecked */
2338 FIXME("(%p) You want to get back a surface? Don't give NULL ptrs!\n", This);
2339 LeaveCriticalSection(&ddraw_cs);
2340 return E_POINTER; /* unchecked */
2343 if (!(DDSD->dwFlags & DDSD_CAPS))
2345 /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
2346 DDSD->dwFlags |= DDSD_CAPS;
2349 if (DDSD->ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD)
2351 /* If the surface is of the 'alloconload' type, ignore the LPSURFACE field */
2352 DDSD->dwFlags &= ~DDSD_LPSURFACE;
2355 if ((DDSD->dwFlags & DDSD_LPSURFACE) && (DDSD->lpSurface == NULL))
2357 /* Frank Herbert's Dune specifies a null pointer for the surface, ignore the LPSURFACE field */
2358 WARN("(%p) Null surface pointer specified, ignore it!\n", This);
2359 DDSD->dwFlags &= ~DDSD_LPSURFACE;
2362 if((DDSD->ddsCaps.dwCaps & (DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE)) == (DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE) &&
2363 !(This->cooperative_level & DDSCL_EXCLUSIVE))
2365 TRACE("(%p): Attempt to create a flipable primary surface without DDSCL_EXCLUSIVE set\n", This);
2367 LeaveCriticalSection(&ddraw_cs);
2368 return DDERR_NOEXCLUSIVEMODE;
2371 if(DDSD->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER)) {
2372 WARN("Application tried to create an explicit front or back buffer\n");
2373 LeaveCriticalSection(&ddraw_cs);
2374 return DDERR_INVALIDCAPS;
2377 if((DDSD->ddsCaps.dwCaps & sysvidmem) == sysvidmem)
2379 /* This is a special switch in ddrawex.dll, but not allowed in ddraw.dll */
2380 WARN("Application tries to put the surface in both system and video memory\n");
2381 LeaveCriticalSection(&ddraw_cs);
2383 return DDERR_INVALIDCAPS;
2386 /* Check cube maps but only if the size includes them */
2387 if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
2389 if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES &&
2390 !(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
2392 WARN("Cube map faces requested without cube map flag\n");
2393 LeaveCriticalSection(&ddraw_cs);
2394 return DDERR_INVALIDCAPS;
2396 if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
2397 (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) == 0)
2399 WARN("Cube map without faces requested\n");
2400 LeaveCriticalSection(&ddraw_cs);
2401 return DDERR_INVALIDPARAMS;
2404 /* Quick tests confirm those can be created, but we don't do that yet */
2405 if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
2406 (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) != DDSCAPS2_CUBEMAP_ALLFACES)
2408 FIXME("Partial cube maps not supported yet\n");
2412 /* According to the msdn this flag is ignored by CreateSurface */
2413 if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
2414 DDSD->ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
2416 /* Modify some flags */
2417 memset(&desc2, 0, sizeof(desc2));
2418 desc2.dwSize = sizeof(desc2); /* For the struct copy */
2419 DD_STRUCT_COPY_BYSIZE(&desc2, DDSD);
2420 desc2.dwSize = sizeof(desc2); /* To override a possibly smaller size */
2421 desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT); /* Just to be sure */
2423 /* Get the video mode from WineD3D - we will need it */
2424 hr = IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
2425 0, /* Swapchain 0 */
2429 ERR("Failed to read display mode from wined3d\n");
2430 switch(This->orig_bpp)
2433 Mode.Format = WINED3DFMT_P8_UINT;
2437 Mode.Format = WINED3DFMT_B5G5R5X1_UNORM;
2441 Mode.Format = WINED3DFMT_B5G6R5_UNORM;
2445 Mode.Format = WINED3DFMT_B8G8R8_UNORM;
2449 Mode.Format = WINED3DFMT_B8G8R8X8_UNORM;
2452 Mode.Width = This->orig_width;
2453 Mode.Height = This->orig_height;
2456 /* No pixelformat given? Use the current screen format */
2457 if(!(desc2.dwFlags & DDSD_PIXELFORMAT))
2459 desc2.dwFlags |= DDSD_PIXELFORMAT;
2460 desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT);
2462 /* Wait: It could be a Z buffer */
2463 if(desc2.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
2465 switch(desc2.u2.dwMipMapCount) /* Who had this glorious idea? */
2468 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_S1_UINT_D15_UNORM);
2471 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D16_UNORM);
2474 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_X8D24_UNORM);
2477 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D32_UNORM);
2480 ERR("Unknown Z buffer bit depth\n");
2485 PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, Mode.Format);
2489 /* No Width or no Height? Use the original screen size
2491 if(!(desc2.dwFlags & DDSD_WIDTH) ||
2492 !(desc2.dwFlags & DDSD_HEIGHT) )
2494 /* Invalid for non-render targets */
2495 if(!(desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
2497 WARN("Creating a non-Primary surface without Width or Height info, returning DDERR_INVALIDPARAMS\n");
2499 LeaveCriticalSection(&ddraw_cs);
2500 return DDERR_INVALIDPARAMS;
2503 desc2.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
2504 desc2.dwWidth = Mode.Width;
2505 desc2.dwHeight = Mode.Height;
2508 /* Mipmap count fixes */
2509 if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
2511 if(desc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
2513 if(desc2.dwFlags & DDSD_MIPMAPCOUNT)
2515 /* Mipmap count is given, should not be 0 */
2516 if( desc2.u2.dwMipMapCount == 0 )
2518 LeaveCriticalSection(&ddraw_cs);
2519 return DDERR_INVALIDPARAMS;
2524 /* Undocumented feature: Create sublevels until
2525 * either the width or the height is 1
2527 DWORD min = desc2.dwWidth < desc2.dwHeight ?
2528 desc2.dwWidth : desc2.dwHeight;
2529 desc2.u2.dwMipMapCount = 0;
2532 desc2.u2.dwMipMapCount += 1;
2539 /* Not-complex mipmap -> Mipmapcount = 1 */
2540 desc2.u2.dwMipMapCount = 1;
2542 extra_surfaces = desc2.u2.dwMipMapCount - 1;
2544 /* There's a mipmap count in the created surface in any case */
2545 desc2.dwFlags |= DDSD_MIPMAPCOUNT;
2547 /* If no mipmap is given, the texture has only one level */
2549 /* The first surface is a front buffer, the back buffer is created afterwards */
2550 if( (desc2.dwFlags & DDSD_CAPS) && (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) )
2552 desc2.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER;
2555 /* The root surface in a cube map is positive x */
2556 if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
2558 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
2559 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
2562 /* Create the first surface */
2563 hr = IDirectDrawImpl_CreateNewSurface(This, &desc2, &object, 0);
2566 ERR("IDirectDrawImpl_CreateNewSurface failed with %08x\n", hr);
2567 LeaveCriticalSection(&ddraw_cs);
2570 object->is_complex_root = TRUE;
2572 *Surf = (IDirectDrawSurface7 *)object;
2574 /* Create Additional surfaces if necessary
2575 * This applies to Primary surfaces which have a back buffer count
2576 * set, but not to mipmap textures. In case of Mipmap textures,
2577 * wineD3D takes care of the creation of additional surfaces
2579 if(DDSD->dwFlags & DDSD_BACKBUFFERCOUNT)
2581 extra_surfaces = DDSD->dwBackBufferCount;
2582 desc2.ddsCaps.dwCaps &= ~DDSCAPS_FRONTBUFFER; /* It's not a front buffer */
2583 desc2.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
2584 desc2.dwBackBufferCount = 0;
2588 if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
2590 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
2591 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEZ;
2592 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2593 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEZ;
2594 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEZ;
2595 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2596 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEZ;
2597 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEY;
2598 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2599 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEY;
2600 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEY;
2601 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2602 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEY;
2603 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEX;
2604 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2605 desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEX;
2606 desc2.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
2609 hr |= CreateAdditionalSurfaces(This, object, extra_surfaces, desc2, FALSE);
2612 /* This destroys and possibly created surfaces too */
2613 IDirectDrawSurface_Release((IDirectDrawSurface7 *)object);
2614 LeaveCriticalSection(&ddraw_cs);
2618 /* If the implementation is OpenGL and there's no d3ddevice, attach a d3ddevice
2619 * But attach the d3ddevice only if the currently created surface was
2620 * a primary surface (2D app in 3D mode) or a 3DDEVICE surface (3D app)
2621 * The only case I can think of where this doesn't apply is when a
2622 * 2D app was configured by the user to run with OpenGL and it didn't create
2623 * the render target as first surface. In this case the render target creation
2624 * will cause the 3D init.
2626 if( (This->ImplType == SURFACE_OPENGL) && !(This->d3d_initialized) &&
2627 desc2.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE) )
2629 IDirectDrawSurfaceImpl *target = object, *surface;
2632 /* Search for the primary to use as render target */
2633 LIST_FOR_EACH(entry, &This->surface_list)
2635 surface = LIST_ENTRY(entry, IDirectDrawSurfaceImpl, surface_list_entry);
2636 if((surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER)) ==
2637 (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER))
2641 TRACE("Using primary %p as render target\n", target);
2646 TRACE("(%p) Attaching a D3DDevice, rendertarget = %p\n", This, target);
2647 hr = IDirectDrawImpl_AttachD3DDevice(This, target);
2650 IDirectDrawSurfaceImpl *release_surf;
2651 ERR("IDirectDrawImpl_AttachD3DDevice failed, hr = %x\n", hr);
2654 /* The before created surface structures are in an incomplete state here.
2655 * WineD3D holds the reference on the IParents, and it released them on the failure
2656 * already. So the regular release method implementation would fail on the attempt
2657 * to destroy either the IParents or the swapchain. So free the surface here.
2658 * The surface structure here is a list, not a tree, because onscreen targets
2659 * cannot be cube textures
2663 release_surf = object;
2664 object = object->complex_array[0];
2665 IDirectDrawSurfaceImpl_Destroy(release_surf);
2667 LeaveCriticalSection(&ddraw_cs);
2670 } else if(!(This->d3d_initialized) && desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) {
2671 IDirectDrawImpl_CreateGDISwapChain(This, object);
2674 /* Addref the ddraw interface to keep an reference for each surface */
2675 IDirectDraw7_AddRef(iface);
2676 object->ifaceToRelease = (IUnknown *) iface;
2678 /* Create a WineD3DTexture if a texture was requested */
2679 if(desc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE)
2682 WINED3DFORMAT Format;
2683 WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
2685 This->tex_root = object;
2687 if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
2689 /* a mipmap is created, create enough levels */
2690 levels = desc2.u2.dwMipMapCount;
2694 /* No mipmap is created, create one level */
2698 /* DDSCAPS_SYSTEMMEMORY textures are in WINED3DPOOL_SYSTEMMEM */
2699 if(DDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
2701 Pool = WINED3DPOOL_SYSTEMMEM;
2703 /* Should I forward the MANAGED cap to the managed pool ? */
2705 /* Get the format. It's set already by CreateNewSurface */
2706 Format = PixelFormat_DD2WineD3D(&object->surface_desc.u4.ddpfPixelFormat);
2708 /* The surfaces are already created, the callback only
2709 * passes the IWineD3DSurface to WineD3D
2711 if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
2713 hr = IWineD3DDevice_CreateCubeTexture(This->wineD3DDevice, DDSD->dwWidth /* Edgelength */,
2714 levels, 0 /* usage */, Format, Pool, (IWineD3DCubeTexture **)&object->wineD3DTexture,
2715 (IUnknown *)object, &ddraw_null_wined3d_parent_ops);
2719 hr = IWineD3DDevice_CreateTexture(This->wineD3DDevice, DDSD->dwWidth, DDSD->dwHeight, levels,
2720 0 /* usage */, Format, Pool, (IWineD3DTexture **)&object->wineD3DTexture,
2721 (IUnknown *)object, &ddraw_null_wined3d_parent_ops);
2723 This->tex_root = NULL;
2726 LeaveCriticalSection(&ddraw_cs);
2730 #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST)
2731 #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH)
2734 Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
2735 const DDPIXELFORMAT *provided)
2737 /* Some flags must be present in both or neither for a match. */
2738 static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
2739 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
2740 | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
2742 if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
2745 if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
2748 if (requested->dwFlags & DDPF_FOURCC)
2749 if (requested->dwFourCC != provided->dwFourCC)
2752 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
2753 |DDPF_LUMINANCE|DDPF_BUMPDUDV))
2754 if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
2757 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
2758 |DDPF_LUMINANCE|DDPF_BUMPDUDV))
2759 if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
2762 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
2763 if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
2766 /* I could be wrong about the bumpmapping. MSDN docs are vague. */
2767 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
2769 if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
2772 if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
2773 if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
2780 IDirectDrawImpl_DDSD_Match(const DDSURFACEDESC2* requested,
2781 const DDSURFACEDESC2* provided)
2790 #define CMP(FLAG, FIELD) \
2791 { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
2792 sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
2794 static const struct compare_info compare[] =
2796 CMP(ALPHABITDEPTH, dwAlphaBitDepth),
2797 CMP(BACKBUFFERCOUNT, dwBackBufferCount),
2799 CMP(CKDESTBLT, ddckCKDestBlt),
2800 CMP(CKDESTOVERLAY, u3 /* ddckCKDestOverlay */),
2801 CMP(CKSRCBLT, ddckCKSrcBlt),
2802 CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
2803 CMP(HEIGHT, dwHeight),
2804 CMP(LINEARSIZE, u1 /* dwLinearSize */),
2805 CMP(LPSURFACE, lpSurface),
2806 CMP(MIPMAPCOUNT, u2 /* dwMipMapCount */),
2807 CMP(PITCH, u1 /* lPitch */),
2808 /* PIXELFORMAT: manual */
2809 CMP(REFRESHRATE, u2 /* dwRefreshRate */),
2810 CMP(TEXTURESTAGE, dwTextureStage),
2811 CMP(WIDTH, dwWidth),
2812 /* ZBUFFERBITDEPTH: "obsolete" */
2819 if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
2822 for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++)
2824 if (requested->dwFlags & compare[i].flag
2825 && memcmp((const char *)provided + compare[i].offset,
2826 (const char *)requested + compare[i].offset,
2827 compare[i].size) != 0)
2831 if (requested->dwFlags & DDSD_PIXELFORMAT)
2833 if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
2834 &provided->u4.ddpfPixelFormat))
2841 #undef DDENUMSURFACES_SEARCHTYPE
2842 #undef DDENUMSURFACES_MATCHTYPE
2844 /*****************************************************************************
2845 * IDirectDraw7::EnumSurfaces
2847 * Loops through all surfaces attached to this device and calls the
2848 * application callback. This can't be relayed to WineD3DDevice,
2849 * because some WineD3DSurfaces' parents are IParent objects
2852 * Flags: Some filtering flags. See IDirectDrawImpl_EnumSurfacesCallback
2853 * DDSD: Description to filter for
2854 * Context: Application-provided pointer, it's passed unmodified to the
2856 * Callback: Address to call for each surface
2859 * DDERR_INVALIDPARAMS if the callback is NULL
2862 *****************************************************************************/
2863 static HRESULT WINAPI
2864 IDirectDrawImpl_EnumSurfaces(IDirectDraw7 *iface,
2866 DDSURFACEDESC2 *DDSD,
2868 LPDDENUMSURFACESCALLBACK7 Callback)
2870 /* The surface enumeration is handled by WineDDraw,
2871 * because it keeps track of all surfaces attached to
2872 * it. The filtering is done by our callback function,
2873 * because WineDDraw doesn't handle ddraw-like surface
2876 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2877 IDirectDrawSurfaceImpl *surf;
2879 DDSURFACEDESC2 desc;
2880 struct list *entry, *entry2;
2882 all = Flags & DDENUMSURFACES_ALL;
2883 nomatch = Flags & DDENUMSURFACES_NOMATCH;
2885 TRACE("(%p)->(%x,%p,%p,%p)\n", This, Flags, DDSD, Context, Callback);
2886 EnterCriticalSection(&ddraw_cs);
2890 LeaveCriticalSection(&ddraw_cs);
2891 return DDERR_INVALIDPARAMS;
2894 /* Use the _SAFE enumeration, the app may destroy enumerated surfaces */
2895 LIST_FOR_EACH_SAFE(entry, entry2, &This->surface_list)
2897 surf = LIST_ENTRY(entry, IDirectDrawSurfaceImpl, surface_list_entry);
2898 if (all || (nomatch != IDirectDrawImpl_DDSD_Match(DDSD, &surf->surface_desc)))
2900 desc = surf->surface_desc;
2901 IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)surf);
2902 if (Callback((IDirectDrawSurface7 *)surf, &desc, Context) != DDENUMRET_OK)
2904 LeaveCriticalSection(&ddraw_cs);
2909 LeaveCriticalSection(&ddraw_cs);
2913 /*****************************************************************************
2914 * DirectDrawCreateClipper (DDRAW.@)
2916 * Creates a new IDirectDrawClipper object.
2919 * Clipper: Address to write the interface pointer to
2920 * UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
2924 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
2925 * E_OUTOFMEMORY if allocating the object failed
2927 *****************************************************************************/
2929 DirectDrawCreateClipper(DWORD Flags,
2930 LPDIRECTDRAWCLIPPER *Clipper,
2933 IDirectDrawClipperImpl* object;
2934 TRACE("(%08x,%p,%p)\n", Flags, Clipper, UnkOuter);
2936 EnterCriticalSection(&ddraw_cs);
2937 if (UnkOuter != NULL)
2939 LeaveCriticalSection(&ddraw_cs);
2940 return CLASS_E_NOAGGREGATION;
2945 LeaveCriticalSection(&ddraw_cs);
2946 return DDERR_NODIRECTDRAWSUPPORT;
2949 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
2950 sizeof(IDirectDrawClipperImpl));
2953 LeaveCriticalSection(&ddraw_cs);
2954 return E_OUTOFMEMORY;
2957 object->lpVtbl = &IDirectDrawClipper_Vtbl;
2959 object->wineD3DClipper = pWineDirect3DCreateClipper((IUnknown *) object);
2960 if(!object->wineD3DClipper)
2962 HeapFree(GetProcessHeap(), 0, object);
2963 LeaveCriticalSection(&ddraw_cs);
2964 return E_OUTOFMEMORY;
2967 *Clipper = (IDirectDrawClipper *) object;
2968 LeaveCriticalSection(&ddraw_cs);
2972 /*****************************************************************************
2973 * IDirectDraw7::CreateClipper
2975 * Creates a DDraw clipper. See DirectDrawCreateClipper for details
2977 *****************************************************************************/
2978 static HRESULT WINAPI
2979 IDirectDrawImpl_CreateClipper(IDirectDraw7 *iface,
2981 IDirectDrawClipper **Clipper,
2984 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
2985 TRACE("(%p)->(%x,%p,%p)\n", This, Flags, Clipper, UnkOuter);
2986 return DirectDrawCreateClipper(Flags, Clipper, UnkOuter);
2989 /*****************************************************************************
2990 * IDirectDraw7::CreatePalette
2992 * Creates a new IDirectDrawPalette object
2995 * Flags: The flags for the new clipper
2996 * ColorTable: Color table to assign to the new clipper
2997 * Palette: Address to write the interface pointer to
2998 * UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3002 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
3003 * E_OUTOFMEMORY if allocating the object failed
3005 *****************************************************************************/
3006 static HRESULT WINAPI
3007 IDirectDrawImpl_CreatePalette(IDirectDraw7 *iface,
3009 PALETTEENTRY *ColorTable,
3010 IDirectDrawPalette **Palette,
3011 IUnknown *pUnkOuter)
3013 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
3014 IDirectDrawPaletteImpl *object;
3015 HRESULT hr = DDERR_GENERIC;
3016 TRACE("(%p)->(%x,%p,%p,%p)\n", This, Flags, ColorTable, Palette, pUnkOuter);
3018 EnterCriticalSection(&ddraw_cs);
3019 if(pUnkOuter != NULL)
3021 WARN("pUnkOuter is %p, returning CLASS_E_NOAGGREGATION\n", pUnkOuter);
3022 LeaveCriticalSection(&ddraw_cs);
3023 return CLASS_E_NOAGGREGATION;
3026 /* The refcount test shows that a cooplevel is required for this */
3027 if(!This->cooperative_level)
3029 WARN("No cooperative level set, returning DDERR_NOCOOPERATIVELEVELSET\n");
3030 LeaveCriticalSection(&ddraw_cs);
3031 return DDERR_NOCOOPERATIVELEVELSET;
3034 object = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectDrawPaletteImpl));
3037 ERR("Out of memory when allocating memory for a palette implementation\n");
3038 LeaveCriticalSection(&ddraw_cs);
3039 return E_OUTOFMEMORY;
3042 object->lpVtbl = &IDirectDrawPalette_Vtbl;
3045 hr = IWineD3DDevice_CreatePalette(This->wineD3DDevice, Flags,
3046 ColorTable, &object->wineD3DPalette, (IUnknown *)object);
3049 HeapFree(GetProcessHeap(), 0, object);
3050 LeaveCriticalSection(&ddraw_cs);
3054 IDirectDraw7_AddRef(iface);
3055 object->ifaceToRelease = (IUnknown *) iface;
3056 *Palette = (IDirectDrawPalette *)object;
3057 LeaveCriticalSection(&ddraw_cs);
3061 /*****************************************************************************
3062 * IDirectDraw7::DuplicateSurface
3064 * Duplicates a surface. The surface memory points to the same memory as
3065 * the original surface, and it's released when the last surface referencing
3066 * it is released. I guess that's beyond Wine's surface management right now
3067 * (Idea: create a new DDraw surface with the same WineD3DSurface. I need a
3068 * test application to implement this)
3071 * Src: Address of the source surface
3072 * Dest: Address to write the new surface pointer to
3075 * See IDirectDraw7::CreateSurface
3077 *****************************************************************************/
3078 static HRESULT WINAPI
3079 IDirectDrawImpl_DuplicateSurface(IDirectDraw7 *iface,
3080 IDirectDrawSurface7 *Src,
3081 IDirectDrawSurface7 **Dest)
3083 IDirectDrawImpl *This = (IDirectDrawImpl *)iface;
3084 IDirectDrawSurfaceImpl *Surf = (IDirectDrawSurfaceImpl *)Src;
3086 FIXME("(%p)->(%p,%p)\n", This, Surf, Dest);
3088 /* For now, simply create a new, independent surface */
3089 return IDirectDraw7_CreateSurface(iface,
3090 &Surf->surface_desc,
3095 /*****************************************************************************
3096 * IDirectDraw7 VTable
3097 *****************************************************************************/
3098 const IDirectDraw7Vtbl IDirectDraw7_Vtbl =
3101 IDirectDrawImpl_QueryInterface,
3102 IDirectDrawImpl_AddRef,
3103 IDirectDrawImpl_Release,
3104 /*** IDirectDraw ***/
3105 IDirectDrawImpl_Compact,
3106 IDirectDrawImpl_CreateClipper,
3107 IDirectDrawImpl_CreatePalette,
3108 IDirectDrawImpl_CreateSurface,
3109 IDirectDrawImpl_DuplicateSurface,
3110 IDirectDrawImpl_EnumDisplayModes,
3111 IDirectDrawImpl_EnumSurfaces,
3112 IDirectDrawImpl_FlipToGDISurface,
3113 IDirectDrawImpl_GetCaps,
3114 IDirectDrawImpl_GetDisplayMode,
3115 IDirectDrawImpl_GetFourCCCodes,
3116 IDirectDrawImpl_GetGDISurface,
3117 IDirectDrawImpl_GetMonitorFrequency,
3118 IDirectDrawImpl_GetScanLine,
3119 IDirectDrawImpl_GetVerticalBlankStatus,
3120 IDirectDrawImpl_Initialize,
3121 IDirectDrawImpl_RestoreDisplayMode,
3122 IDirectDrawImpl_SetCooperativeLevel,
3123 IDirectDrawImpl_SetDisplayMode,
3124 IDirectDrawImpl_WaitForVerticalBlank,
3125 /*** IDirectDraw2 ***/
3126 IDirectDrawImpl_GetAvailableVidMem,
3127 /*** IDirectDraw3 ***/
3128 IDirectDrawImpl_GetSurfaceFromDC,
3129 /*** IDirectDraw4 ***/
3130 IDirectDrawImpl_RestoreAllSurfaces,
3131 IDirectDrawImpl_TestCooperativeLevel,
3132 IDirectDrawImpl_GetDeviceIdentifier,
3133 /*** IDirectDraw7 ***/
3134 IDirectDrawImpl_StartModeTest,
3135 IDirectDrawImpl_EvaluateMode
3138 /*****************************************************************************
3139 * IDirectDrawImpl_FindDecl
3141 * Finds the WineD3D vertex declaration for a specific fvf, and creates one
3142 * if none was found.
3144 * This function is in ddraw.c and the DDraw object space because D3D7
3145 * vertex buffers are created using the IDirect3D interface to the ddraw
3146 * object, so they can be valid across D3D devices(theoretically. The ddraw
3147 * object also owns the wined3d device
3151 * fvf: Fvf to find the decl for
3154 * NULL in case of an error, the IWineD3DVertexDeclaration interface for the
3157 *****************************************************************************/
3158 IWineD3DVertexDeclaration *
3159 IDirectDrawImpl_FindDecl(IDirectDrawImpl *This,
3163 IWineD3DVertexDeclaration* pDecl = NULL;
3164 int p, low, high; /* deliberately signed */
3165 struct FvfToDecl *convertedDecls = This->decls;
3167 TRACE("Searching for declaration for fvf %08x... ", fvf);
3170 high = This->numConvertedDecls - 1;
3171 while(low <= high) {
3172 p = (low + high) >> 1;
3174 if(convertedDecls[p].fvf == fvf) {
3175 TRACE("found %p\n", convertedDecls[p].decl);
3176 return convertedDecls[p].decl;
3177 } else if(convertedDecls[p].fvf < fvf) {
3183 TRACE("not found. Creating and inserting at position %d.\n", low);
3185 hr = IWineD3DDevice_CreateVertexDeclarationFromFVF(This->wineD3DDevice, &pDecl,
3186 (IUnknown *)This, &ddraw_null_wined3d_parent_ops, fvf);
3187 if (hr != S_OK) return NULL;
3189 if(This->declArraySize == This->numConvertedDecls) {
3190 int grow = max(This->declArraySize / 2, 8);
3191 convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls,
3192 sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow));
3193 if(!convertedDecls) {
3194 /* This will destroy it */
3195 IWineD3DVertexDeclaration_Release(pDecl);
3198 This->decls = convertedDecls;
3199 This->declArraySize += grow;
3202 memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(convertedDecls[0]) * (This->numConvertedDecls - low));
3203 convertedDecls[low].decl = pDecl;
3204 convertedDecls[low].fvf = fvf;
3205 This->numConvertedDecls++;
3207 TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls);
3211 /* IWineD3DDeviceParent IUnknown methods */
3213 static inline struct IDirectDrawImpl *ddraw_from_device_parent(IWineD3DDeviceParent *iface)
3215 return (struct IDirectDrawImpl *)((char*)iface - FIELD_OFFSET(struct IDirectDrawImpl, device_parent_vtbl));
3218 static HRESULT STDMETHODCALLTYPE device_parent_QueryInterface(IWineD3DDeviceParent *iface, REFIID riid, void **object)
3220 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
3221 return IDirectDrawImpl_QueryInterface((IDirectDraw7 *)This, riid, object);
3224 static ULONG STDMETHODCALLTYPE device_parent_AddRef(IWineD3DDeviceParent *iface)
3226 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
3227 return IDirectDrawImpl_AddRef((IDirectDraw7 *)This);
3230 static ULONG STDMETHODCALLTYPE device_parent_Release(IWineD3DDeviceParent *iface)
3232 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
3233 return IDirectDrawImpl_Release((IDirectDraw7 *)This);
3236 /* IWineD3DDeviceParent methods */
3238 static void STDMETHODCALLTYPE device_parent_WineD3DDeviceCreated(IWineD3DDeviceParent *iface, IWineD3DDevice *device)
3240 TRACE("iface %p, device %p\n", iface, device);
3243 static HRESULT STDMETHODCALLTYPE device_parent_CreateSurface(IWineD3DDeviceParent *iface,
3244 IUnknown *superior, UINT width, UINT height, WINED3DFORMAT format, DWORD usage,
3245 WINED3DPOOL pool, UINT level, WINED3DCUBEMAP_FACES face, IWineD3DSurface **surface)
3247 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
3248 IDirectDrawSurfaceImpl *surf = NULL;
3250 DDSCAPS2 searchcaps = This->tex_root->surface_desc.ddsCaps;
3252 TRACE("iface %p, superior %p, width %u, height %u, format %#x, usage %#x,\n"
3253 "\tpool %#x, level %u, face %u, surface %p\n",
3254 iface, superior, width, height, format, usage, pool, level, face, surface);
3256 searchcaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
3259 case WINED3DCUBEMAP_FACE_POSITIVE_X:
3260 TRACE("Asked for positive x\n");
3261 if (searchcaps.dwCaps2 & DDSCAPS2_CUBEMAP)
3263 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
3265 surf = This->tex_root; break;
3266 case WINED3DCUBEMAP_FACE_NEGATIVE_X:
3267 TRACE("Asked for negative x\n");
3268 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEX; break;
3269 case WINED3DCUBEMAP_FACE_POSITIVE_Y:
3270 TRACE("Asked for positive y\n");
3271 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEY; break;
3272 case WINED3DCUBEMAP_FACE_NEGATIVE_Y:
3273 TRACE("Asked for negative y\n");
3274 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEY; break;
3275 case WINED3DCUBEMAP_FACE_POSITIVE_Z:
3276 TRACE("Asked for positive z\n");
3277 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEZ; break;
3278 case WINED3DCUBEMAP_FACE_NEGATIVE_Z:
3279 TRACE("Asked for negative z\n");
3280 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEZ; break;
3281 default: {ERR("Unexpected cube face\n");} /* Stupid compiler */
3286 IDirectDrawSurface7 *attached;
3287 IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)This->tex_root, &searchcaps, &attached);
3288 surf = (IDirectDrawSurfaceImpl *)attached;
3289 IDirectDrawSurface7_Release(attached);
3291 if (!surf) ERR("root search surface not found\n");
3293 /* Find the wanted mipmap. There are enough mipmaps in the chain */
3296 IDirectDrawSurface7 *attached;
3297 IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)surf, &searchcaps, &attached);
3298 if(!attached) ERR("Surface not found\n");
3299 surf = (IDirectDrawSurfaceImpl *)attached;
3300 IDirectDrawSurface7_Release(attached);
3304 /* Return the surface */
3305 *surface = surf->WineD3DSurface;
3306 IWineD3DSurface_AddRef(*surface);
3308 TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *surface, surf);
3313 static HRESULT WINAPI findRenderTarget(IDirectDrawSurface7 *surface, DDSURFACEDESC2 *surface_desc, void *ctx)
3315 IDirectDrawSurfaceImpl *s = (IDirectDrawSurfaceImpl *)surface;
3316 IDirectDrawSurfaceImpl **target = ctx;
3318 if (!s->isRenderTarget)
3321 IDirectDrawSurface7_Release(surface);
3322 return DDENUMRET_CANCEL;
3325 /* Recurse into the surface tree */
3326 IDirectDrawSurface7_EnumAttachedSurfaces(surface, ctx, findRenderTarget);
3328 IDirectDrawSurface7_Release(surface);
3329 if (*target) return DDENUMRET_CANCEL;
3331 return DDENUMRET_OK;
3334 static HRESULT STDMETHODCALLTYPE device_parent_CreateRenderTarget(IWineD3DDeviceParent *iface,
3335 IUnknown *superior, UINT width, UINT height, WINED3DFORMAT format, WINED3DMULTISAMPLE_TYPE multisample_type,
3336 DWORD multisample_quality, BOOL lockable, IWineD3DSurface **surface)
3338 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
3339 IDirectDrawSurfaceImpl *d3d_surface = This->d3d_target;
3340 IDirectDrawSurfaceImpl *target = NULL;
3342 TRACE("iface %p, superior %p, width %u, height %u, format %#x, multisample_type %#x,\n"
3343 "\tmultisample_quality %u, lockable %u, surface %p\n",
3344 iface, superior, width, height, format, multisample_type, multisample_quality, lockable, surface);
3346 if (d3d_surface->isRenderTarget)
3348 IDirectDrawSurface7_EnumAttachedSurfaces((IDirectDrawSurface7 *)d3d_surface, &target, findRenderTarget);
3352 target = d3d_surface;
3357 target = This->d3d_target;
3358 ERR(" (%p) : No DirectDrawSurface found to create the back buffer. Using the front buffer as back buffer. Uncertain consequences\n", This);
3361 /* TODO: Return failure if the dimensions do not match, but this shouldn't happen */
3363 *surface = target->WineD3DSurface;
3364 IWineD3DSurface_AddRef(*surface);
3365 target->isRenderTarget = TRUE;
3367 TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *surface, d3d_surface);
3372 static HRESULT STDMETHODCALLTYPE device_parent_CreateDepthStencilSurface(IWineD3DDeviceParent *iface,
3373 IUnknown *superior, UINT width, UINT height, WINED3DFORMAT format, WINED3DMULTISAMPLE_TYPE multisample_type,
3374 DWORD multisample_quality, BOOL discard, IWineD3DSurface **surface)
3376 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
3377 IDirectDrawSurfaceImpl *ddraw_surface;
3378 DDSURFACEDESC2 ddsd;
3381 TRACE("iface %p, superior %p, width %u, height %u, format %#x, multisample_type %#x,\n"
3382 "\tmultisample_quality %u, discard %u, surface %p\n",
3383 iface, superior, width, height, format, multisample_type, multisample_quality, discard, surface);
3387 /* Create a DirectDraw surface */
3388 memset(&ddsd, 0, sizeof(ddsd));
3389 ddsd.dwSize = sizeof(ddsd);
3390 ddsd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
3391 ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
3392 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
3393 ddsd.dwHeight = height;
3394 ddsd.dwWidth = width;
3397 PixelFormat_WineD3DtoDD(&ddsd.u4.ddpfPixelFormat, format);
3401 ddsd.dwFlags ^= DDSD_PIXELFORMAT;
3404 This->depthstencil = TRUE;
3405 hr = IDirectDraw7_CreateSurface((IDirectDraw7 *)This, &ddsd, (IDirectDrawSurface7 **)&ddraw_surface, NULL);
3406 This->depthstencil = FALSE;
3409 ERR(" (%p) Creating a DepthStencil Surface failed, result = %x\n", This, hr);
3413 *surface = ddraw_surface->WineD3DSurface;
3414 IWineD3DSurface_AddRef(*surface);
3415 IDirectDrawSurface7_Release((IDirectDrawSurface7 *)ddraw_surface);
3420 static HRESULT STDMETHODCALLTYPE device_parent_CreateVolume(IWineD3DDeviceParent *iface,
3421 IUnknown *superior, UINT width, UINT height, UINT depth, WINED3DFORMAT format,
3422 WINED3DPOOL pool, DWORD usage, IWineD3DVolume **volume)
3424 TRACE("iface %p, superior %p, width %u, height %u, depth %u, format %#x, pool %#x, usage %#x, volume %p\n",
3425 iface, superior, width, height, depth, format, pool, usage, volume);
3427 ERR("Not implemented!\n");
3432 static HRESULT STDMETHODCALLTYPE device_parent_CreateSwapChain(IWineD3DDeviceParent *iface,
3433 WINED3DPRESENT_PARAMETERS *present_parameters, IWineD3DSwapChain **swapchain)
3435 struct IDirectDrawImpl *This = ddraw_from_device_parent(iface);
3436 IDirectDrawSurfaceImpl *iterator;
3437 IParentImpl *object;
3440 TRACE("iface %p, present_parameters %p, swapchain %p\n", iface, present_parameters, swapchain);
3442 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IParentImpl));
3445 FIXME("Allocation of memory failed\n");
3447 return DDERR_OUTOFVIDEOMEMORY;
3450 object->lpVtbl = &IParent_Vtbl;
3453 hr = IWineD3DDevice_CreateSwapChain(This->wineD3DDevice, present_parameters,
3454 swapchain, (IUnknown *)object, This->ImplType);
3457 FIXME("(%p) CreateSwapChain failed, returning %#x\n", iface, hr);
3458 HeapFree(GetProcessHeap(), 0 , object);
3463 object->child = (IUnknown *)*swapchain;
3464 This->d3d_target->wineD3DSwapChain = *swapchain;
3465 iterator = This->d3d_target->complex_array[0];
3468 iterator->wineD3DSwapChain = *swapchain;
3469 iterator = iterator->complex_array[0];
3475 const IWineD3DDeviceParentVtbl ddraw_wined3d_device_parent_vtbl =
3477 /* IUnknown methods */
3478 device_parent_QueryInterface,
3479 device_parent_AddRef,
3480 device_parent_Release,
3481 /* IWineD3DDeviceParent methods */
3482 device_parent_WineD3DDeviceCreated,
3483 device_parent_CreateSurface,
3484 device_parent_CreateRenderTarget,
3485 device_parent_CreateDepthStencilSurface,
3486 device_parent_CreateVolume,
3487 device_parent_CreateSwapChain,