ddraw: Store wined3d state in d3d_device.
[wine.git] / dlls / ddraw / ddraw.c
blob21497cd7a8ba131f3d1e4cc1e3300c36afbd5204
1 /*
2 * Copyright 1997-2000 Marcus Meissner
3 * Copyright 1998-2000 Lionel Ulmer
4 * Copyright 2000-2001 TransGaming Technologies Inc.
5 * Copyright 2006 Stefan Dösinger
6 * Copyright 2008 Denver Gingerich
7 * Copyright 2007-2008, 2011, 2013 Stefan Dösinger for CodeWeavers
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "ddraw_private.h"
25 #include "ddrawi.h"
26 #include "d3dhal.h"
28 #include "wine/exception.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
32 static const struct ddraw *exclusive_ddraw;
33 static HWND exclusive_window;
35 /* Device identifier. Don't relay it to WineD3D */
36 static const DDDEVICEIDENTIFIER2 deviceidentifier =
38 "vga.dll", /* default 2D driver */
39 "DirectDraw HAL",
40 { { 0x00010001, 0x00010001 } },
41 0, 0, 0, 0,
42 /* a8373c10-7ac4-4deb-849a-009844d08b2d */
43 {0xa8373c10,0x7ac4,0x4deb, {0x84,0x9a,0x00,0x98,0x44,0xd0,0x8b,0x2d}},
47 static struct enum_device_entry
49 char interface_name[100];
50 char device_name[100];
51 const GUID *device_guid;
52 DWORD unsupported_caps;
53 } device_list7[] =
55 /* T&L HAL device */
57 "WINE Direct3D7 Hardware Transform and Lighting acceleration using WineD3D",
58 "Wine D3D7 T&L HAL",
59 &IID_IDirect3DTnLHalDevice,
63 /* HAL device */
65 "WINE Direct3D7 Hardware acceleration using WineD3D",
66 "Direct3D HAL",
67 &IID_IDirect3DHALDevice,
68 D3DDEVCAPS_HWTRANSFORMANDLIGHT,
71 /* RGB device */
73 "WINE Direct3D7 RGB Software Emulation using WineD3D",
74 "Wine D3D7 RGB",
75 &IID_IDirect3DRGBDevice,
76 D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX | D3DDEVCAPS_HWRASTERIZATION,
80 static void STDMETHODCALLTYPE ddraw_null_wined3d_object_destroyed(void *parent) {}
82 const struct wined3d_parent_ops ddraw_null_wined3d_parent_ops =
84 ddraw_null_wined3d_object_destroyed,
87 static void CDECL ddraw_swapchain_windowed_state_changed(struct wined3d_swapchain_state_parent *parent,
88 BOOL windowed)
90 TRACE("parent %p, windowed %d.\n", parent, windowed);
93 static const struct wined3d_swapchain_state_parent_ops ddraw_swapchain_state_parent_ops =
95 ddraw_swapchain_windowed_state_changed,
98 static inline struct ddraw *impl_from_IDirectDraw(IDirectDraw *iface)
100 return CONTAINING_RECORD(iface, struct ddraw, IDirectDraw_iface);
103 static inline struct ddraw *impl_from_IDirectDraw2(IDirectDraw2 *iface)
105 return CONTAINING_RECORD(iface, struct ddraw, IDirectDraw2_iface);
108 static inline struct ddraw *impl_from_IDirectDraw4(IDirectDraw4 *iface)
110 return CONTAINING_RECORD(iface, struct ddraw, IDirectDraw4_iface);
113 static inline struct ddraw *impl_from_IDirectDraw7(IDirectDraw7 *iface)
115 return CONTAINING_RECORD(iface, struct ddraw, IDirectDraw7_iface);
118 static inline struct ddraw *impl_from_IDirect3D(IDirect3D *iface)
120 return CONTAINING_RECORD(iface, struct ddraw, IDirect3D_iface);
123 static inline struct ddraw *impl_from_IDirect3D2(IDirect3D2 *iface)
125 return CONTAINING_RECORD(iface, struct ddraw, IDirect3D2_iface);
128 static inline struct ddraw *impl_from_IDirect3D3(IDirect3D3 *iface)
130 return CONTAINING_RECORD(iface, struct ddraw, IDirect3D3_iface);
133 static inline struct ddraw *impl_from_IDirect3D7(IDirect3D7 *iface)
135 return CONTAINING_RECORD(iface, struct ddraw, IDirect3D7_iface);
138 static HRESULT WINAPI ddraw7_QueryInterface(IDirectDraw7 *iface, REFIID riid, void **out)
140 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
142 TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
144 if (!riid)
146 *out = NULL;
147 return DDERR_INVALIDPARAMS;
150 /* The refcount unit test revealed that an IDirect3D7 interface can only
151 * be queried from a DirectDraw object that was created as an IDirectDraw7
152 * interface. The older interfaces can query any IDirect3D version except
153 * 7, because they are all initially created as IDirectDraw. This isn't
154 * really crucial behavior, and messy to implement with the common
155 * creation function, so it has been left out here. */
156 if (IsEqualGUID(&IID_IDirectDraw7, riid)
157 || IsEqualGUID(&IID_IUnknown, riid))
159 *out = &ddraw->IDirectDraw7_iface;
160 TRACE("Returning IDirectDraw7 interface %p.\n", *out);
162 else if (IsEqualGUID(&IID_IDirectDraw4, riid))
164 *out = &ddraw->IDirectDraw4_iface;
165 TRACE("Returning IDirectDraw4 interface %p.\n", *out);
167 else if (IsEqualGUID(&IID_IDirectDraw2, riid))
169 *out = &ddraw->IDirectDraw2_iface;
170 TRACE("Returning IDirectDraw2 interface %p.\n", *out);
172 else if (IsEqualGUID(&IID_IDirectDraw, riid))
174 *out = &ddraw->IDirectDraw_iface;
175 TRACE("Returning IDirectDraw interface %p.\n", *out);
177 else if (IsEqualGUID(&IID_IDirect3D7, riid))
179 ddraw->d3dversion = 7;
180 *out = &ddraw->IDirect3D7_iface;
181 TRACE("Returning Direct3D7 interface %p.\n", *out);
183 else if (IsEqualGUID(&IID_IDirect3D3, riid))
185 ddraw->d3dversion = 3;
186 *out = &ddraw->IDirect3D3_iface;
187 TRACE("Returning Direct3D3 interface %p.\n", *out);
189 else if (IsEqualGUID(&IID_IDirect3D2, riid))
191 ddraw->d3dversion = 2;
192 *out = &ddraw->IDirect3D2_iface;
193 TRACE("Returning Direct3D2 interface %p.\n", *out);
195 else if (IsEqualGUID(&IID_IDirect3D, riid))
197 ddraw->d3dversion = 1;
198 *out = &ddraw->IDirect3D_iface;
199 TRACE("Returning Direct3D interface %p.\n", *out);
201 /* Unknown interface */
202 else
204 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
205 *out = NULL;
206 return E_NOINTERFACE;
209 IUnknown_AddRef((IUnknown *)*out);
210 return S_OK;
213 static HRESULT WINAPI ddraw4_QueryInterface(IDirectDraw4 *iface, REFIID riid, void **object)
215 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
217 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
219 return ddraw7_QueryInterface(&ddraw->IDirectDraw7_iface, riid, object);
222 static HRESULT WINAPI ddraw2_QueryInterface(IDirectDraw2 *iface, REFIID riid, void **object)
224 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
226 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
228 return ddraw7_QueryInterface(&ddraw->IDirectDraw7_iface, riid, object);
231 static HRESULT WINAPI ddraw1_QueryInterface(IDirectDraw *iface, REFIID riid, void **object)
233 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
235 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
237 return ddraw7_QueryInterface(&ddraw->IDirectDraw7_iface, riid, object);
240 static HRESULT WINAPI d3d7_QueryInterface(IDirect3D7 *iface, REFIID riid, void **object)
242 struct ddraw *ddraw = impl_from_IDirect3D7(iface);
244 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
246 return ddraw7_QueryInterface(&ddraw->IDirectDraw7_iface, riid, object);
249 static HRESULT WINAPI d3d3_QueryInterface(IDirect3D3 *iface, REFIID riid, void **object)
251 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
253 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
255 return ddraw7_QueryInterface(&ddraw->IDirectDraw7_iface, riid, object);
258 static HRESULT WINAPI d3d2_QueryInterface(IDirect3D2 *iface, REFIID riid, void **object)
260 struct ddraw *ddraw = impl_from_IDirect3D2(iface);
262 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
264 return ddraw7_QueryInterface(&ddraw->IDirectDraw7_iface, riid, object);
267 static HRESULT WINAPI d3d1_QueryInterface(IDirect3D *iface, REFIID riid, void **object)
269 struct ddraw *ddraw = impl_from_IDirect3D(iface);
271 TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
273 return ddraw7_QueryInterface(&ddraw->IDirectDraw7_iface, riid, object);
276 /*****************************************************************************
277 * IDirectDraw7::AddRef
279 * Increases the interfaces refcount, basically
281 * DDraw refcounting is a bit tricky. The different DirectDraw interface
282 * versions have individual refcounts, but the IDirect3D interfaces do not.
283 * All interfaces are from one object, that means calling QueryInterface on an
284 * IDirectDraw7 interface for an IDirectDraw4 interface does not create a new
285 * ddraw object.
287 * That means all AddRef and Release implementations of IDirectDrawX work
288 * with their own counter, and IDirect3DX::AddRef thunk to IDirectDraw (1),
289 * except of IDirect3D7 which thunks to IDirectDraw7
291 * Returns: The new refcount
293 *****************************************************************************/
294 static ULONG WINAPI ddraw7_AddRef(IDirectDraw7 *iface)
296 struct ddraw *This = impl_from_IDirectDraw7(iface);
297 ULONG ref = InterlockedIncrement(&This->ref7);
299 TRACE("%p increasing refcount to %lu.\n", This, ref);
301 if(ref == 1) InterlockedIncrement(&This->numIfaces);
303 return ref;
306 static ULONG WINAPI ddraw4_AddRef(IDirectDraw4 *iface)
308 struct ddraw *This = impl_from_IDirectDraw4(iface);
309 ULONG ref = InterlockedIncrement(&This->ref4);
311 TRACE("%p increasing refcount to %lu.\n", This, ref);
313 if (ref == 1) InterlockedIncrement(&This->numIfaces);
315 return ref;
318 static ULONG WINAPI ddraw2_AddRef(IDirectDraw2 *iface)
320 struct ddraw *This = impl_from_IDirectDraw2(iface);
321 ULONG ref = InterlockedIncrement(&This->ref2);
323 TRACE("%p increasing refcount to %lu.\n", This, ref);
325 if (ref == 1) InterlockedIncrement(&This->numIfaces);
327 return ref;
330 static ULONG WINAPI ddraw1_AddRef(IDirectDraw *iface)
332 struct ddraw *This = impl_from_IDirectDraw(iface);
333 ULONG ref = InterlockedIncrement(&This->ref1);
335 TRACE("%p increasing refcount to %lu.\n", This, ref);
337 if (ref == 1) InterlockedIncrement(&This->numIfaces);
339 return ref;
342 static ULONG WINAPI d3d7_AddRef(IDirect3D7 *iface)
344 struct ddraw *This = impl_from_IDirect3D7(iface);
346 TRACE("iface %p.\n", iface);
348 return ddraw7_AddRef(&This->IDirectDraw7_iface);
351 static ULONG WINAPI d3d3_AddRef(IDirect3D3 *iface)
353 struct ddraw *This = impl_from_IDirect3D3(iface);
355 TRACE("iface %p.\n", iface);
357 return ddraw1_AddRef(&This->IDirectDraw_iface);
360 static ULONG WINAPI d3d2_AddRef(IDirect3D2 *iface)
362 struct ddraw *This = impl_from_IDirect3D2(iface);
364 TRACE("iface %p.\n", iface);
366 return ddraw1_AddRef(&This->IDirectDraw_iface);
369 static ULONG WINAPI d3d1_AddRef(IDirect3D *iface)
371 struct ddraw *This = impl_from_IDirect3D(iface);
373 TRACE("iface %p.\n", iface);
375 return ddraw1_AddRef(&This->IDirectDraw_iface);
378 static void ddraw_destroy_swapchain(struct ddraw *ddraw)
380 unsigned int i;
382 TRACE("Destroying the swapchain.\n");
384 wined3d_swapchain_decref(ddraw->wined3d_swapchain);
386 for (i = 0; i < ddraw->numConvertedDecls; ++i)
388 wined3d_vertex_declaration_decref(ddraw->decls[i].decl);
390 free(ddraw->decls);
391 ddraw->numConvertedDecls = 0;
393 wined3d_swapchain_decref(ddraw->wined3d_swapchain);
394 ddraw->wined3d_swapchain = NULL;
396 /* Free the d3d window if one was created. */
397 if (ddraw->d3d_window && ddraw->d3d_window != ddraw->dest_window)
399 TRACE("Destroying the hidden render window %p.\n", ddraw->d3d_window);
400 DestroyWindow(ddraw->d3d_window);
401 ddraw->d3d_window = 0;
404 ddraw->flags &= ~DDRAW_D3D_INITIALIZED;
406 ddraw_set_swapchain_window(ddraw, NULL);
408 TRACE("Swapchain destroyed.\n");
411 /*****************************************************************************
412 * ddraw_destroy
414 * Destroys a ddraw object if all refcounts are 0. This is to share code
415 * between the IDirectDrawX::Release functions
417 * Params:
418 * This: DirectDraw object to destroy
420 *****************************************************************************/
421 static void ddraw_destroy(struct ddraw *This)
423 IDirectDraw7_SetCooperativeLevel(&This->IDirectDraw7_iface, NULL, DDSCL_NORMAL);
424 IDirectDraw7_RestoreDisplayMode(&This->IDirectDraw7_iface);
426 /* Destroy the device window if we created one */
427 if(This->devicewindow != 0)
429 TRACE(" (%p) Destroying the device window %p\n", This, This->devicewindow);
430 DestroyWindow(This->devicewindow);
431 This->devicewindow = 0;
434 wined3d_mutex_lock();
435 list_remove(&This->ddraw_list_entry);
436 wined3d_mutex_unlock();
438 if (This->wined3d_swapchain)
439 ddraw_destroy_swapchain(This);
440 wined3d_device_decref(This->wined3d_device);
441 wined3d_decref(This->wined3d);
443 if (This->d3ddevice)
444 This->d3ddevice->ddraw = NULL;
446 /* Now free the object */
447 free(This);
450 /*****************************************************************************
451 * IDirectDraw7::Release
453 * Decreases the refcount. If the refcount falls to 0, the object is destroyed
455 * Returns: The new refcount
456 *****************************************************************************/
457 static ULONG WINAPI ddraw7_Release(IDirectDraw7 *iface)
459 struct ddraw *This = impl_from_IDirectDraw7(iface);
460 ULONG ref = InterlockedDecrement(&This->ref7);
462 TRACE("%p decreasing refcount to %lu.\n", This, ref);
464 if (!ref && !InterlockedDecrement(&This->numIfaces))
465 ddraw_destroy(This);
467 return ref;
470 static ULONG WINAPI ddraw4_Release(IDirectDraw4 *iface)
472 struct ddraw *This = impl_from_IDirectDraw4(iface);
473 ULONG ref = InterlockedDecrement(&This->ref4);
475 TRACE("%p decreasing refcount to %lu.\n", This, ref);
477 if (!ref && !InterlockedDecrement(&This->numIfaces))
478 ddraw_destroy(This);
480 return ref;
483 static ULONG WINAPI ddraw2_Release(IDirectDraw2 *iface)
485 struct ddraw *This = impl_from_IDirectDraw2(iface);
486 ULONG ref = InterlockedDecrement(&This->ref2);
488 TRACE("%p decreasing refcount to %lu.\n", This, ref);
490 if (!ref && !InterlockedDecrement(&This->numIfaces))
491 ddraw_destroy(This);
493 return ref;
496 static ULONG WINAPI ddraw1_Release(IDirectDraw *iface)
498 struct ddraw *This = impl_from_IDirectDraw(iface);
499 ULONG ref = InterlockedDecrement(&This->ref1);
501 TRACE("%p decreasing refcount to %lu.\n", This, ref);
503 if (!ref && !InterlockedDecrement(&This->numIfaces))
504 ddraw_destroy(This);
506 return ref;
509 static ULONG WINAPI d3d7_Release(IDirect3D7 *iface)
511 struct ddraw *This = impl_from_IDirect3D7(iface);
513 TRACE("iface %p.\n", iface);
515 return ddraw7_Release(&This->IDirectDraw7_iface);
518 static ULONG WINAPI d3d3_Release(IDirect3D3 *iface)
520 struct ddraw *This = impl_from_IDirect3D3(iface);
522 TRACE("iface %p.\n", iface);
524 return ddraw1_Release(&This->IDirectDraw_iface);
527 static ULONG WINAPI d3d2_Release(IDirect3D2 *iface)
529 struct ddraw *This = impl_from_IDirect3D2(iface);
531 TRACE("iface %p.\n", iface);
533 return ddraw1_Release(&This->IDirectDraw_iface);
536 static ULONG WINAPI d3d1_Release(IDirect3D *iface)
538 struct ddraw *This = impl_from_IDirect3D(iface);
540 TRACE("iface %p.\n", iface);
542 return ddraw1_Release(&This->IDirectDraw_iface);
545 /*****************************************************************************
546 * IDirectDraw methods
547 *****************************************************************************/
549 static HRESULT ddraw_set_focus_window(struct ddraw *ddraw, HWND window)
551 /* FIXME: This looks wrong, exclusive mode should imply a destination
552 * window. */
553 if ((ddraw->cooperative_level & DDSCL_EXCLUSIVE) && ddraw->dest_window)
555 TRACE("Setting DDSCL_SETFOCUSWINDOW with an already set window, returning DDERR_HWNDALREADYSET.\n");
556 return DDERR_HWNDALREADYSET;
559 ddraw->focuswindow = window;
561 return DD_OK;
564 static HRESULT ddraw_attach_d3d_device(struct ddraw *ddraw, HWND window,
565 DWORD cooplevel, struct wined3d_swapchain **wined3d_swapchain)
567 struct wined3d_swapchain_desc swapchain_desc;
568 struct wined3d_display_mode mode;
569 HRESULT hr;
571 TRACE("ddraw %p.\n", ddraw);
573 if (FAILED(hr = wined3d_output_get_display_mode(ddraw->wined3d_output, &mode, NULL)))
575 ERR("Failed to get display mode.\n");
576 return hr;
579 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
580 swapchain_desc.output = ddraw->wined3d_output;
581 swapchain_desc.backbuffer_width = mode.width;
582 swapchain_desc.backbuffer_height = mode.height;
583 swapchain_desc.backbuffer_format = mode.format_id;
584 swapchain_desc.backbuffer_bind_flags = 0;
585 swapchain_desc.backbuffer_count = 1;
586 swapchain_desc.swap_effect = WINED3D_SWAP_EFFECT_DISCARD;
587 swapchain_desc.device_window = window;
588 swapchain_desc.windowed = !(cooplevel & DDSCL_FULLSCREEN);
589 swapchain_desc.flags = DDRAW_WINED3D_SWAPCHAIN_FLAGS;
591 if ((cooplevel & DDSCL_NOWINDOWCHANGES) || window != GetForegroundWindow())
592 swapchain_desc.flags |= WINED3D_SWAPCHAIN_NO_WINDOW_CHANGES;
594 if (ddraw->flags & DDRAW_NO3D)
595 return wined3d_swapchain_create(ddraw->wined3d_device, &swapchain_desc,
596 &ddraw->state_parent, NULL, &ddraw_null_wined3d_parent_ops, wined3d_swapchain);
598 if (!window || window == GetDesktopWindow())
600 window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "Hidden D3D Window",
601 WS_DISABLED, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
602 NULL, NULL, NULL, NULL);
603 if (!window)
605 ERR("Failed to create window, last error %#lx.\n", GetLastError());
606 return E_FAIL;
609 ShowWindow(window, SW_HIDE); /* Just to be sure */
610 WARN("No window for the Direct3DDevice, created hidden window %p.\n", window);
612 swapchain_desc.device_window = window;
614 else
616 TRACE("Using existing window %p for Direct3D rendering.\n", window);
618 ddraw->d3d_window = window;
620 /* Set this NOW, otherwise creating the depth stencil surface will cause a
621 * recursive loop until ram or emulated video memory is full. */
622 ddraw->flags |= DDRAW_D3D_INITIALIZED;
623 if (FAILED(hr = wined3d_swapchain_create(ddraw->wined3d_device, &swapchain_desc,
624 &ddraw->state_parent, NULL, &ddraw_null_wined3d_parent_ops, wined3d_swapchain)))
626 ddraw->flags &= ~DDRAW_D3D_INITIALIZED;
627 DestroyWindow(window);
628 ddraw->d3d_window = NULL;
629 return hr;
632 ddraw->declArraySize = 2;
633 if (!(ddraw->decls = calloc(ddraw->declArraySize, sizeof(*ddraw->decls))))
635 ERR("Error allocating an array for the converted vertex decls.\n");
636 ddraw->declArraySize = 0;
637 wined3d_swapchain_decref(*wined3d_swapchain);
638 DestroyWindow(window);
639 ddraw->d3d_window = NULL;
640 return E_OUTOFMEMORY;
643 TRACE("Successfully initialized 3D.\n");
645 return DD_OK;
648 static HRESULT ddraw_create_swapchain(struct ddraw *ddraw, HWND window, DWORD cooplevel)
650 HRESULT hr;
652 if (ddraw->wined3d_swapchain)
654 ERR("Swapchain already created.\n");
655 return E_FAIL;
658 if (FAILED(hr = ddraw_attach_d3d_device(ddraw, window, cooplevel, &ddraw->wined3d_swapchain)))
660 ERR("Failed to create swapchain, hr %#lx.\n", hr);
661 return hr;
663 wined3d_swapchain_incref(ddraw->wined3d_swapchain);
665 ddraw_set_swapchain_window(ddraw, window);
667 if (ddraw->primary && ddraw->primary->palette)
668 wined3d_swapchain_set_palette(ddraw->wined3d_swapchain, ddraw->primary->palette->wined3d_palette);
670 return DD_OK;
673 /*****************************************************************************
674 * IDirectDraw7::RestoreDisplayMode
676 * Restores the display mode to what it was at creation time. Basically.
678 * Returns
679 * DD_OK on success
680 * DDERR_NOEXCLUSIVE mode if the device isn't in fullscreen mode
682 *****************************************************************************/
683 static HRESULT WINAPI ddraw7_RestoreDisplayMode(IDirectDraw7 *iface)
685 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
686 struct wined3d_display_mode mode;
687 RECT clip_rect;
688 HRESULT hr;
690 TRACE("iface %p.\n", iface);
692 wined3d_mutex_lock();
694 if (!(ddraw->flags & DDRAW_RESTORE_MODE))
696 wined3d_mutex_unlock();
697 return DD_OK;
700 if (exclusive_ddraw && exclusive_ddraw != ddraw)
702 wined3d_mutex_unlock();
703 return DDERR_NOEXCLUSIVEMODE;
706 if (SUCCEEDED(hr = wined3d_restore_display_modes(ddraw->wined3d)))
708 ddraw->flags &= ~DDRAW_RESTORE_MODE;
709 if (ddraw->cooperative_level & DDSCL_EXCLUSIVE &&
710 SUCCEEDED(hr = wined3d_output_get_display_mode(ddraw->wined3d_output, &mode, NULL)))
712 SetRect(&clip_rect, 0, 0, mode.width, mode.height);
713 ClipCursor(&clip_rect);
717 InterlockedCompareExchange(&ddraw->device_state, DDRAW_DEVICE_STATE_NOT_RESTORED, DDRAW_DEVICE_STATE_OK);
719 wined3d_mutex_unlock();
721 return hr;
724 static HRESULT WINAPI ddraw4_RestoreDisplayMode(IDirectDraw4 *iface)
726 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
728 TRACE("iface %p.\n", iface);
730 return ddraw7_RestoreDisplayMode(&ddraw->IDirectDraw7_iface);
733 static HRESULT WINAPI ddraw2_RestoreDisplayMode(IDirectDraw2 *iface)
735 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
737 TRACE("iface %p.\n", iface);
739 return ddraw7_RestoreDisplayMode(&ddraw->IDirectDraw7_iface);
742 static HRESULT WINAPI ddraw1_RestoreDisplayMode(IDirectDraw *iface)
744 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
746 TRACE("iface %p.\n", iface);
748 return ddraw7_RestoreDisplayMode(&ddraw->IDirectDraw7_iface);
751 /*****************************************************************************
752 * IDirectDraw7::SetCooperativeLevel
754 * Sets the cooperative level for the DirectDraw object, and the window
755 * assigned to it. The cooperative level determines the general behavior
756 * of the DirectDraw application
758 * Warning: This is quite tricky, as it's not really documented which
759 * cooperative levels can be combined with each other. If a game fails
760 * after this function, try to check the cooperative levels passed on
761 * Windows, and if it returns something different.
763 * If you think that this function caused the failure because it writes a
764 * fixme, be sure to run again with a +ddraw trace.
766 * What is known about cooperative levels (See the ddraw modes test):
767 * DDSCL_EXCLUSIVE requires DDSCL_FULLSCREEN.
768 * DDSCL_NORMAL is not compatible with DDSCL_EXCLUSIVE.
769 * Unlike what msdn claims, DDSCL_NORMAL | DDSCL_FULLSCREEN is allowed.
770 * DDSCL_SETFOCUSWINDOW can be passed only in DDSCL_NORMAL mode, but after that
771 * DDSCL_EXCLUSIVE can be activated.
772 * DDSCL_SETFOCUSWINDOW may only be used with DDSCL_NOWINDOWCHANGES or
773 * DDSCL_CREATEDEVICEWINDOW.
775 * Handled flags: DDSCL_NORMAL, DDSCL_FULLSCREEN, DDSCL_EXCLUSIVE,
776 * DDSCL_CREATEDEVICEWINDOW, DDSCL_SETDEVICEWINDOW
777 * DDSCL_SETFOCUSWINDOW (partially),
778 * DDSCL_MULTITHREADED (work in progress)
779 * DDSCL_FPUPRESERVE (see device.c)
781 * Unsure about this: DDSCL_FPUSETUP
783 * These don't seem very important for wine:
784 * DDSCL_ALLOWREBOOT, DDSCL_ALLOWMODEX
786 * Returns:
787 * DD_OK if the cooperative level was set successfully
788 * DDERR_INVALIDPARAMS if the passed cooperative level combination is invalid
789 * DDERR_HWNDALREADYSET if DDSCL_SETFOCUSWINDOW is passed in exclusive mode
790 * (Probably others too, have to investigate)
792 *****************************************************************************/
793 static HRESULT ddraw_set_cooperative_level(struct ddraw *ddraw, HWND window,
794 DWORD cooplevel, BOOL restore_mode_on_normal)
796 struct wined3d_rendertarget_view *rtv = NULL, *dsv = NULL;
797 struct wined3d_stateblock *stateblock;
798 BOOL restore_state = FALSE;
799 struct d3d_device *device;
800 RECT clip_rect;
801 HRESULT hr;
803 TRACE("ddraw %p, window %p, flags %#lx, restore_mode_on_normal %x.\n", ddraw, window, cooplevel,
804 restore_mode_on_normal);
805 DDRAW_dump_cooperativelevel(cooplevel);
807 wined3d_mutex_lock();
809 if (ddraw->flags & DDRAW_SCL_RECURSIVE)
811 WARN("Recursive call, returning DD_OK.\n");
812 hr = DD_OK;
813 goto done;
815 ddraw->flags |= DDRAW_SCL_RECURSIVE;
817 /* Tests suggest that we need one of them: */
818 if(!(cooplevel & (DDSCL_SETFOCUSWINDOW |
819 DDSCL_NORMAL |
820 DDSCL_EXCLUSIVE )))
822 TRACE("Incorrect cooplevel flags, returning DDERR_INVALIDPARAMS\n");
823 hr = DDERR_INVALIDPARAMS;
824 goto done;
827 if ((cooplevel & DDSCL_CREATEDEVICEWINDOW) && !(cooplevel & DDSCL_EXCLUSIVE))
829 WARN("DDSCL_CREATEDEVICEWINDOW requires DDSCL_EXCLUSIVE.\n");
830 hr = DDERR_INVALIDPARAMS;
831 goto done;
834 /* Handle those levels first which set various hwnds */
835 if ((cooplevel & DDSCL_SETFOCUSWINDOW) && !(cooplevel & DDSCL_CREATEDEVICEWINDOW))
837 /* This isn't compatible with a lot of flags */
838 if (cooplevel & (DDSCL_MULTITHREADED
839 | DDSCL_FPUSETUP
840 | DDSCL_FPUPRESERVE
841 | DDSCL_ALLOWREBOOT
842 | DDSCL_ALLOWMODEX
843 | DDSCL_SETDEVICEWINDOW
844 | DDSCL_NORMAL
845 | DDSCL_EXCLUSIVE
846 | DDSCL_FULLSCREEN))
848 WARN("Called with incompatible flags, returning DDERR_INVALIDPARAMS.\n");
849 hr = DDERR_INVALIDPARAMS;
850 goto done;
853 hr = ddraw_set_focus_window(ddraw, window);
854 goto done;
857 if (cooplevel & DDSCL_EXCLUSIVE)
859 if (!(cooplevel & DDSCL_FULLSCREEN) || !(window || (cooplevel & DDSCL_CREATEDEVICEWINDOW)))
861 WARN("DDSCL_EXCLUSIVE requires DDSCL_FULLSCREEN and a window.\n");
862 hr = DDERR_INVALIDPARAMS;
863 goto done;
866 if (cooplevel & DDSCL_CREATEDEVICEWINDOW)
868 HWND device_window;
870 if (!ddraw->focuswindow && !(cooplevel & DDSCL_SETFOCUSWINDOW))
872 WARN("No focus window set.\n");
873 hr = DDERR_NOFOCUSWINDOW;
874 goto done;
877 device_window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "DirectDrawDeviceWnd",
878 WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
879 NULL, NULL, NULL, NULL);
880 if (!device_window)
882 ERR("Failed to create window, last error %#lx.\n", GetLastError());
883 hr = E_FAIL;
884 goto done;
887 ShowWindow(device_window, SW_SHOW);
888 TRACE("Created a device window %p.\n", device_window);
890 /* Native apparently leaks the created device window if setting the
891 * focus window below fails. */
892 ddraw->cooperative_level |= DDSCL_CREATEDEVICEWINDOW;
893 ddraw->devicewindow = device_window;
895 if (cooplevel & DDSCL_SETFOCUSWINDOW)
897 if (!window)
899 hr = DDERR_NOHWND;
900 goto done;
903 if (FAILED(hr = ddraw_set_focus_window(ddraw, window)))
904 goto done;
907 window = device_window;
910 else
912 if (ddraw->cooperative_level & DDSCL_CREATEDEVICEWINDOW)
913 DestroyWindow(ddraw->devicewindow);
914 ddraw->devicewindow = NULL;
915 ddraw->focuswindow = NULL;
918 if ((cooplevel & DDSCL_EXCLUSIVE) && exclusive_window != window)
920 ddraw->device_state = DDRAW_DEVICE_STATE_NOT_RESTORED;
921 exclusive_window = window;
924 if (cooplevel & DDSCL_MULTITHREADED && !(ddraw->cooperative_level & DDSCL_MULTITHREADED))
925 wined3d_device_set_multithreaded(ddraw->wined3d_device);
927 device = ddraw->d3ddevice;
928 if (ddraw->wined3d_swapchain)
930 if (!(ddraw->flags & DDRAW_NO3D) && device)
932 restore_state = TRUE;
934 if (FAILED(hr = wined3d_stateblock_create(ddraw->wined3d_device,
935 device->state, WINED3D_SBT_ALL, &stateblock)))
937 ERR("Failed to create stateblock, hr %#lx.\n", hr);
938 goto done;
941 rtv = wined3d_device_context_get_rendertarget_view(ddraw->immediate_context, 0);
942 /* Rendering to the wined3d frontbuffer. */
943 if (rtv && !wined3d_rendertarget_view_get_sub_resource_parent(rtv))
944 rtv = NULL;
945 else if (rtv)
946 wined3d_rendertarget_view_incref(rtv);
948 if ((dsv = wined3d_device_context_get_depth_stencil_view(ddraw->immediate_context)))
949 wined3d_rendertarget_view_incref(dsv);
952 ddraw_destroy_swapchain(ddraw);
955 if (FAILED(hr = ddraw_create_swapchain(ddraw, window, cooplevel)))
956 ERR("Failed to create swapchain, hr %#lx.\n", hr);
958 if (restore_state)
960 if (dsv)
962 wined3d_device_context_set_depth_stencil_view(ddraw->immediate_context, dsv);
963 wined3d_rendertarget_view_decref(dsv);
966 if (rtv)
968 wined3d_device_context_set_rendertarget_views(ddraw->immediate_context, 0, 1, &rtv, FALSE);
969 wined3d_rendertarget_view_decref(rtv);
972 wined3d_stateblock_apply(stateblock, device->state);
973 wined3d_stateblock_decref(stateblock);
976 if (!(cooplevel & DDSCL_EXCLUSIVE) && (ddraw->cooperative_level & DDSCL_EXCLUSIVE))
978 /* When going from exclusive mode to normal, ddraw removes the
979 topmost bit unless the DDSCL_NOWINDOWCHANGES flag is set in
980 this call that sets it to normal, not in the old coop level. */
981 if (!(cooplevel & DDSCL_NOWINDOWCHANGES))
982 SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
984 if (restore_mode_on_normal && FAILED(ddraw7_RestoreDisplayMode(&ddraw->IDirectDraw7_iface)))
985 ERR("RestoreDisplayMode failed\n");
986 ClipCursor(NULL);
989 if ((ddraw->cooperative_level & DDSCL_EXCLUSIVE)
990 && (window != ddraw->dest_window || !(cooplevel & DDSCL_EXCLUSIVE)))
991 wined3d_device_release_focus_window(ddraw->wined3d_device);
993 if ((cooplevel & DDSCL_EXCLUSIVE)
994 && (window != ddraw->dest_window || !(ddraw->cooperative_level & DDSCL_EXCLUSIVE)))
996 hr = wined3d_device_acquire_focus_window(ddraw->wined3d_device, window);
997 if (FAILED(hr))
999 ERR("Failed to acquire focus window, hr %#lx.\n", hr);
1000 goto done;
1004 if (cooplevel & DDSCL_EXCLUSIVE)
1006 SetRect(&clip_rect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1007 ClipCursor(&clip_rect);
1010 /* Unhandled flags */
1011 if (cooplevel & DDSCL_ALLOWREBOOT)
1012 WARN("Unhandled flag DDSCL_ALLOWREBOOT, harmless\n");
1013 if (cooplevel & DDSCL_ALLOWMODEX)
1014 WARN("Unhandled flag DDSCL_ALLOWMODEX, harmless\n");
1015 if (cooplevel & DDSCL_FPUSETUP)
1016 WARN("Unhandled flag DDSCL_FPUSETUP, harmless\n");
1018 if (cooplevel & DDSCL_EXCLUSIVE)
1019 exclusive_ddraw = ddraw;
1020 else if (exclusive_ddraw == ddraw)
1021 exclusive_ddraw = NULL;
1023 /* Store the cooperative_level */
1024 ddraw->cooperative_level = cooplevel;
1025 ddraw->dest_window = window;
1027 TRACE("SetCooperativeLevel returning DD_OK\n");
1028 hr = DD_OK;
1029 done:
1030 ddraw->flags &= ~DDRAW_SCL_RECURSIVE;
1031 wined3d_mutex_unlock();
1033 return hr;
1036 static HRESULT WINAPI ddraw7_SetCooperativeLevel(IDirectDraw7 *iface, HWND window, DWORD flags)
1038 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
1040 TRACE("iface %p, window %p, flags %#lx.\n", iface, window, flags);
1042 return ddraw_set_cooperative_level(ddraw, window, flags, !(ddraw->flags & DDRAW_SCL_DDRAW1));
1045 static HRESULT WINAPI ddraw4_SetCooperativeLevel(IDirectDraw4 *iface, HWND window, DWORD flags)
1047 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1049 TRACE("iface %p, window %p, flags %#lx.\n", iface, window, flags);
1051 return ddraw_set_cooperative_level(ddraw, window, flags, !(ddraw->flags & DDRAW_SCL_DDRAW1));
1054 static HRESULT WINAPI ddraw2_SetCooperativeLevel(IDirectDraw2 *iface, HWND window, DWORD flags)
1056 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
1058 TRACE("iface %p, window %p, flags %#lx.\n", iface, window, flags);
1060 return ddraw_set_cooperative_level(ddraw, window, flags, !(ddraw->flags & DDRAW_SCL_DDRAW1));
1063 static HRESULT WINAPI ddraw1_SetCooperativeLevel(IDirectDraw *iface, HWND window, DWORD flags)
1065 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
1066 HRESULT hr;
1068 TRACE("iface %p, window %p, flags %#lx.\n", iface, window, flags);
1070 hr = ddraw_set_cooperative_level(ddraw, window, flags, FALSE);
1071 if (SUCCEEDED(hr))
1072 ddraw->flags |= DDRAW_SCL_DDRAW1;
1073 return hr;
1076 /*****************************************************************************
1077 * IDirectDraw7::SetDisplayMode
1079 * Sets the display screen resolution, color depth and refresh frequency
1080 * when in fullscreen mode (in theory).
1081 * Possible return values listed in the SDK suggest that this method fails
1082 * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets
1083 * the display mode in DDSCL_NORMAL mode without an hwnd specified.
1084 * It seems to be valid to pass 0 for With and Height, this has to be tested
1085 * It could mean that the current video mode should be left as-is. (But why
1086 * call it then?)
1088 * Params:
1089 * Height, Width: Screen dimension
1090 * BPP: Color depth in Bits per pixel
1091 * Refreshrate: Screen refresh rate
1092 * Flags: Other stuff
1094 * Returns
1095 * DD_OK on success
1097 *****************************************************************************/
1098 static HRESULT WINAPI ddraw7_SetDisplayMode(IDirectDraw7 *iface, DWORD width, DWORD height,
1099 DWORD bpp, DWORD refresh_rate, DWORD flags)
1101 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
1102 struct wined3d_display_mode mode;
1103 enum wined3d_format_id format;
1104 RECT clip_rect;
1105 HRESULT hr;
1107 TRACE("iface %p, width %lu, height %lu, bpp %lu, refresh_rate %lu, flags %#lx.\n",
1108 iface, width, height, bpp, refresh_rate, flags);
1110 if (force_refresh_rate != 0)
1112 TRACE("ForceRefreshRate overriding passed-in refresh rate (%lu Hz) to %lu Hz\n",
1113 refresh_rate, force_refresh_rate);
1114 refresh_rate = force_refresh_rate;
1117 wined3d_mutex_lock();
1119 if (exclusive_ddraw && exclusive_ddraw != ddraw)
1121 wined3d_mutex_unlock();
1122 return DDERR_NOEXCLUSIVEMODE;
1125 if (!width || !height)
1127 /* It looks like Need for Speed Porsche Unleashed expects DD_OK here. */
1128 wined3d_mutex_unlock();
1129 return DD_OK;
1132 switch (bpp)
1134 case 8: format = WINED3DFMT_P8_UINT; break;
1135 case 15: format = WINED3DFMT_B5G5R5X1_UNORM; break;
1136 case 16: format = WINED3DFMT_B5G6R5_UNORM; break;
1137 case 24: format = WINED3DFMT_B8G8R8_UNORM; break;
1138 case 32: format = WINED3DFMT_B8G8R8X8_UNORM; break;
1139 default: format = WINED3DFMT_UNKNOWN; break;
1142 mode.width = width;
1143 mode.height = height;
1144 mode.refresh_rate = refresh_rate;
1145 mode.format_id = format;
1146 mode.scanline_ordering = WINED3D_SCANLINE_ORDERING_UNKNOWN;
1148 /* TODO: The possible return values from msdn suggest that the screen mode
1149 * can't be changed if a surface is locked or some drawing is in progress. */
1150 if (SUCCEEDED(hr = wined3d_output_set_display_mode(ddraw->wined3d_output, &mode)))
1152 if (ddraw->primary)
1154 DDSURFACEDESC2 *surface_desc = &ddraw->primary->surface_desc;
1156 if (FAILED(hr = wined3d_swapchain_resize_buffers(ddraw->wined3d_swapchain, 0,
1157 surface_desc->dwWidth, surface_desc->dwHeight, mode.format_id, WINED3D_MULTISAMPLE_NONE, 0)))
1158 ERR("Failed to resize buffers, hr %#lx.\n", hr);
1159 else
1160 ddrawformat_from_wined3dformat(&ddraw->primary->surface_desc.ddpfPixelFormat, mode.format_id);
1162 ddraw->flags |= DDRAW_RESTORE_MODE;
1164 if (ddraw->cooperative_level & DDSCL_EXCLUSIVE)
1166 SetRect(&clip_rect, 0, 0, width, height);
1167 ClipCursor(&clip_rect);
1171 InterlockedCompareExchange(&ddraw->device_state, DDRAW_DEVICE_STATE_NOT_RESTORED, DDRAW_DEVICE_STATE_OK);
1173 wined3d_mutex_unlock();
1175 return hr_ddraw_from_wined3d(hr);
1178 static HRESULT WINAPI ddraw4_SetDisplayMode(IDirectDraw4 *iface, DWORD width, DWORD height,
1179 DWORD bpp, DWORD refresh_rate, DWORD flags)
1181 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1183 TRACE("iface %p, width %lu, height %lu, bpp %lu, refresh_rate %lu, flags %#lx.\n",
1184 iface, width, height, bpp, refresh_rate, flags);
1186 return ddraw7_SetDisplayMode(&ddraw->IDirectDraw7_iface, width, height, bpp, refresh_rate, flags);
1189 static HRESULT WINAPI ddraw2_SetDisplayMode(IDirectDraw2 *iface,
1190 DWORD width, DWORD height, DWORD bpp, DWORD refresh_rate, DWORD flags)
1192 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
1194 TRACE("iface %p, width %lu, height %lu, bpp %lu, refresh_rate %lu, flags %#lx.\n",
1195 iface, width, height, bpp, refresh_rate, flags);
1197 return ddraw7_SetDisplayMode(&ddraw->IDirectDraw7_iface, width, height, bpp, refresh_rate, flags);
1200 static HRESULT WINAPI ddraw1_SetDisplayMode(IDirectDraw *iface, DWORD width, DWORD height, DWORD bpp)
1202 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
1204 TRACE("iface %p, width %lu, height %lu, bpp %lu.\n", iface, width, height, bpp);
1206 return ddraw7_SetDisplayMode(&ddraw->IDirectDraw7_iface, width, height, bpp, 0, 0);
1209 void ddraw_d3dcaps1_from_7(D3DDEVICEDESC *caps1, D3DDEVICEDESC7 *caps7)
1211 memset(caps1, 0, sizeof(*caps1));
1212 caps1->dwSize = sizeof(*caps1);
1213 caps1->dwFlags = D3DDD_COLORMODEL
1214 | D3DDD_DEVCAPS
1215 | D3DDD_TRANSFORMCAPS
1216 | D3DDD_BCLIPPING
1217 | D3DDD_LIGHTINGCAPS
1218 | D3DDD_LINECAPS
1219 | D3DDD_TRICAPS
1220 | D3DDD_DEVICERENDERBITDEPTH
1221 | D3DDD_DEVICEZBUFFERBITDEPTH
1222 | D3DDD_MAXBUFFERSIZE
1223 | D3DDD_MAXVERTEXCOUNT;
1224 caps1->dcmColorModel = D3DCOLOR_RGB;
1225 caps1->dwDevCaps = caps7->dwDevCaps;
1226 caps1->dtcTransformCaps.dwSize = sizeof(caps1->dtcTransformCaps);
1227 caps1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
1228 caps1->bClipping = TRUE;
1229 caps1->dlcLightingCaps.dwSize = sizeof(caps1->dlcLightingCaps);
1230 caps1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL
1231 | D3DLIGHTCAPS_PARALLELPOINT
1232 | D3DLIGHTCAPS_POINT
1233 | D3DLIGHTCAPS_SPOT;
1234 caps1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
1235 caps1->dlcLightingCaps.dwNumLights = caps7->dwMaxActiveLights;
1236 caps1->dpcLineCaps = caps7->dpcLineCaps;
1237 caps1->dpcTriCaps = caps7->dpcTriCaps;
1238 caps1->dwDeviceRenderBitDepth = caps7->dwDeviceRenderBitDepth;
1239 caps1->dwDeviceZBufferBitDepth = caps7->dwDeviceZBufferBitDepth;
1240 caps1->dwMaxBufferSize = 0;
1241 caps1->dwMaxVertexCount = 65536;
1242 caps1->dwMinTextureWidth = caps7->dwMinTextureWidth;
1243 caps1->dwMinTextureHeight = caps7->dwMinTextureHeight;
1244 caps1->dwMaxTextureWidth = caps7->dwMaxTextureWidth;
1245 caps1->dwMaxTextureHeight = caps7->dwMaxTextureHeight;
1246 caps1->dwMinStippleWidth = 1;
1247 caps1->dwMinStippleHeight = 1;
1248 caps1->dwMaxStippleWidth = 32;
1249 caps1->dwMaxStippleHeight = 32;
1250 caps1->dwMaxTextureRepeat = caps7->dwMaxTextureRepeat;
1251 caps1->dwMaxTextureAspectRatio = caps7->dwMaxTextureAspectRatio;
1252 caps1->dwMaxAnisotropy = caps7->dwMaxAnisotropy;
1253 caps1->dvGuardBandLeft = caps7->dvGuardBandLeft;
1254 caps1->dvGuardBandTop = caps7->dvGuardBandTop;
1255 caps1->dvGuardBandRight = caps7->dvGuardBandRight;
1256 caps1->dvGuardBandBottom = caps7->dvGuardBandBottom;
1257 caps1->dvExtentsAdjust = caps7->dvExtentsAdjust;
1258 caps1->dwStencilCaps = caps7->dwStencilCaps;
1259 caps1->dwFVFCaps = caps7->dwFVFCaps;
1260 caps1->dwTextureOpCaps = caps7->dwTextureOpCaps;
1261 caps1->wMaxTextureBlendStages = caps7->wMaxTextureBlendStages;
1262 caps1->wMaxSimultaneousTextures = caps7->wMaxSimultaneousTextures;
1265 HRESULT ddraw_get_d3dcaps(const struct ddraw *ddraw, D3DDEVICEDESC7 *caps)
1267 struct wined3d_caps wined3d_caps;
1268 HRESULT hr;
1270 TRACE("ddraw %p, caps %p.\n", ddraw, caps);
1272 memset(&wined3d_caps, 0, sizeof(wined3d_caps));
1274 wined3d_mutex_lock();
1275 hr = wined3d_get_device_caps(ddraw->wined3d_adapter, WINED3D_DEVICE_TYPE_HAL, &wined3d_caps);
1276 wined3d_mutex_unlock();
1277 if (FAILED(hr))
1279 WARN("Failed to get device caps, hr %#lx.\n", hr);
1280 return hr;
1283 caps->dwDevCaps = wined3d_caps.DevCaps;
1284 caps->dpcLineCaps.dwMiscCaps = wined3d_caps.PrimitiveMiscCaps;
1285 caps->dpcLineCaps.dwRasterCaps = wined3d_caps.RasterCaps;
1286 caps->dpcLineCaps.dwZCmpCaps = wined3d_caps.ZCmpCaps;
1287 caps->dpcLineCaps.dwSrcBlendCaps = wined3d_caps.SrcBlendCaps;
1288 caps->dpcLineCaps.dwDestBlendCaps = wined3d_caps.DestBlendCaps;
1289 caps->dpcLineCaps.dwAlphaCmpCaps = wined3d_caps.AlphaCmpCaps;
1290 caps->dpcLineCaps.dwShadeCaps = wined3d_caps.ShadeCaps;
1291 caps->dpcLineCaps.dwTextureCaps = wined3d_caps.TextureCaps;
1292 caps->dpcLineCaps.dwTextureFilterCaps = wined3d_caps.TextureFilterCaps;
1293 caps->dpcLineCaps.dwTextureAddressCaps = wined3d_caps.TextureAddressCaps;
1295 caps->dwMaxTextureWidth = wined3d_caps.MaxTextureWidth;
1296 caps->dwMaxTextureHeight = wined3d_caps.MaxTextureHeight;
1298 caps->dwMaxTextureRepeat = wined3d_caps.MaxTextureRepeat;
1299 caps->dwMaxTextureAspectRatio = wined3d_caps.MaxTextureAspectRatio;
1300 caps->dwMaxAnisotropy = wined3d_caps.MaxAnisotropy;
1301 caps->dvMaxVertexW = wined3d_caps.MaxVertexW;
1303 caps->dvGuardBandLeft = wined3d_caps.GuardBandLeft;
1304 caps->dvGuardBandTop = wined3d_caps.GuardBandTop;
1305 caps->dvGuardBandRight = wined3d_caps.GuardBandRight;
1306 caps->dvGuardBandBottom = wined3d_caps.GuardBandBottom;
1308 caps->dvExtentsAdjust = wined3d_caps.ExtentsAdjust;
1309 caps->dwStencilCaps = wined3d_caps.StencilCaps;
1311 caps->dwFVFCaps = wined3d_caps.FVFCaps;
1312 caps->dwTextureOpCaps = wined3d_caps.TextureOpCaps;
1314 caps->dwVertexProcessingCaps = wined3d_caps.VertexProcessingCaps;
1315 caps->dwMaxActiveLights = wined3d_caps.MaxActiveLights;
1317 /* Remove all non-d3d7 caps */
1318 caps->dwDevCaps &= (
1319 D3DDEVCAPS_FLOATTLVERTEX | D3DDEVCAPS_SORTINCREASINGZ | D3DDEVCAPS_SORTDECREASINGZ |
1320 D3DDEVCAPS_SORTEXACT | D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY |
1321 D3DDEVCAPS_TLVERTEXSYSTEMMEMORY | D3DDEVCAPS_TLVERTEXVIDEOMEMORY | D3DDEVCAPS_TEXTURESYSTEMMEMORY |
1322 D3DDEVCAPS_TEXTUREVIDEOMEMORY | D3DDEVCAPS_DRAWPRIMTLVERTEX | D3DDEVCAPS_CANRENDERAFTERFLIP |
1323 D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_DRAWPRIMITIVES2 | D3DDEVCAPS_SEPARATETEXTUREMEMORIES |
1324 D3DDEVCAPS_DRAWPRIMITIVES2EX | D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_CANBLTSYSTONONLOCAL |
1325 D3DDEVCAPS_HWRASTERIZATION);
1327 caps->dwStencilCaps &= (
1328 D3DSTENCILCAPS_KEEP | D3DSTENCILCAPS_ZERO | D3DSTENCILCAPS_REPLACE |
1329 D3DSTENCILCAPS_INCRSAT | D3DSTENCILCAPS_DECRSAT | D3DSTENCILCAPS_INVERT |
1330 D3DSTENCILCAPS_INCR | D3DSTENCILCAPS_DECR);
1332 /* FVF caps ?*/
1334 caps->dwTextureOpCaps &= (
1335 D3DTEXOPCAPS_DISABLE | D3DTEXOPCAPS_SELECTARG1 | D3DTEXOPCAPS_SELECTARG2 |
1336 D3DTEXOPCAPS_MODULATE | D3DTEXOPCAPS_MODULATE2X | D3DTEXOPCAPS_MODULATE4X |
1337 D3DTEXOPCAPS_ADD | D3DTEXOPCAPS_ADDSIGNED | D3DTEXOPCAPS_ADDSIGNED2X |
1338 D3DTEXOPCAPS_SUBTRACT | D3DTEXOPCAPS_ADDSMOOTH | D3DTEXOPCAPS_BLENDTEXTUREALPHA |
1339 D3DTEXOPCAPS_BLENDFACTORALPHA | D3DTEXOPCAPS_BLENDTEXTUREALPHAPM | D3DTEXOPCAPS_BLENDCURRENTALPHA |
1340 D3DTEXOPCAPS_PREMODULATE | D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR | D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA |
1341 D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA | D3DTEXOPCAPS_BUMPENVMAP |
1342 D3DTEXOPCAPS_BUMPENVMAPLUMINANCE | D3DTEXOPCAPS_DOTPRODUCT3);
1344 caps->dwVertexProcessingCaps &= (
1345 D3DVTXPCAPS_TEXGEN | D3DVTXPCAPS_MATERIALSOURCE7 | D3DVTXPCAPS_VERTEXFOG |
1346 D3DVTXPCAPS_DIRECTIONALLIGHTS | D3DVTXPCAPS_POSITIONALLIGHTS | D3DVTXPCAPS_LOCALVIEWER);
1348 caps->dpcLineCaps.dwMiscCaps &= (
1349 D3DPMISCCAPS_MASKPLANES | D3DPMISCCAPS_MASKZ | D3DPMISCCAPS_LINEPATTERNREP |
1350 D3DPMISCCAPS_CONFORMANT | D3DPMISCCAPS_CULLNONE | D3DPMISCCAPS_CULLCW |
1351 D3DPMISCCAPS_CULLCCW);
1353 caps->dpcLineCaps.dwRasterCaps &= (
1354 D3DPRASTERCAPS_DITHER | D3DPRASTERCAPS_ROP2 | D3DPRASTERCAPS_XOR |
1355 D3DPRASTERCAPS_PAT | D3DPRASTERCAPS_ZTEST | D3DPRASTERCAPS_SUBPIXEL |
1356 D3DPRASTERCAPS_SUBPIXELX | D3DPRASTERCAPS_FOGVERTEX | D3DPRASTERCAPS_FOGTABLE |
1357 D3DPRASTERCAPS_STIPPLE | D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT | D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT |
1358 D3DPRASTERCAPS_ANTIALIASEDGES | D3DPRASTERCAPS_MIPMAPLODBIAS |
1359 D3DPRASTERCAPS_ZBUFFERLESSHSR | D3DPRASTERCAPS_FOGRANGE | D3DPRASTERCAPS_ANISOTROPY |
1360 D3DPRASTERCAPS_WBUFFER | D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT | D3DPRASTERCAPS_WFOG |
1361 D3DPRASTERCAPS_ZFOG | WINED3DPRASTERCAPS_DEPTHBIAS);
1362 if (caps->dpcLineCaps.dwRasterCaps & WINED3DPRASTERCAPS_DEPTHBIAS)
1363 caps->dpcLineCaps.dwRasterCaps = (caps->dpcLineCaps.dwRasterCaps | D3DPRASTERCAPS_ZBIAS)
1364 & ~WINED3DPRASTERCAPS_DEPTHBIAS;
1365 if (wined3d_caps.LineCaps & WINED3DLINECAPS_ANTIALIAS)
1366 caps->dpcLineCaps.dwRasterCaps |= D3DPRASTERCAPS_ANTIALIASEDGES;
1368 caps->dpcLineCaps.dwZCmpCaps &= (
1369 D3DPCMPCAPS_NEVER | D3DPCMPCAPS_LESS | D3DPCMPCAPS_EQUAL |
1370 D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_NOTEQUAL |
1371 D3DPCMPCAPS_GREATEREQUAL | D3DPCMPCAPS_ALWAYS);
1373 caps->dpcLineCaps.dwSrcBlendCaps &= (
1374 D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR |
1375 D3DPBLENDCAPS_INVSRCCOLOR | D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA |
1376 D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_DESTCOLOR |
1377 D3DPBLENDCAPS_INVDESTCOLOR | D3DPBLENDCAPS_SRCALPHASAT | D3DPBLENDCAPS_BOTHSRCALPHA |
1378 D3DPBLENDCAPS_BOTHINVSRCALPHA);
1380 caps->dpcLineCaps.dwDestBlendCaps &= (
1381 D3DPBLENDCAPS_ZERO | D3DPBLENDCAPS_ONE | D3DPBLENDCAPS_SRCCOLOR |
1382 D3DPBLENDCAPS_INVSRCCOLOR | D3DPBLENDCAPS_SRCALPHA | D3DPBLENDCAPS_INVSRCALPHA |
1383 D3DPBLENDCAPS_DESTALPHA | D3DPBLENDCAPS_INVDESTALPHA | D3DPBLENDCAPS_DESTCOLOR |
1384 D3DPBLENDCAPS_INVDESTCOLOR | D3DPBLENDCAPS_SRCALPHASAT | D3DPBLENDCAPS_BOTHSRCALPHA |
1385 D3DPBLENDCAPS_BOTHINVSRCALPHA);
1387 caps->dpcLineCaps.dwAlphaCmpCaps &= (
1388 D3DPCMPCAPS_NEVER | D3DPCMPCAPS_LESS | D3DPCMPCAPS_EQUAL |
1389 D3DPCMPCAPS_LESSEQUAL | D3DPCMPCAPS_GREATER | D3DPCMPCAPS_NOTEQUAL |
1390 D3DPCMPCAPS_GREATEREQUAL | D3DPCMPCAPS_ALWAYS);
1392 caps->dpcLineCaps.dwShadeCaps &= (
1393 D3DPSHADECAPS_COLORFLATMONO | D3DPSHADECAPS_COLORFLATRGB | D3DPSHADECAPS_COLORGOURAUDMONO |
1394 D3DPSHADECAPS_COLORGOURAUDRGB | D3DPSHADECAPS_COLORPHONGMONO | D3DPSHADECAPS_COLORPHONGRGB |
1395 D3DPSHADECAPS_SPECULARFLATMONO | D3DPSHADECAPS_SPECULARFLATRGB | D3DPSHADECAPS_SPECULARGOURAUDMONO |
1396 D3DPSHADECAPS_SPECULARGOURAUDRGB | D3DPSHADECAPS_SPECULARPHONGMONO | D3DPSHADECAPS_SPECULARPHONGRGB |
1397 D3DPSHADECAPS_ALPHAFLATBLEND | D3DPSHADECAPS_ALPHAFLATSTIPPLED | D3DPSHADECAPS_ALPHAGOURAUDBLEND |
1398 D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED | D3DPSHADECAPS_ALPHAPHONGBLEND | D3DPSHADECAPS_ALPHAPHONGSTIPPLED |
1399 D3DPSHADECAPS_FOGFLAT | D3DPSHADECAPS_FOGGOURAUD | D3DPSHADECAPS_FOGPHONG);
1401 caps->dpcLineCaps.dwTextureCaps &= (
1402 D3DPTEXTURECAPS_PERSPECTIVE | D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_ALPHA |
1403 D3DPTEXTURECAPS_TRANSPARENCY | D3DPTEXTURECAPS_BORDER | D3DPTEXTURECAPS_SQUAREONLY |
1404 D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE | D3DPTEXTURECAPS_ALPHAPALETTE| D3DPTEXTURECAPS_NONPOW2CONDITIONAL |
1405 D3DPTEXTURECAPS_PROJECTED | D3DPTEXTURECAPS_CUBEMAP | D3DPTEXTURECAPS_COLORKEYBLEND);
1407 caps->dpcLineCaps.dwTextureFilterCaps &= (
1408 D3DPTFILTERCAPS_NEAREST | D3DPTFILTERCAPS_LINEAR | D3DPTFILTERCAPS_MIPNEAREST |
1409 D3DPTFILTERCAPS_MIPLINEAR | D3DPTFILTERCAPS_LINEARMIPNEAREST | D3DPTFILTERCAPS_LINEARMIPLINEAR |
1410 D3DPTFILTERCAPS_MINFPOINT | D3DPTFILTERCAPS_MINFLINEAR | D3DPTFILTERCAPS_MINFANISOTROPIC |
1411 D3DPTFILTERCAPS_MIPFPOINT | D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MAGFPOINT |
1412 D3DPTFILTERCAPS_MAGFLINEAR | D3DPTFILTERCAPS_MAGFANISOTROPIC | D3DPTFILTERCAPS_MAGFAFLATCUBIC |
1413 D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC);
1415 caps->dpcLineCaps.dwTextureAddressCaps &= (
1416 D3DPTADDRESSCAPS_WRAP | D3DPTADDRESSCAPS_MIRROR | D3DPTADDRESSCAPS_CLAMP |
1417 D3DPTADDRESSCAPS_BORDER | D3DPTADDRESSCAPS_INDEPENDENTUV);
1419 if (!(caps->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2))
1421 /* DirectX7 always has the np2 flag set, no matter what the card
1422 * supports. Some old games (Rollcage) check the caps incorrectly.
1423 * If wined3d supports nonpow2 textures it also has np2 conditional
1424 * support. */
1425 caps->dpcLineCaps.dwTextureCaps |= D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL;
1428 /* Fill the missing members, and do some fixup */
1429 caps->dpcLineCaps.dwSize = sizeof(caps->dpcLineCaps);
1430 caps->dpcLineCaps.dwTextureBlendCaps = D3DPTBLENDCAPS_ADD
1431 | D3DPTBLENDCAPS_MODULATEMASK
1432 | D3DPTBLENDCAPS_COPY
1433 | D3DPTBLENDCAPS_DECAL
1434 | D3DPTBLENDCAPS_DECALALPHA
1435 | D3DPTBLENDCAPS_DECALMASK
1436 | D3DPTBLENDCAPS_MODULATE
1437 | D3DPTBLENDCAPS_MODULATEALPHA;
1438 caps->dpcLineCaps.dwStippleWidth = 32;
1439 caps->dpcLineCaps.dwStippleHeight = 32;
1440 /* Use the same for the TriCaps */
1441 caps->dpcTriCaps = caps->dpcLineCaps;
1443 caps->dwDeviceRenderBitDepth = DDBD_16 | DDBD_24 | DDBD_32;
1444 caps->dwDeviceZBufferBitDepth = DDBD_16 | DDBD_24;
1445 caps->dwMinTextureWidth = 1;
1446 caps->dwMinTextureHeight = 1;
1448 /* Convert DWORDs safely to WORDs */
1449 caps->wMaxTextureBlendStages = min(wined3d_caps.MaxTextureBlendStages, 0xffff);
1450 caps->wMaxSimultaneousTextures = min(wined3d_caps.MaxSimultaneousTextures, 0xffff);
1451 caps->wMaxUserClipPlanes = min(wined3d_caps.MaxUserClipPlanes, D3DMAXUSERCLIPPLANES);
1452 caps->wMaxVertexBlendMatrices = min(wined3d_caps.MaxVertexBlendMatrices, 0xffff);
1454 caps->deviceGUID = IID_IDirect3DTnLHalDevice;
1456 caps->dwReserved1 = 0;
1457 caps->dwReserved2 = 0;
1458 caps->dwReserved3 = 0;
1459 caps->dwReserved4 = 0;
1461 return DD_OK;
1464 /*****************************************************************************
1465 * IDirectDraw7::GetCaps
1467 * Returns the drives capabilities
1469 * Used for version 1, 2, 4 and 7
1471 * Params:
1472 * DriverCaps: Structure to write the Hardware accelerated caps to
1473 * HelCaps: Structure to write the emulation caps to
1475 * Returns
1476 * This implementation returns DD_OK only
1478 *****************************************************************************/
1479 static HRESULT WINAPI ddraw7_GetCaps(IDirectDraw7 *iface, DDCAPS *DriverCaps, DDCAPS *HELCaps)
1481 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
1482 DDSCAPS2 ddscaps = {0, 0, 0, {0}};
1483 struct wined3d_caps winecaps;
1484 DDCAPS caps;
1485 HRESULT hr;
1487 TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, DriverCaps, HELCaps);
1489 /* One structure must be != NULL */
1490 if (!DriverCaps && !HELCaps)
1492 WARN("Invalid parameters.\n");
1493 return DDERR_INVALIDPARAMS;
1496 memset(&caps, 0, sizeof(caps));
1497 memset(&winecaps, 0, sizeof(winecaps));
1498 caps.dwSize = sizeof(caps);
1500 wined3d_mutex_lock();
1501 hr = wined3d_device_get_device_caps(ddraw->wined3d_device, &winecaps);
1502 if (FAILED(hr))
1504 WARN("Failed to get device caps, %#lx.\n", hr);
1505 wined3d_mutex_unlock();
1506 return hr;
1509 hr = IDirectDraw7_GetAvailableVidMem(iface, &ddscaps, &caps.dwVidMemTotal, &caps.dwVidMemFree);
1510 if (FAILED(hr))
1512 WARN("IDirectDraw7::GetAvailableVidMem failed\n");
1513 wined3d_mutex_unlock();
1514 return hr;
1517 hr = IDirectDraw7_GetFourCCCodes(iface, &caps.dwNumFourCCCodes, NULL);
1518 wined3d_mutex_unlock();
1519 if (FAILED(hr))
1521 WARN("IDirectDraw7::GetFourCCCodes failed\n");
1522 return hr;
1525 caps.dwCaps = winecaps.ddraw_caps.caps;
1526 caps.dwCaps2 = winecaps.ddraw_caps.caps2;
1527 caps.dwCKeyCaps = winecaps.ddraw_caps.color_key_caps;
1528 caps.dwFXCaps = winecaps.ddraw_caps.fx_caps;
1529 caps.dwPalCaps = DDPCAPS_8BIT | DDPCAPS_PRIMARYSURFACE;
1530 caps.ddsCaps.dwCaps = winecaps.ddraw_caps.dds_caps;
1531 caps.dwSVBCaps = winecaps.ddraw_caps.svb_caps;
1532 caps.dwSVBCKeyCaps = winecaps.ddraw_caps.svb_color_key_caps;
1533 caps.dwSVBFXCaps = winecaps.ddraw_caps.svb_fx_caps;
1534 caps.dwVSBCaps = winecaps.ddraw_caps.vsb_caps;
1535 caps.dwVSBCKeyCaps = winecaps.ddraw_caps.vsb_color_key_caps;
1536 caps.dwVSBFXCaps = winecaps.ddraw_caps.vsb_fx_caps;
1537 caps.dwSSBCaps = winecaps.ddraw_caps.ssb_caps;
1538 caps.dwSSBCKeyCaps = winecaps.ddraw_caps.ssb_color_key_caps;
1539 caps.dwSSBFXCaps = winecaps.ddraw_caps.ssb_fx_caps;
1541 caps.dwCaps |= DDCAPS_ALIGNSTRIDE;
1542 caps.dwAlignStrideAlign = DDRAW_STRIDE_ALIGNMENT;
1544 caps.ddsOldCaps.dwCaps = caps.ddsCaps.dwCaps;
1546 if(DriverCaps)
1548 DD_STRUCT_COPY_BYSIZE(DriverCaps, &caps);
1549 if (TRACE_ON(ddraw))
1551 TRACE("Driver Caps :\n");
1552 DDRAW_dump_DDCAPS(DriverCaps);
1556 if(HELCaps)
1558 DD_STRUCT_COPY_BYSIZE(HELCaps, &caps);
1559 if (TRACE_ON(ddraw))
1561 TRACE("HEL Caps :\n");
1562 DDRAW_dump_DDCAPS(HELCaps);
1566 return DD_OK;
1569 static HRESULT WINAPI ddraw4_GetCaps(IDirectDraw4 *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1571 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1573 TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1575 return ddraw7_GetCaps(&ddraw->IDirectDraw7_iface, driver_caps, hel_caps);
1578 static HRESULT WINAPI ddraw2_GetCaps(IDirectDraw2 *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1580 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
1582 TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1584 return ddraw7_GetCaps(&ddraw->IDirectDraw7_iface, driver_caps, hel_caps);
1587 static HRESULT WINAPI ddraw1_GetCaps(IDirectDraw *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1589 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
1591 TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1593 return ddraw7_GetCaps(&ddraw->IDirectDraw7_iface, driver_caps, hel_caps);
1596 /*****************************************************************************
1597 * IDirectDraw7::Compact
1599 * No idea what it does, MSDN says it's not implemented.
1601 * Returns
1602 * DD_OK, but this is unchecked
1604 *****************************************************************************/
1605 static HRESULT WINAPI ddraw7_Compact(IDirectDraw7 *iface)
1607 TRACE("iface %p.\n", iface);
1609 return DD_OK;
1612 static HRESULT WINAPI ddraw4_Compact(IDirectDraw4 *iface)
1614 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1616 TRACE("iface %p.\n", iface);
1618 return ddraw7_Compact(&ddraw->IDirectDraw7_iface);
1621 static HRESULT WINAPI ddraw2_Compact(IDirectDraw2 *iface)
1623 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
1625 TRACE("iface %p.\n", iface);
1627 return ddraw7_Compact(&ddraw->IDirectDraw7_iface);
1630 static HRESULT WINAPI ddraw1_Compact(IDirectDraw *iface)
1632 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
1634 TRACE("iface %p.\n", iface);
1636 return ddraw7_Compact(&ddraw->IDirectDraw7_iface);
1639 /*****************************************************************************
1640 * IDirectDraw7::GetDisplayMode
1642 * Returns information about the current display mode
1644 * Exists in versions 1, 2, 4 and 7
1646 * Params:
1647 * DDSD: Address of a surface description structure to write the info to
1649 * Returns
1650 * DD_OK
1652 *****************************************************************************/
1653 static HRESULT WINAPI ddraw7_GetDisplayMode(IDirectDraw7 *iface, DDSURFACEDESC2 *DDSD)
1655 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
1656 struct wined3d_display_mode mode;
1657 HRESULT hr;
1659 TRACE("iface %p, surface_desc %p.\n", iface, DDSD);
1661 /* This seems sane */
1662 if (!DDSD || (DDSD->dwSize != sizeof(DDSURFACEDESC) && DDSD->dwSize != sizeof(DDSURFACEDESC2)))
1663 return DDERR_INVALIDPARAMS;
1665 wined3d_mutex_lock();
1667 if (FAILED(hr = wined3d_output_get_display_mode(ddraw->wined3d_output, &mode, NULL)))
1669 ERR("Failed to get display mode, hr %#lx.\n", hr);
1670 wined3d_mutex_unlock();
1671 return hr;
1674 memset(DDSD, 0, DDSD->dwSize);
1675 DDSD->dwSize = sizeof(*DDSD);
1676 DDSD->dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_REFRESHRATE;
1677 DDSD->dwWidth = mode.width;
1678 DDSD->dwHeight = mode.height;
1679 DDSD->dwRefreshRate = mode.refresh_rate;
1680 DDSD->ddpfPixelFormat.dwSize = sizeof(DDSD->ddpfPixelFormat);
1681 ddrawformat_from_wined3dformat(&DDSD->ddpfPixelFormat, mode.format_id);
1682 DDSD->lPitch = mode.width * DDSD->ddpfPixelFormat.dwRGBBitCount / 8;
1684 if(TRACE_ON(ddraw))
1686 TRACE("Returning surface desc :\n");
1687 DDRAW_dump_surface_desc(DDSD);
1690 wined3d_mutex_unlock();
1692 return DD_OK;
1695 static HRESULT WINAPI ddraw4_GetDisplayMode(IDirectDraw4 *iface, DDSURFACEDESC2 *surface_desc)
1697 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1699 TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1701 return ddraw7_GetDisplayMode(&ddraw->IDirectDraw7_iface, surface_desc);
1704 static HRESULT WINAPI ddraw2_GetDisplayMode(IDirectDraw2 *iface, DDSURFACEDESC *surface_desc)
1706 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
1707 HRESULT hr;
1709 TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1711 hr = ddraw7_GetDisplayMode(&ddraw->IDirectDraw7_iface, (DDSURFACEDESC2 *)surface_desc);
1712 if (SUCCEEDED(hr)) surface_desc->dwSize = sizeof(*surface_desc);
1713 return hr;
1716 static HRESULT WINAPI ddraw1_GetDisplayMode(IDirectDraw *iface, DDSURFACEDESC *surface_desc)
1718 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
1719 HRESULT hr;
1721 TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1723 hr = ddraw7_GetDisplayMode(&ddraw->IDirectDraw7_iface, (DDSURFACEDESC2 *)surface_desc);
1724 if (SUCCEEDED(hr)) surface_desc->dwSize = sizeof(*surface_desc);
1725 return hr;
1728 /*****************************************************************************
1729 * IDirectDraw7::GetFourCCCodes
1731 * Returns an array of supported FourCC codes.
1733 * Exists in versions 1, 2, 4 and 7
1735 * Params:
1736 * NumCodes: Contains the number of Codes that Codes can carry. Returns the number
1737 * of enumerated codes
1738 * Codes: Pointer to an array of DWORDs where the supported codes are written
1739 * to
1741 * Returns
1742 * Always returns DD_OK, as it's a stub for now
1744 *****************************************************************************/
1745 static HRESULT WINAPI ddraw7_GetFourCCCodes(IDirectDraw7 *iface, DWORD *NumCodes, DWORD *Codes)
1747 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
1748 static const enum wined3d_format_id formats[] =
1750 WINED3DFMT_YUY2, WINED3DFMT_UYVY, WINED3DFMT_YV12,
1751 WINED3DFMT_DXT1, WINED3DFMT_DXT2, WINED3DFMT_DXT3, WINED3DFMT_DXT4, WINED3DFMT_DXT5,
1752 WINED3DFMT_ATI2N, WINED3DFMT_NVHU, WINED3DFMT_NVHS
1754 struct wined3d_display_mode mode;
1755 DWORD count = 0, i, outsize;
1756 HRESULT hr;
1758 TRACE("iface %p, codes_count %p, codes %p.\n", iface, NumCodes, Codes);
1760 if (FAILED(hr = wined3d_output_get_display_mode(ddraw->wined3d_output, &mode, NULL)))
1762 ERR("Failed to get display mode, hr %#lx.\n", hr);
1763 return hr;
1766 outsize = NumCodes && Codes ? *NumCodes : 0;
1768 for (i = 0; i < ARRAY_SIZE(formats); ++i)
1770 if (SUCCEEDED(wined3d_check_device_format(ddraw->wined3d, ddraw->wined3d_adapter, WINED3D_DEVICE_TYPE_HAL,
1771 mode.format_id, 0, 0, WINED3D_RTYPE_TEXTURE_2D, formats[i])))
1773 if (count < outsize)
1774 Codes[count] = formats[i];
1775 ++count;
1778 if(NumCodes) {
1779 TRACE("Returning %lu FourCC codes\n", count);
1780 *NumCodes = count;
1783 return DD_OK;
1786 static HRESULT WINAPI ddraw4_GetFourCCCodes(IDirectDraw4 *iface, DWORD *codes_count, DWORD *codes)
1788 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1790 TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1792 return ddraw7_GetFourCCCodes(&ddraw->IDirectDraw7_iface, codes_count, codes);
1795 static HRESULT WINAPI ddraw2_GetFourCCCodes(IDirectDraw2 *iface, DWORD *codes_count, DWORD *codes)
1797 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
1799 TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1801 return ddraw7_GetFourCCCodes(&ddraw->IDirectDraw7_iface, codes_count, codes);
1804 static HRESULT WINAPI ddraw1_GetFourCCCodes(IDirectDraw *iface, DWORD *codes_count, DWORD *codes)
1806 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
1808 TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1810 return ddraw7_GetFourCCCodes(&ddraw->IDirectDraw7_iface, codes_count, codes);
1813 static HRESULT WINAPI ddraw7_GetMonitorFrequency(IDirectDraw7 *iface, DWORD *frequency)
1815 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
1816 struct wined3d_display_mode mode;
1817 HRESULT hr;
1819 TRACE("iface %p, frequency %p.\n", iface, frequency);
1821 wined3d_mutex_lock();
1822 hr = wined3d_output_get_display_mode(ddraw->wined3d_output, &mode, NULL);
1823 wined3d_mutex_unlock();
1824 if (FAILED(hr))
1826 WARN("Failed to get display mode, hr %#lx.\n", hr);
1827 return hr;
1830 *frequency = mode.refresh_rate;
1832 return DD_OK;
1835 static HRESULT WINAPI ddraw4_GetMonitorFrequency(IDirectDraw4 *iface, DWORD *frequency)
1837 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1839 TRACE("iface %p, frequency %p.\n", iface, frequency);
1841 return ddraw7_GetMonitorFrequency(&ddraw->IDirectDraw7_iface, frequency);
1844 static HRESULT WINAPI ddraw2_GetMonitorFrequency(IDirectDraw2 *iface, DWORD *frequency)
1846 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
1848 TRACE("iface %p, frequency %p.\n", iface, frequency);
1850 return ddraw7_GetMonitorFrequency(&ddraw->IDirectDraw7_iface, frequency);
1853 static HRESULT WINAPI ddraw1_GetMonitorFrequency(IDirectDraw *iface, DWORD *frequency)
1855 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
1857 TRACE("iface %p, frequency %p.\n", iface, frequency);
1859 return ddraw7_GetMonitorFrequency(&ddraw->IDirectDraw7_iface, frequency);
1862 static HRESULT WINAPI ddraw7_GetVerticalBlankStatus(IDirectDraw7 *iface, BOOL *status)
1864 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
1865 struct wined3d_raster_status raster_status;
1866 HRESULT hr;
1868 TRACE("iface %p, status %p.\n", iface, status);
1870 if(!status)
1871 return DDERR_INVALIDPARAMS;
1873 wined3d_mutex_lock();
1874 hr = wined3d_output_get_raster_status(ddraw->wined3d_output, &raster_status);
1875 wined3d_mutex_unlock();
1876 if (FAILED(hr))
1878 WARN("Failed to get raster status, hr %#lx.\n", hr);
1879 return hr;
1882 *status = raster_status.in_vblank;
1884 return DD_OK;
1887 static HRESULT WINAPI ddraw4_GetVerticalBlankStatus(IDirectDraw4 *iface, BOOL *status)
1889 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1891 TRACE("iface %p, status %p.\n", iface, status);
1893 return ddraw7_GetVerticalBlankStatus(&ddraw->IDirectDraw7_iface, status);
1896 static HRESULT WINAPI ddraw2_GetVerticalBlankStatus(IDirectDraw2 *iface, BOOL *status)
1898 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
1900 TRACE("iface %p, status %p.\n", iface, status);
1902 return ddraw7_GetVerticalBlankStatus(&ddraw->IDirectDraw7_iface, status);
1905 static HRESULT WINAPI ddraw1_GetVerticalBlankStatus(IDirectDraw *iface, BOOL *status)
1907 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
1909 TRACE("iface %p, status %p.\n", iface, status);
1911 return ddraw7_GetVerticalBlankStatus(&ddraw->IDirectDraw7_iface, status);
1914 /*****************************************************************************
1915 * IDirectDraw7::GetAvailableVidMem
1917 * Returns the total and free video memory
1919 * Params:
1920 * caps: Specifies the memory type asked for
1921 * total: Pointer to a DWORD to be filled with the total memory
1922 * free: Pointer to a DWORD to be filled with the free memory
1924 * Returns
1925 * DD_OK on success
1926 * DDERR_INVALIDPARAMS if free and total are NULL
1928 *****************************************************************************/
1929 static HRESULT WINAPI ddraw7_GetAvailableVidMem(IDirectDraw7 *iface, DDSCAPS2 *caps, DWORD *total,
1930 DWORD *free)
1932 unsigned int framebuffer_size, total_vidmem, free_vidmem;
1933 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
1934 struct wined3d_display_mode mode;
1935 HRESULT hr = DD_OK;
1937 TRACE("iface %p, caps %p, total %p, free %p.\n", iface, caps, total, free);
1939 if (!total && !free)
1940 return DDERR_INVALIDPARAMS;
1942 if (TRACE_ON(ddraw))
1944 TRACE("Asked for memory with description: ");
1945 DDRAW_dump_DDSCAPS2(caps);
1947 wined3d_mutex_lock();
1949 /* Todo: System memory vs local video memory vs non-local video memory
1950 * The MSDN also mentions differences between texture memory and other
1951 * resources, but that's not important
1954 /* Some applications (e.g. 3DMark 2000) assume that the reported amount of
1955 * video memory doesn't include the memory used by the default framebuffer.
1957 if (FAILED(hr = wined3d_output_get_display_mode(ddraw->wined3d_output, &mode, NULL)))
1959 WARN("Failed to get display mode, hr %#lx.\n", hr);
1960 wined3d_mutex_unlock();
1961 return hr;
1963 framebuffer_size = wined3d_calculate_format_pitch(ddraw->wined3d_adapter,
1964 mode.format_id, mode.width);
1965 framebuffer_size *= mode.height;
1967 if (free)
1969 free_vidmem = wined3d_device_get_available_texture_mem(ddraw->wined3d_device);
1970 *free = framebuffer_size > free_vidmem ? 0 : free_vidmem - framebuffer_size;
1971 TRACE("Free video memory %#lx.\n", *free);
1974 if (total)
1976 struct wined3d_adapter_identifier desc = {0};
1978 hr = wined3d_adapter_get_identifier(ddraw->wined3d_adapter, 0, &desc);
1979 total_vidmem = min(UINT_MAX, desc.video_memory);
1980 *total = framebuffer_size > total_vidmem ? 0 : total_vidmem - framebuffer_size;
1981 TRACE("Total video memory %#lx.\n", *total);
1984 wined3d_mutex_unlock();
1986 return hr;
1989 static HRESULT WINAPI ddraw4_GetAvailableVidMem(IDirectDraw4 *iface,
1990 DDSCAPS2 *caps, DWORD *total, DWORD *free)
1992 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
1994 TRACE("iface %p, caps %p, total %p, free %p.\n", iface, caps, total, free);
1996 return ddraw7_GetAvailableVidMem(&ddraw->IDirectDraw7_iface, caps, total, free);
1999 static HRESULT WINAPI ddraw2_GetAvailableVidMem(IDirectDraw2 *iface,
2000 DDSCAPS *caps, DWORD *total, DWORD *free)
2002 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2003 DDSCAPS2 caps2;
2005 TRACE("iface %p, caps %p, total %p, free %p.\n", iface, caps, total, free);
2007 DDRAW_Convert_DDSCAPS_1_To_2(caps, &caps2);
2008 return ddraw7_GetAvailableVidMem(&ddraw->IDirectDraw7_iface, &caps2, total, free);
2011 /*****************************************************************************
2012 * IDirectDraw7::Initialize
2014 * Initializes a DirectDraw interface.
2016 * Params:
2017 * GUID: Interface identifier. Well, don't know what this is really good
2018 * for
2020 * Returns
2021 * Returns DD_OK on the first call,
2022 * DDERR_ALREADYINITIALIZED on repeated calls
2024 *****************************************************************************/
2025 static HRESULT WINAPI ddraw7_Initialize(IDirectDraw7 *iface, GUID *guid)
2027 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2029 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
2031 if (ddraw->flags & DDRAW_INITIALIZED)
2032 return DDERR_ALREADYINITIALIZED;
2034 /* FIXME: To properly take the GUID into account we should call
2035 * ddraw_init() here instead of in DDRAW_Create(). */
2036 if (guid)
2037 FIXME("Ignoring guid %s.\n", debugstr_guid(guid));
2039 ddraw->flags |= DDRAW_INITIALIZED;
2040 return DD_OK;
2043 static HRESULT WINAPI ddraw4_Initialize(IDirectDraw4 *iface, GUID *guid)
2045 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2047 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
2049 return ddraw7_Initialize(&ddraw->IDirectDraw7_iface, guid);
2052 static HRESULT WINAPI ddraw2_Initialize(IDirectDraw2 *iface, GUID *guid)
2054 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2056 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
2058 return ddraw7_Initialize(&ddraw->IDirectDraw7_iface, guid);
2061 static HRESULT WINAPI ddraw1_Initialize(IDirectDraw *iface, GUID *guid)
2063 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2065 TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
2067 return ddraw7_Initialize(&ddraw->IDirectDraw7_iface, guid);
2070 static HRESULT WINAPI d3d1_Initialize(IDirect3D *iface, REFIID riid)
2072 TRACE("iface %p, riid %s.\n", iface, debugstr_guid(riid));
2074 return DDERR_ALREADYINITIALIZED;
2077 /*****************************************************************************
2078 * IDirectDraw7::FlipToGDISurface
2080 * "Makes the surface that the GDI writes to the primary surface"
2081 * Looks like some windows specific thing we don't have to care about.
2082 * According to MSDN it permits GDI dialog boxes in FULLSCREEN mode. Good to
2083 * show error boxes ;)
2084 * Well, just return DD_OK.
2086 * Returns:
2087 * Always returns DD_OK
2089 *****************************************************************************/
2090 static HRESULT WINAPI ddraw7_FlipToGDISurface(IDirectDraw7 *iface)
2092 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2093 IDirectDrawSurface7 *gdi_surface;
2094 struct ddraw_surface *gdi_impl;
2095 HRESULT hr;
2097 TRACE("iface %p.\n", iface);
2099 wined3d_mutex_lock();
2101 if (FAILED(hr = IDirectDraw7_GetGDISurface(iface, &gdi_surface)))
2103 WARN("Failed to retrieve GDI surface, hr %#lx.\n", hr);
2104 wined3d_mutex_unlock();
2105 return hr;
2108 gdi_impl = impl_from_IDirectDrawSurface7(gdi_surface);
2109 if (gdi_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2110 hr = DD_OK;
2111 else
2112 hr = IDirectDrawSurface7_Flip(&ddraw->primary->IDirectDrawSurface7_iface, gdi_surface, DDFLIP_WAIT);
2113 IDirectDrawSurface7_Release(gdi_surface);
2115 wined3d_mutex_unlock();
2117 return hr;
2120 static HRESULT WINAPI ddraw4_FlipToGDISurface(IDirectDraw4 *iface)
2122 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2124 TRACE("iface %p.\n", iface);
2126 return ddraw7_FlipToGDISurface(&ddraw->IDirectDraw7_iface);
2129 static HRESULT WINAPI ddraw2_FlipToGDISurface(IDirectDraw2 *iface)
2131 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2133 TRACE("iface %p.\n", iface);
2135 return ddraw7_FlipToGDISurface(&ddraw->IDirectDraw7_iface);
2138 static HRESULT WINAPI ddraw1_FlipToGDISurface(IDirectDraw *iface)
2140 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2142 TRACE("iface %p.\n", iface);
2144 return ddraw7_FlipToGDISurface(&ddraw->IDirectDraw7_iface);
2147 /*****************************************************************************
2148 * IDirectDraw7::WaitForVerticalBlank
2150 * This method allows applications to get in sync with the vertical blank
2151 * interval.
2152 * The wormhole demo in the DirectX 7 sdk uses this call, and it doesn't
2153 * redraw the screen, most likely because of this stub
2155 * Parameters:
2156 * Flags: one of DDWAITVB_BLOCKBEGIN, DDWAITVB_BLOCKBEGINEVENT
2157 * or DDWAITVB_BLOCKEND
2158 * h: Not used, according to MSDN
2160 * Returns:
2161 * Always returns DD_OK
2163 *****************************************************************************/
2164 static HRESULT WINAPI ddraw7_WaitForVerticalBlank(IDirectDraw7 *iface, DWORD Flags, HANDLE event)
2166 static BOOL hide;
2168 TRACE("iface %p, flags %#lx, event %p.\n", iface, Flags, event);
2170 /* This function is called often, so print the fixme only once */
2171 if(!hide)
2173 FIXME("iface %p, flags %#lx, event %p stub!\n", iface, Flags, event);
2174 hide = TRUE;
2177 /* MSDN says DDWAITVB_BLOCKBEGINEVENT is not supported */
2178 if(Flags & DDWAITVB_BLOCKBEGINEVENT)
2179 return DDERR_UNSUPPORTED; /* unchecked */
2181 return DD_OK;
2184 static HRESULT WINAPI ddraw4_WaitForVerticalBlank(IDirectDraw4 *iface, DWORD flags, HANDLE event)
2186 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2188 TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event);
2190 return ddraw7_WaitForVerticalBlank(&ddraw->IDirectDraw7_iface, flags, event);
2193 static HRESULT WINAPI ddraw2_WaitForVerticalBlank(IDirectDraw2 *iface, DWORD flags, HANDLE event)
2195 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2197 TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event);
2199 return ddraw7_WaitForVerticalBlank(&ddraw->IDirectDraw7_iface, flags, event);
2202 static HRESULT WINAPI ddraw1_WaitForVerticalBlank(IDirectDraw *iface, DWORD flags, HANDLE event)
2204 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2206 TRACE("iface %p, flags %#lx, event %p.\n", iface, flags, event);
2208 return ddraw7_WaitForVerticalBlank(&ddraw->IDirectDraw7_iface, flags, event);
2211 static HRESULT WINAPI ddraw7_GetScanLine(IDirectDraw7 *iface, DWORD *Scanline)
2213 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2214 struct wined3d_raster_status raster_status;
2215 HRESULT hr;
2217 TRACE("iface %p, line %p.\n", iface, Scanline);
2219 wined3d_mutex_lock();
2220 hr = wined3d_output_get_raster_status(ddraw->wined3d_output, &raster_status);
2221 wined3d_mutex_unlock();
2222 if (FAILED(hr))
2224 WARN("Failed to get raster status, hr %#lx.\n", hr);
2225 return hr;
2228 *Scanline = raster_status.scan_line;
2230 if (raster_status.in_vblank)
2231 return DDERR_VERTICALBLANKINPROGRESS;
2233 return DD_OK;
2236 static HRESULT WINAPI ddraw4_GetScanLine(IDirectDraw4 *iface, DWORD *line)
2238 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2240 TRACE("iface %p, line %p.\n", iface, line);
2242 return ddraw7_GetScanLine(&ddraw->IDirectDraw7_iface, line);
2245 static HRESULT WINAPI ddraw2_GetScanLine(IDirectDraw2 *iface, DWORD *line)
2247 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2249 TRACE("iface %p, line %p.\n", iface, line);
2251 return ddraw7_GetScanLine(&ddraw->IDirectDraw7_iface, line);
2254 static HRESULT WINAPI ddraw1_GetScanLine(IDirectDraw *iface, DWORD *line)
2256 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2258 TRACE("iface %p, line %p.\n", iface, line);
2260 return ddraw7_GetScanLine(&ddraw->IDirectDraw7_iface, line);
2263 static HRESULT WINAPI ddraw7_TestCooperativeLevel(IDirectDraw7 *iface)
2265 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2267 TRACE("iface %p.\n", iface);
2269 return ddraw->device_state == DDRAW_DEVICE_STATE_LOST ? DDERR_NOEXCLUSIVEMODE : DD_OK;
2272 static HRESULT WINAPI ddraw4_TestCooperativeLevel(IDirectDraw4 *iface)
2274 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2276 TRACE("iface %p.\n", iface);
2278 return ddraw7_TestCooperativeLevel(&ddraw->IDirectDraw7_iface);
2281 /*****************************************************************************
2282 * IDirectDraw7::GetGDISurface
2284 * Returns the surface that GDI is treating as the primary surface.
2285 * For Wine this is the front buffer
2287 * Params:
2288 * GDISurface: Address to write the surface pointer to
2290 * Returns:
2291 * DD_OK if the surface was found
2292 * DDERR_NOTFOUND if the GDI surface wasn't found
2294 *****************************************************************************/
2295 static HRESULT WINAPI ddraw7_GetGDISurface(IDirectDraw7 *iface, IDirectDrawSurface7 **surface)
2297 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2298 struct ddraw_surface *ddraw_surface;
2300 TRACE("iface %p, surface %p.\n", iface, surface);
2302 wined3d_mutex_lock();
2304 if (!ddraw->gdi_surface || !(ddraw_surface = wined3d_texture_get_sub_resource_parent(ddraw->gdi_surface, 0)))
2306 WARN("GDI surface not available.\n");
2307 *surface = NULL;
2308 wined3d_mutex_unlock();
2309 return DDERR_NOTFOUND;
2311 *surface = &ddraw_surface->IDirectDrawSurface7_iface;
2312 IDirectDrawSurface7_AddRef(*surface);
2314 wined3d_mutex_unlock();
2316 return DD_OK;
2319 static HRESULT WINAPI ddraw4_GetGDISurface(IDirectDraw4 *iface, IDirectDrawSurface4 **surface)
2321 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2322 struct ddraw_surface *surface_impl;
2323 IDirectDrawSurface7 *surface7;
2324 HRESULT hr;
2326 TRACE("iface %p, surface %p.\n", iface, surface);
2328 hr = ddraw7_GetGDISurface(&ddraw->IDirectDraw7_iface, &surface7);
2329 if (FAILED(hr))
2331 *surface = NULL;
2332 return hr;
2334 surface_impl = impl_from_IDirectDrawSurface7(surface7);
2335 *surface = &surface_impl->IDirectDrawSurface4_iface;
2336 IDirectDrawSurface4_AddRef(*surface);
2337 IDirectDrawSurface7_Release(surface7);
2339 return hr;
2342 static HRESULT WINAPI ddraw2_GetGDISurface(IDirectDraw2 *iface, IDirectDrawSurface **surface)
2344 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2345 struct ddraw_surface *surface_impl;
2346 IDirectDrawSurface7 *surface7;
2347 HRESULT hr;
2349 TRACE("iface %p, surface %p.\n", iface, surface);
2351 hr = ddraw7_GetGDISurface(&ddraw->IDirectDraw7_iface, &surface7);
2352 if (FAILED(hr))
2354 *surface = NULL;
2355 return hr;
2357 surface_impl = impl_from_IDirectDrawSurface7(surface7);
2358 *surface = &surface_impl->IDirectDrawSurface_iface;
2359 IDirectDrawSurface_AddRef(*surface);
2360 IDirectDrawSurface7_Release(surface7);
2362 return hr;
2365 static HRESULT WINAPI ddraw1_GetGDISurface(IDirectDraw *iface, IDirectDrawSurface **surface)
2367 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2368 struct ddraw_surface *surface_impl;
2369 IDirectDrawSurface7 *surface7;
2370 HRESULT hr;
2372 TRACE("iface %p, surface %p.\n", iface, surface);
2374 hr = ddraw7_GetGDISurface(&ddraw->IDirectDraw7_iface, &surface7);
2375 if (FAILED(hr))
2377 *surface = NULL;
2378 return hr;
2380 surface_impl = impl_from_IDirectDrawSurface7(surface7);
2381 *surface = &surface_impl->IDirectDrawSurface_iface;
2382 IDirectDrawSurface_AddRef(*surface);
2383 IDirectDrawSurface7_Release(surface7);
2385 return hr;
2388 struct displaymodescallback_context
2390 LPDDENUMMODESCALLBACK func;
2391 void *context;
2394 static HRESULT CALLBACK EnumDisplayModesCallbackThunk(DDSURFACEDESC2 *surface_desc, void *context)
2396 struct displaymodescallback_context *cbcontext = context;
2397 DDSURFACEDESC desc;
2399 DDSD2_to_DDSD(surface_desc, &desc);
2400 return cbcontext->func(&desc, cbcontext->context);
2403 /*****************************************************************************
2404 * IDirectDraw7::EnumDisplayModes
2406 * Enumerates the supported Display modes. The modes can be filtered with
2407 * the DDSD parameter.
2409 * Params:
2410 * Flags: can be DDEDM_REFRESHRATES and DDEDM_STANDARDVGAMODES. For old ddraw
2411 * versions (3 and older?) this is reserved and must be 0.
2412 * DDSD: Surface description to filter the modes
2413 * Context: Pointer passed back to the callback function
2414 * cb: Application-provided callback function
2416 * Returns:
2417 * DD_OK on success
2418 * DDERR_INVALIDPARAMS if the callback wasn't set
2420 *****************************************************************************/
2421 static HRESULT WINAPI ddraw7_EnumDisplayModes(IDirectDraw7 *iface, DWORD Flags,
2422 DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMMODESCALLBACK2 cb)
2424 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2425 struct wined3d_display_mode *enum_modes = NULL;
2426 struct wined3d_display_mode mode;
2427 unsigned int modenum, fmt;
2428 DDSURFACEDESC2 callback_sd;
2429 unsigned enum_mode_count = 0, enum_mode_array_size = 16;
2430 DDPIXELFORMAT pixelformat;
2432 static const enum wined3d_format_id checkFormatList[] =
2434 WINED3DFMT_B8G8R8X8_UNORM,
2435 WINED3DFMT_B5G6R5_UNORM,
2436 WINED3DFMT_P8_UINT,
2439 TRACE("iface %p, flags %#lx, surface_desc %p, context %p, callback %p.\n",
2440 iface, Flags, DDSD, Context, cb);
2442 if (!cb)
2443 return DDERR_INVALIDPARAMS;
2445 if (!(enum_modes = malloc(enum_mode_array_size * sizeof(*enum_modes))))
2446 return DDERR_OUTOFMEMORY;
2448 wined3d_mutex_lock();
2450 pixelformat.dwSize = sizeof(pixelformat);
2451 for(fmt = 0; fmt < ARRAY_SIZE(checkFormatList); fmt++)
2453 modenum = 0;
2454 while (wined3d_output_get_mode(ddraw->wined3d_output, checkFormatList[fmt],
2455 WINED3D_SCANLINE_ORDERING_UNKNOWN, modenum++, &mode, false) == WINED3D_OK)
2457 BOOL found = FALSE;
2458 unsigned i;
2460 ddrawformat_from_wined3dformat(&pixelformat, mode.format_id);
2461 if (DDSD)
2463 if (DDSD->dwFlags & DDSD_WIDTH && mode.width != DDSD->dwWidth)
2464 continue;
2465 if (DDSD->dwFlags & DDSD_HEIGHT && mode.height != DDSD->dwHeight)
2466 continue;
2467 if (DDSD->dwFlags & DDSD_REFRESHRATE && mode.refresh_rate != DDSD->dwRefreshRate)
2468 continue;
2469 if (DDSD->dwFlags & DDSD_PIXELFORMAT
2470 && pixelformat.dwRGBBitCount != DDSD->ddpfPixelFormat.dwRGBBitCount)
2471 continue;
2474 /* DX docs state EnumDisplayMode should return only unique modes */
2475 for (i = 0; i < enum_mode_count; i++)
2477 if (enum_modes[i].width == mode.width && enum_modes[i].height == mode.height
2478 && enum_modes[i].format_id == mode.format_id
2479 && (enum_modes[i].refresh_rate == mode.refresh_rate || !(Flags & DDEDM_REFRESHRATES)))
2481 found = TRUE;
2482 break;
2485 if(found) continue;
2487 memset(&callback_sd, 0, sizeof(callback_sd));
2488 callback_sd.dwSize = sizeof(callback_sd);
2489 callback_sd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
2491 callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH|DDSD_REFRESHRATE;
2492 if (Flags & DDEDM_REFRESHRATES)
2493 callback_sd.dwRefreshRate = mode.refresh_rate;
2495 callback_sd.dwWidth = mode.width;
2496 callback_sd.dwHeight = mode.height;
2498 callback_sd.ddpfPixelFormat=pixelformat;
2500 /* Calc pitch and DWORD align like MSDN says */
2501 callback_sd.lPitch = (callback_sd.ddpfPixelFormat.dwRGBBitCount / 8) * mode.width;
2502 callback_sd.lPitch = (callback_sd.lPitch + 3) & ~3;
2504 TRACE("Enumerating %lux%lux%lu @%lu\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.ddpfPixelFormat.dwRGBBitCount,
2505 callback_sd.dwRefreshRate);
2507 if(cb(&callback_sd, Context) == DDENUMRET_CANCEL)
2509 TRACE("Application asked to terminate the enumeration\n");
2510 free(enum_modes);
2511 wined3d_mutex_unlock();
2512 return DD_OK;
2515 if (enum_mode_count == enum_mode_array_size)
2517 struct wined3d_display_mode *new_enum_modes;
2519 enum_mode_array_size *= 2;
2520 if (!(new_enum_modes = realloc(enum_modes, enum_mode_array_size * sizeof(*new_enum_modes))))
2522 free(enum_modes);
2523 wined3d_mutex_unlock();
2524 return DDERR_OUTOFMEMORY;
2527 enum_modes = new_enum_modes;
2529 enum_modes[enum_mode_count++] = mode;
2533 TRACE("End of enumeration\n");
2534 free(enum_modes);
2535 wined3d_mutex_unlock();
2537 return DD_OK;
2540 static HRESULT WINAPI ddraw4_EnumDisplayModes(IDirectDraw4 *iface, DWORD flags,
2541 DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMMODESCALLBACK2 callback)
2543 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2545 TRACE("iface %p, flags %#lx, surface_desc %p, context %p, callback %p.\n",
2546 iface, flags, surface_desc, context, callback);
2548 return ddraw7_EnumDisplayModes(&ddraw->IDirectDraw7_iface, flags, surface_desc, context, callback);
2551 static HRESULT WINAPI ddraw2_EnumDisplayModes(IDirectDraw2 *iface, DWORD flags,
2552 DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2554 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2555 struct displaymodescallback_context cbcontext;
2556 DDSURFACEDESC2 surface_desc2;
2558 TRACE("iface %p, flags %#lx, surface_desc %p, context %p, callback %p.\n",
2559 iface, flags, surface_desc, context, callback);
2561 cbcontext.func = callback;
2562 cbcontext.context = context;
2564 if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
2565 return ddraw7_EnumDisplayModes(&ddraw->IDirectDraw7_iface, flags,
2566 surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumDisplayModesCallbackThunk);
2569 static HRESULT WINAPI ddraw1_EnumDisplayModes(IDirectDraw *iface, DWORD flags,
2570 DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2572 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2573 struct displaymodescallback_context cbcontext;
2574 DDSURFACEDESC2 surface_desc2;
2576 TRACE("iface %p, flags %#lx, surface_desc %p, context %p, callback %p.\n",
2577 iface, flags, surface_desc, context, callback);
2579 cbcontext.func = callback;
2580 cbcontext.context = context;
2582 if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
2583 return ddraw7_EnumDisplayModes(&ddraw->IDirectDraw7_iface, flags,
2584 surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumDisplayModesCallbackThunk);
2587 /*****************************************************************************
2588 * IDirectDraw7::EvaluateMode
2590 * Used with IDirectDraw7::StartModeTest to test video modes.
2591 * EvaluateMode is used to pass or fail a mode, and continue with the next
2592 * mode
2594 * Params:
2595 * Flags: DDEM_MODEPASSED or DDEM_MODEFAILED
2596 * Timeout: Returns the amount of seconds left before the mode would have
2597 * been failed automatically
2599 * Returns:
2600 * This implementation always DD_OK, because it's a stub
2602 *****************************************************************************/
2603 static HRESULT WINAPI ddraw7_EvaluateMode(IDirectDraw7 *iface, DWORD Flags, DWORD *Timeout)
2605 FIXME("iface %p, flags %#lx, timeout %p stub!\n", iface, Flags, Timeout);
2607 /* When implementing this, implement it in WineD3D */
2609 return DD_OK;
2612 /*****************************************************************************
2613 * IDirectDraw7::GetDeviceIdentifier
2615 * Returns the device identifier, which gives information about the driver
2616 * Our device identifier is defined at the beginning of this file.
2618 * Params:
2619 * DDDI: Address for the returned structure
2620 * Flags: Can be DDGDI_GETHOSTIDENTIFIER
2622 * Returns:
2623 * On success it returns DD_OK
2624 * DDERR_INVALIDPARAMS if DDDI is NULL
2626 *****************************************************************************/
2627 static HRESULT WINAPI ddraw7_GetDeviceIdentifier(IDirectDraw7 *iface,
2628 DDDEVICEIDENTIFIER2 *DDDI, DWORD Flags)
2630 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2631 struct wined3d_adapter_identifier adapter_id;
2632 HRESULT hr = S_OK;
2634 TRACE("iface %p, device_identifier %p, flags %#lx.\n", iface, DDDI, Flags);
2636 if (!DDDI)
2637 return DDERR_INVALIDPARAMS;
2639 if (Flags & DDGDI_GETHOSTIDENTIFIER)
2641 /* The DDGDI_GETHOSTIDENTIFIER returns the information about the 2D
2642 * host adapter, if there's a secondary 3D adapter. This doesn't apply
2643 * to any modern hardware, nor is it interesting for Wine, so ignore it.
2644 * Size of DDDEVICEIDENTIFIER2 may be aligned to 8 bytes and thus 4
2645 * bytes too long. So only copy the relevant part of the structure
2648 memcpy(DDDI, &deviceidentifier, FIELD_OFFSET(DDDEVICEIDENTIFIER2, dwWHQLLevel) + sizeof(DWORD));
2649 return DD_OK;
2652 /* Drakan: Order of the Flame expects accurate D3D device information from ddraw */
2653 adapter_id.driver = DDDI->szDriver;
2654 adapter_id.driver_size = sizeof(DDDI->szDriver);
2655 adapter_id.description = DDDI->szDescription;
2656 adapter_id.description_size = sizeof(DDDI->szDescription);
2657 wined3d_mutex_lock();
2658 hr = wined3d_adapter_get_identifier(ddraw->wined3d_adapter, WINED3DENUM_WHQL_LEVEL, &adapter_id);
2659 wined3d_mutex_unlock();
2660 if (FAILED(hr)) return hr;
2662 DDDI->liDriverVersion = adapter_id.driver_version;
2663 DDDI->dwVendorId = adapter_id.vendor_id;
2664 DDDI->dwDeviceId = adapter_id.device_id;
2665 DDDI->dwSubSysId = adapter_id.subsystem_id;
2666 DDDI->dwRevision = adapter_id.revision;
2667 DDDI->guidDeviceIdentifier = adapter_id.device_identifier;
2668 DDDI->dwWHQLLevel = adapter_id.whql_level;
2669 return DD_OK;
2672 static HRESULT WINAPI ddraw4_GetDeviceIdentifier(IDirectDraw4 *iface,
2673 DDDEVICEIDENTIFIER *identifier, DWORD flags)
2675 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2676 DDDEVICEIDENTIFIER2 identifier2;
2677 HRESULT hr;
2679 TRACE("iface %p, identifier %p, flags %#lx.\n", iface, identifier, flags);
2681 hr = ddraw7_GetDeviceIdentifier(&ddraw->IDirectDraw7_iface, &identifier2, flags);
2682 DDRAW_Convert_DDDEVICEIDENTIFIER_2_To_1(&identifier2, identifier);
2684 return hr;
2687 /*****************************************************************************
2688 * IDirectDraw7::GetSurfaceFromDC
2690 * Returns the Surface for a GDI device context handle.
2691 * Is this related to IDirectDrawSurface::GetDC ???
2693 * Params:
2694 * hdc: hdc to return the surface for
2695 * Surface: Address to write the surface pointer to
2697 * Returns:
2698 * Always returns DD_OK because it's a stub
2700 *****************************************************************************/
2701 static HRESULT WINAPI ddraw7_GetSurfaceFromDC(IDirectDraw7 *iface,
2702 HDC dc, IDirectDrawSurface7 **surface)
2704 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2705 struct ddraw_surface *surface_impl;
2707 TRACE("iface %p, dc %p, surface %p.\n", iface, dc, surface);
2709 if (!surface)
2710 return E_INVALIDARG;
2712 if (!dc)
2713 goto done;
2715 wined3d_mutex_lock();
2716 LIST_FOR_EACH_ENTRY(surface_impl, &ddraw->surface_list, struct ddraw_surface, surface_list_entry)
2718 if (surface_impl->dc != dc)
2719 continue;
2721 TRACE("Found surface %p for dc %p.\n", surface_impl, dc);
2722 *surface = &surface_impl->IDirectDrawSurface7_iface;
2723 IDirectDrawSurface7_AddRef(*surface);
2724 wined3d_mutex_unlock();
2725 return DD_OK;
2727 wined3d_mutex_unlock();
2729 done:
2730 TRACE("No surface found for dc %p.\n", dc);
2731 *surface = NULL;
2732 return DDERR_NOTFOUND;
2735 static HRESULT WINAPI ddraw4_GetSurfaceFromDC(IDirectDraw4 *iface, HDC dc,
2736 IDirectDrawSurface4 **surface)
2738 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2739 struct ddraw_surface *surface_impl;
2740 IDirectDrawSurface7 *surface7;
2741 HRESULT hr;
2743 TRACE("iface %p, dc %p, surface %p.\n", iface, dc, surface);
2745 if (!surface) return E_INVALIDARG;
2747 hr = ddraw7_GetSurfaceFromDC(&ddraw->IDirectDraw7_iface, dc, &surface7);
2748 if (FAILED(hr))
2750 *surface = NULL;
2751 return hr;
2753 surface_impl = impl_from_IDirectDrawSurface7(surface7);
2754 /* Tests say this is true */
2755 *surface = (IDirectDrawSurface4 *)&surface_impl->IDirectDrawSurface_iface;
2756 IDirectDrawSurface_AddRef(&surface_impl->IDirectDrawSurface_iface);
2757 IDirectDrawSurface7_Release(surface7);
2759 return hr;
2762 static HRESULT CALLBACK restore_callback(IDirectDrawSurface7 *surface, DDSURFACEDESC2 *desc, void *context)
2764 IDirectDrawSurface_Restore(surface);
2765 IDirectDrawSurface_Release(surface);
2767 return DDENUMRET_OK;
2770 static HRESULT WINAPI ddraw7_RestoreAllSurfaces(IDirectDraw7 *iface)
2772 TRACE("iface %p.\n", iface);
2774 return IDirectDraw7_EnumSurfaces(iface, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
2775 NULL, NULL, restore_callback);
2778 static HRESULT WINAPI ddraw4_RestoreAllSurfaces(IDirectDraw4 *iface)
2780 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2782 TRACE("iface %p.\n", iface);
2784 return ddraw7_RestoreAllSurfaces(&ddraw->IDirectDraw7_iface);
2787 /*****************************************************************************
2788 * IDirectDraw7::StartModeTest
2790 * Tests the specified video modes to update the system registry with
2791 * refresh rate information. StartModeTest starts the mode test,
2792 * EvaluateMode is used to fail or pass a mode. If EvaluateMode
2793 * isn't called within 15 seconds, the mode is failed automatically
2795 * As refresh rates are handled by the X server, I don't think this
2796 * Method is important
2798 * Params:
2799 * Modes: An array of mode specifications
2800 * NumModes: The number of modes in Modes
2801 * Flags: Some flags...
2803 * Returns:
2804 * Returns DDERR_TESTFINISHED if flags contains DDSMT_ISTESTREQUIRED,
2805 * if no modes are passed, DDERR_INVALIDPARAMS is returned,
2806 * otherwise DD_OK
2808 *****************************************************************************/
2809 static HRESULT WINAPI ddraw7_StartModeTest(IDirectDraw7 *iface, SIZE *Modes, DWORD NumModes, DWORD Flags)
2811 FIXME("iface %p, modes %p, mode_count %lu, flags %#lx partial stub!\n",
2812 iface, Modes, NumModes, Flags);
2814 /* This looks sane */
2815 if( (!Modes) || (NumModes == 0) ) return DDERR_INVALIDPARAMS;
2817 /* DDSMT_ISTESTREQUIRED asks if a mode test is necessary.
2818 * As it is not, DDERR_TESTFINISHED is returned
2819 * (hopefully that's correct
2821 if(Flags & DDSMT_ISTESTREQUIRED) return DDERR_TESTFINISHED;
2822 * well, that value doesn't (yet) exist in the wine headers, so ignore it
2825 return DD_OK;
2828 static HRESULT WINAPI ddraw7_CreateSurface(IDirectDraw7 *iface, DDSURFACEDESC2 *surface_desc,
2829 IDirectDrawSurface7 **surface, IUnknown *outer_unknown)
2831 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2832 struct ddraw_surface *impl;
2833 HRESULT hr;
2835 TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
2836 iface, surface_desc, surface, outer_unknown);
2838 wined3d_mutex_lock();
2840 if (!(ddraw->cooperative_level & (DDSCL_NORMAL | DDSCL_EXCLUSIVE)))
2842 WARN("Cooperative level not set.\n");
2843 wined3d_mutex_unlock();
2844 return DDERR_NOCOOPERATIVELEVELSET;
2847 if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC2))
2849 WARN("Application supplied invalid surface descriptor\n");
2850 wined3d_mutex_unlock();
2851 return DDERR_INVALIDPARAMS;
2854 __TRY
2856 *surface = NULL;
2858 __EXCEPT_PAGE_FAULT
2860 WARN("Surface pointer %p is invalid.\n", surface);
2861 wined3d_mutex_unlock();
2862 return DDERR_INVALIDPARAMS;
2864 __ENDTRY;
2866 if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
2868 if (TRACE_ON(ddraw))
2870 TRACE(" (%p) Requesting surface desc :\n", iface);
2871 DDRAW_dump_surface_desc(surface_desc);
2874 WARN("Application tried to create an explicit front or back buffer\n");
2875 wined3d_mutex_unlock();
2876 return DDERR_INVALIDCAPS;
2879 hr = ddraw_surface_create(ddraw, surface_desc, &impl, outer_unknown, 7);
2880 wined3d_mutex_unlock();
2881 if (FAILED(hr))
2882 return hr;
2884 *surface = &impl->IDirectDrawSurface7_iface;
2885 IDirectDraw7_AddRef(iface);
2886 impl->ifaceToRelease = (IUnknown *)iface;
2888 return hr;
2891 static HRESULT WINAPI ddraw4_CreateSurface(IDirectDraw4 *iface,
2892 DDSURFACEDESC2 *surface_desc, IDirectDrawSurface4 **surface, IUnknown *outer_unknown)
2894 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2895 struct ddraw_surface *impl;
2896 HRESULT hr;
2898 TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
2899 iface, surface_desc, surface, outer_unknown);
2901 wined3d_mutex_lock();
2903 if (!(ddraw->cooperative_level & (DDSCL_NORMAL | DDSCL_EXCLUSIVE)))
2905 WARN("Cooperative level not set.\n");
2906 wined3d_mutex_unlock();
2907 return DDERR_NOCOOPERATIVELEVELSET;
2910 if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC2))
2912 WARN("Application supplied invalid surface descriptor\n");
2913 wined3d_mutex_unlock();
2914 return DDERR_INVALIDPARAMS;
2917 __TRY
2919 *surface = NULL;
2921 __EXCEPT_PAGE_FAULT
2923 WARN("Surface pointer %p is invalid.\n", surface);
2924 wined3d_mutex_unlock();
2925 return DDERR_INVALIDPARAMS;
2927 __ENDTRY;
2929 if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
2931 if (TRACE_ON(ddraw))
2933 TRACE(" (%p) Requesting surface desc :\n", iface);
2934 DDRAW_dump_surface_desc(surface_desc);
2937 WARN("Application tried to create an explicit front or back buffer\n");
2938 wined3d_mutex_unlock();
2939 return DDERR_INVALIDCAPS;
2942 hr = ddraw_surface_create(ddraw, surface_desc, &impl, outer_unknown, 4);
2943 wined3d_mutex_unlock();
2944 if (FAILED(hr))
2945 return hr;
2947 *surface = &impl->IDirectDrawSurface4_iface;
2948 IDirectDraw4_AddRef(iface);
2949 impl->ifaceToRelease = (IUnknown *)iface;
2951 return hr;
2954 static HRESULT WINAPI ddraw2_CreateSurface(IDirectDraw2 *iface,
2955 DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
2957 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2958 struct ddraw_surface *impl;
2959 HRESULT hr;
2960 DDSURFACEDESC2 surface_desc2;
2962 TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
2963 iface, surface_desc, surface, outer_unknown);
2965 wined3d_mutex_lock();
2967 if (!(ddraw->cooperative_level & (DDSCL_NORMAL | DDSCL_EXCLUSIVE)))
2969 WARN("Cooperative level not set.\n");
2970 wined3d_mutex_unlock();
2971 return DDERR_NOCOOPERATIVELEVELSET;
2974 if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC))
2976 WARN("Application supplied invalid surface descriptor\n");
2977 wined3d_mutex_unlock();
2978 return DDERR_INVALIDPARAMS;
2981 __TRY
2983 *surface = NULL;
2985 __EXCEPT_PAGE_FAULT
2987 WARN("Surface pointer %p is invalid.\n", surface);
2988 wined3d_mutex_unlock();
2989 return DDERR_INVALIDPARAMS;
2991 __ENDTRY;
2993 DDSD_to_DDSD2(surface_desc, &surface_desc2);
2994 if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
2996 if (TRACE_ON(ddraw))
2998 TRACE(" (%p) Requesting surface desc :\n", iface);
2999 DDRAW_dump_surface_desc((DDSURFACEDESC2 *)surface_desc);
3002 WARN("Application tried to create an explicit front or back buffer\n");
3003 wined3d_mutex_unlock();
3004 return DDERR_INVALIDCAPS;
3007 hr = ddraw_surface_create(ddraw, &surface_desc2, &impl, outer_unknown, 2);
3008 wined3d_mutex_unlock();
3009 if (FAILED(hr))
3010 return hr;
3012 *surface = &impl->IDirectDrawSurface_iface;
3013 impl->ifaceToRelease = NULL;
3015 return hr;
3018 static HRESULT WINAPI ddraw1_CreateSurface(IDirectDraw *iface,
3019 DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
3021 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3022 struct ddraw_surface *impl;
3023 HRESULT hr;
3024 DDSURFACEDESC2 surface_desc2;
3026 TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3027 iface, surface_desc, surface, outer_unknown);
3029 wined3d_mutex_lock();
3031 if (!(ddraw->cooperative_level & (DDSCL_NORMAL | DDSCL_EXCLUSIVE)))
3033 WARN("Cooperative level not set.\n");
3034 wined3d_mutex_unlock();
3035 return DDERR_NOCOOPERATIVELEVELSET;
3038 if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC))
3040 WARN("Application supplied invalid surface descriptor\n");
3041 wined3d_mutex_unlock();
3042 return DDERR_INVALIDPARAMS;
3045 __TRY
3047 *surface = NULL;
3049 __EXCEPT_PAGE_FAULT
3051 WARN("Surface pointer %p is invalid.\n", surface);
3052 wined3d_mutex_unlock();
3053 return DDERR_INVALIDPARAMS;
3055 __ENDTRY;
3057 if ((surface_desc->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER))
3058 == (DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER)
3059 || (surface_desc->ddsCaps.dwCaps & (DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER))
3060 == ((DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER)))
3062 WARN("Application tried to create an explicit front or back buffer.\n");
3063 wined3d_mutex_unlock();
3064 return DDERR_INVALIDCAPS;
3067 DDSD_to_DDSD2(surface_desc, &surface_desc2);
3068 hr = ddraw_surface_create(ddraw, &surface_desc2, &impl, outer_unknown, 1);
3069 wined3d_mutex_unlock();
3070 if (FAILED(hr))
3071 return hr;
3073 *surface = &impl->IDirectDrawSurface_iface;
3074 impl->ifaceToRelease = NULL;
3076 return hr;
3079 static BOOL
3080 Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
3081 const DDPIXELFORMAT *provided)
3083 /* Some flags must be present in both or neither for a match. */
3084 static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
3085 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
3086 | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
3088 if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
3089 return FALSE;
3091 if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
3092 return FALSE;
3094 if (requested->dwFlags & DDPF_FOURCC)
3095 if (requested->dwFourCC != provided->dwFourCC)
3096 return FALSE;
3098 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
3099 |DDPF_LUMINANCE|DDPF_BUMPDUDV))
3100 if (requested->dwRGBBitCount != provided->dwRGBBitCount)
3101 return FALSE;
3103 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
3104 |DDPF_LUMINANCE|DDPF_BUMPDUDV))
3105 if (requested->dwRBitMask != provided->dwRBitMask)
3106 return FALSE;
3108 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
3109 if (requested->dwGBitMask != provided->dwGBitMask)
3110 return FALSE;
3112 /* I could be wrong about the bumpmapping. MSDN docs are vague. */
3113 if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
3114 |DDPF_BUMPDUDV))
3115 if (requested->dwBBitMask != provided->dwBBitMask)
3116 return FALSE;
3118 if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
3119 if (requested->dwRGBAlphaBitMask != provided->dwRGBAlphaBitMask)
3120 return FALSE;
3122 return TRUE;
3125 static BOOL ddraw_match_surface_desc(const DDSURFACEDESC2 *requested, const DDSURFACEDESC2 *provided)
3127 struct compare_info
3129 DWORD flag;
3130 ptrdiff_t offset;
3131 size_t size;
3134 #define CMP(FLAG, FIELD) \
3135 { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
3136 sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
3138 static const struct compare_info compare[] =
3140 CMP(ALPHABITDEPTH, dwAlphaBitDepth),
3141 CMP(BACKBUFFERCOUNT, dwBackBufferCount),
3142 CMP(CAPS, ddsCaps),
3143 CMP(CKDESTBLT, ddckCKDestBlt),
3144 CMP(CKDESTOVERLAY, ddckCKDestOverlay),
3145 CMP(CKSRCBLT, ddckCKSrcBlt),
3146 CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
3147 CMP(HEIGHT, dwHeight),
3148 CMP(LINEARSIZE, dwLinearSize),
3149 CMP(LPSURFACE, lpSurface),
3150 CMP(MIPMAPCOUNT, dwMipMapCount),
3151 CMP(PITCH, lPitch),
3152 /* PIXELFORMAT: manual */
3153 CMP(REFRESHRATE, dwRefreshRate),
3154 CMP(TEXTURESTAGE, dwTextureStage),
3155 CMP(WIDTH, dwWidth),
3156 /* ZBUFFERBITDEPTH: "obsolete" */
3159 #undef CMP
3161 unsigned int i;
3163 if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
3164 return FALSE;
3166 for (i=0; i < ARRAY_SIZE(compare); i++)
3168 if (requested->dwFlags & compare[i].flag
3169 && memcmp((const char *)provided + compare[i].offset,
3170 (const char *)requested + compare[i].offset,
3171 compare[i].size) != 0)
3172 return FALSE;
3175 if (requested->dwFlags & DDSD_PIXELFORMAT)
3177 if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->ddpfPixelFormat,
3178 &provided->ddpfPixelFormat))
3179 return FALSE;
3182 return TRUE;
3185 struct surfacescallback2_context
3187 LPDDENUMSURFACESCALLBACK2 func;
3188 void *context;
3191 struct surfacescallback_context
3193 LPDDENUMSURFACESCALLBACK func;
3194 void *context;
3197 static HRESULT CALLBACK EnumSurfacesCallback2Thunk(IDirectDrawSurface7 *surface,
3198 DDSURFACEDESC2 *surface_desc, void *context)
3200 struct ddraw_surface *surface_impl = impl_from_IDirectDrawSurface7(surface);
3201 struct surfacescallback2_context *cbcontext = context;
3203 if (!surface)
3204 return cbcontext->func(NULL, surface_desc, cbcontext->context);
3206 IDirectDrawSurface4_AddRef(&surface_impl->IDirectDrawSurface4_iface);
3207 IDirectDrawSurface7_Release(surface);
3209 return cbcontext->func(&surface_impl->IDirectDrawSurface4_iface,
3210 surface_desc, cbcontext->context);
3213 static HRESULT CALLBACK EnumSurfacesCallbackThunk(IDirectDrawSurface7 *surface,
3214 DDSURFACEDESC2 *surface_desc, void *context)
3216 struct ddraw_surface *surface_impl = impl_from_IDirectDrawSurface7(surface);
3217 struct surfacescallback_context *cbcontext = context;
3219 if (!surface)
3220 return cbcontext->func(NULL, (DDSURFACEDESC *)surface_desc, cbcontext->context);
3222 IDirectDrawSurface_AddRef(&surface_impl->IDirectDrawSurface_iface);
3223 IDirectDrawSurface7_Release(surface);
3225 return cbcontext->func(&surface_impl->IDirectDrawSurface_iface,
3226 (DDSURFACEDESC *)surface_desc, cbcontext->context);
3229 struct enum_surface_mode_params
3231 IDirectDraw7 *ddraw;
3232 const DDSURFACEDESC2 *desc;
3233 LPDDENUMSURFACESCALLBACK7 callback;
3234 void *context;
3237 static HRESULT CALLBACK enum_surface_mode_callback(DDSURFACEDESC2 *surface_desc, void *context)
3239 const struct enum_surface_mode_params *params = context;
3240 DDSURFACEDESC2 desc = *params->desc;
3241 IDirectDrawSurface7 *surface;
3243 desc.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_PIXELFORMAT;
3244 desc.dwWidth = surface_desc->dwWidth;
3245 desc.dwHeight = surface_desc->dwHeight;
3246 desc.lPitch = surface_desc->lPitch;
3247 desc.ddpfPixelFormat = surface_desc->ddpfPixelFormat;
3249 if (SUCCEEDED(ddraw7_CreateSurface(params->ddraw, &desc, &surface, NULL)))
3251 IDirectDrawSurface7_Release(surface);
3252 return params->callback(NULL, &desc, params->context);
3254 return DDENUMRET_OK;
3257 /*****************************************************************************
3258 * IDirectDraw7::EnumSurfaces
3260 * Loops through all surfaces attached to this device and calls the
3261 * application callback. This can't be relayed to WineD3DDevice,
3262 * because some WineD3DSurfaces' parents are IParent objects
3264 * Params:
3265 * Flags: Some filtering flags. See IDirectDrawImpl_EnumSurfacesCallback
3266 * DDSD: Description to filter for
3267 * Context: Application-provided pointer, it's passed unmodified to the
3268 * Callback function
3269 * Callback: Address to call for each surface
3271 * Returns:
3272 * DDERR_INVALIDPARAMS if the callback is NULL
3273 * DD_OK on success
3275 *****************************************************************************/
3276 static HRESULT WINAPI ddraw7_EnumSurfaces(IDirectDraw7 *iface, DWORD flags,
3277 DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMSURFACESCALLBACK7 callback)
3279 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
3280 HRESULT hr = DD_OK;
3282 TRACE("iface %p, flags %#lx, surface_desc %p, context %p, callback %p.\n",
3283 iface, flags, surface_desc, context, callback);
3285 if (!callback)
3286 return DDERR_INVALIDPARAMS;
3288 if (flags & DDENUMSURFACES_CANBECREATED)
3290 IDirectDrawSurface7 *surface;
3292 if ((flags & (DDENUMSURFACES_ALL | DDENUMSURFACES_MATCH | DDENUMSURFACES_NOMATCH)) != DDENUMSURFACES_MATCH)
3293 return DDERR_INVALIDPARAMS;
3295 wined3d_mutex_lock();
3297 if (surface_desc->dwFlags & (DDSD_WIDTH | DDSD_HEIGHT))
3299 if (SUCCEEDED(ddraw7_CreateSurface(iface, surface_desc, &surface, NULL)))
3301 struct ddraw_surface *surface_impl = impl_from_IDirectDrawSurface7(surface);
3302 callback(NULL, &surface_impl->surface_desc, context);
3303 IDirectDrawSurface7_Release(surface);
3306 else
3308 DDSURFACEDESC2 desc =
3310 .dwSize = sizeof(desc),
3311 .dwFlags = DDSD_PIXELFORMAT,
3312 .ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT),
3314 struct enum_surface_mode_params params =
3316 .ddraw = iface,
3317 .desc = surface_desc,
3318 .callback = callback,
3319 .context = context,
3321 struct wined3d_display_mode mode;
3323 if (FAILED(hr = wined3d_output_get_display_mode(ddraw->wined3d_output, &mode, NULL)))
3325 ERR("Failed to get display mode, hr %#lx.\n", hr);
3326 wined3d_mutex_unlock();
3327 return hr_ddraw_from_wined3d(hr);
3330 ddrawformat_from_wined3dformat(&desc.ddpfPixelFormat, mode.format_id);
3331 hr = ddraw7_EnumDisplayModes(iface, 0, &desc, &params, enum_surface_mode_callback);
3334 wined3d_mutex_unlock();
3336 else if (flags & DDENUMSURFACES_DOESEXIST)
3338 struct ddraw_surface *surface, *cursor;
3339 BOOL nomatch = !!(flags & DDENUMSURFACES_NOMATCH);
3341 wined3d_mutex_lock();
3343 /* Use the safe enumeration, as the callback may destroy surfaces. */
3344 LIST_FOR_EACH_ENTRY_SAFE(surface, cursor, &ddraw->surface_list, struct ddraw_surface, surface_list_entry)
3346 if (!surface->iface_count)
3348 WARN("Not enumerating surface %p because it doesn't have any references.\n", surface);
3349 continue;
3352 if ((flags & DDENUMSURFACES_ALL)
3353 || nomatch != ddraw_match_surface_desc(surface_desc, &surface->surface_desc))
3355 DDSURFACEDESC2 desc = surface->surface_desc;
3357 TRACE("Enumerating surface %p.\n", surface);
3358 IDirectDrawSurface7_AddRef(&surface->IDirectDrawSurface7_iface);
3359 if (callback(&surface->IDirectDrawSurface7_iface, &desc, context) != DDENUMRET_OK)
3360 break;
3364 wined3d_mutex_unlock();
3366 else
3368 return DDERR_INVALIDPARAMS;
3371 return hr;
3374 static HRESULT WINAPI ddraw4_EnumSurfaces(IDirectDraw4 *iface, DWORD flags,
3375 DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMSURFACESCALLBACK2 callback)
3377 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
3378 struct surfacescallback2_context cbcontext;
3380 TRACE("iface %p, flags %#lx, surface_desc %p, context %p, callback %p.\n",
3381 iface, flags, surface_desc, context, callback);
3383 cbcontext.func = callback;
3384 cbcontext.context = context;
3386 return ddraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, flags, surface_desc,
3387 &cbcontext, EnumSurfacesCallback2Thunk);
3390 static HRESULT WINAPI ddraw2_EnumSurfaces(IDirectDraw2 *iface, DWORD flags,
3391 DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3393 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
3394 struct surfacescallback_context cbcontext;
3395 DDSURFACEDESC2 surface_desc2;
3397 TRACE("iface %p, flags %#lx, surface_desc %p, context %p, callback %p.\n",
3398 iface, flags, surface_desc, context, callback);
3400 cbcontext.func = callback;
3401 cbcontext.context = context;
3403 if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
3404 return ddraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, flags,
3405 surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumSurfacesCallbackThunk);
3408 static HRESULT WINAPI ddraw1_EnumSurfaces(IDirectDraw *iface, DWORD flags,
3409 DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3411 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3412 struct surfacescallback_context cbcontext;
3413 DDSURFACEDESC2 surface_desc2;
3415 TRACE("iface %p, flags %#lx, surface_desc %p, context %p, callback %p.\n",
3416 iface, flags, surface_desc, context, callback);
3418 cbcontext.func = callback;
3419 cbcontext.context = context;
3421 if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
3422 return ddraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, flags,
3423 surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumSurfacesCallbackThunk);
3426 /*****************************************************************************
3427 * DirectDrawCreateClipper (DDRAW.@)
3429 * Creates a new IDirectDrawClipper object.
3431 * Params:
3432 * Clipper: Address to write the interface pointer to
3433 * UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3434 * NULL
3436 * Returns:
3437 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
3438 * E_OUTOFMEMORY if allocating the object failed
3440 *****************************************************************************/
3441 HRESULT WINAPI DirectDrawCreateClipper(DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3443 struct ddraw_clipper *object;
3444 HRESULT hr;
3446 TRACE("flags %#lx, clipper %p, outer_unknown %p.\n",
3447 flags, clipper, outer_unknown);
3449 if (outer_unknown)
3450 return CLASS_E_NOAGGREGATION;
3452 wined3d_mutex_lock();
3454 if (!(object = calloc(1, sizeof(*object))))
3456 wined3d_mutex_unlock();
3457 return E_OUTOFMEMORY;
3460 hr = ddraw_clipper_init(object);
3461 if (FAILED(hr))
3463 WARN("Failed to initialize clipper, hr %#lx.\n", hr);
3464 free(object);
3465 wined3d_mutex_unlock();
3466 return hr;
3469 TRACE("Created clipper %p.\n", object);
3470 *clipper = &object->IDirectDrawClipper_iface;
3471 wined3d_mutex_unlock();
3473 return DD_OK;
3476 /*****************************************************************************
3477 * IDirectDraw7::CreateClipper
3479 * Creates a DDraw clipper. See DirectDrawCreateClipper for details
3481 *****************************************************************************/
3482 static HRESULT WINAPI ddraw7_CreateClipper(IDirectDraw7 *iface, DWORD Flags,
3483 IDirectDrawClipper **Clipper, IUnknown *UnkOuter)
3485 TRACE("iface %p, flags %#lx, clipper %p, outer_unknown %p.\n",
3486 iface, Flags, Clipper, UnkOuter);
3488 return DirectDrawCreateClipper(Flags, Clipper, UnkOuter);
3491 static HRESULT WINAPI ddraw4_CreateClipper(IDirectDraw4 *iface, DWORD flags,
3492 IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3494 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
3496 TRACE("iface %p, flags %#lx, clipper %p, outer_unknown %p.\n",
3497 iface, flags, clipper, outer_unknown);
3499 return ddraw7_CreateClipper(&ddraw->IDirectDraw7_iface, flags, clipper, outer_unknown);
3502 static HRESULT WINAPI ddraw2_CreateClipper(IDirectDraw2 *iface,
3503 DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3505 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
3507 TRACE("iface %p, flags %#lx, clipper %p, outer_unknown %p.\n",
3508 iface, flags, clipper, outer_unknown);
3510 return ddraw7_CreateClipper(&ddraw->IDirectDraw7_iface, flags, clipper, outer_unknown);
3513 static HRESULT WINAPI ddraw1_CreateClipper(IDirectDraw *iface,
3514 DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3516 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3518 TRACE("iface %p, flags %#lx, clipper %p, outer_unknown %p.\n",
3519 iface, flags, clipper, outer_unknown);
3521 return ddraw7_CreateClipper(&ddraw->IDirectDraw7_iface, flags, clipper, outer_unknown);
3524 /*****************************************************************************
3525 * IDirectDraw7::CreatePalette
3527 * Creates a new IDirectDrawPalette object
3529 * Params:
3530 * Flags: The flags for the new clipper
3531 * ColorTable: Color table to assign to the new clipper
3532 * Palette: Address to write the interface pointer to
3533 * UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3534 * NULL
3536 * Returns:
3537 * CLASS_E_NOAGGREGATION if UnkOuter != NULL
3538 * E_OUTOFMEMORY if allocating the object failed
3540 *****************************************************************************/
3541 static HRESULT WINAPI ddraw7_CreatePalette(IDirectDraw7 *iface, DWORD Flags,
3542 PALETTEENTRY *ColorTable, IDirectDrawPalette **Palette, IUnknown *pUnkOuter)
3544 struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
3545 struct ddraw_palette *object;
3546 HRESULT hr;
3548 TRACE("iface %p, flags %#lx, color_table %p, palette %p, outer_unknown %p.\n",
3549 iface, Flags, ColorTable, Palette, pUnkOuter);
3551 if (pUnkOuter)
3552 return CLASS_E_NOAGGREGATION;
3554 wined3d_mutex_lock();
3556 /* The refcount test shows that a cooplevel is required for this */
3557 if (!ddraw->cooperative_level)
3559 WARN("No cooperative level set, returning DDERR_NOCOOPERATIVELEVELSET\n");
3560 wined3d_mutex_unlock();
3561 return DDERR_NOCOOPERATIVELEVELSET;
3564 if (!(object = malloc(sizeof(*object))))
3566 ERR("Out of memory when allocating memory for a palette implementation\n");
3567 wined3d_mutex_unlock();
3568 return E_OUTOFMEMORY;
3571 hr = ddraw_palette_init(object, ddraw, Flags, ColorTable);
3572 if (FAILED(hr))
3574 WARN("Failed to initialize palette, hr %#lx.\n", hr);
3575 free(object);
3576 wined3d_mutex_unlock();
3577 return hr;
3580 TRACE("Created palette %p.\n", object);
3581 *Palette = &object->IDirectDrawPalette_iface;
3582 wined3d_mutex_unlock();
3584 return DD_OK;
3587 static HRESULT WINAPI ddraw4_CreatePalette(IDirectDraw4 *iface, DWORD flags, PALETTEENTRY *entries,
3588 IDirectDrawPalette **palette, IUnknown *outer_unknown)
3590 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
3591 HRESULT hr;
3593 TRACE("iface %p, flags %#lx, entries %p, palette %p, outer_unknown %p.\n",
3594 iface, flags, entries, palette, outer_unknown);
3596 hr = ddraw7_CreatePalette(&ddraw->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3597 if (SUCCEEDED(hr) && *palette)
3599 struct ddraw_palette *impl = impl_from_IDirectDrawPalette(*palette);
3600 IDirectDraw7_Release(&ddraw->IDirectDraw7_iface);
3601 IDirectDraw4_AddRef(iface);
3602 impl->ifaceToRelease = (IUnknown *)iface;
3604 return hr;
3607 static HRESULT WINAPI ddraw2_CreatePalette(IDirectDraw2 *iface, DWORD flags,
3608 PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3610 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
3611 HRESULT hr;
3613 TRACE("iface %p, flags %#lx, entries %p, palette %p, outer_unknown %p.\n",
3614 iface, flags, entries, palette, outer_unknown);
3616 hr = ddraw7_CreatePalette(&ddraw->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3617 if (SUCCEEDED(hr) && *palette)
3619 struct ddraw_palette *impl = impl_from_IDirectDrawPalette(*palette);
3620 IDirectDraw7_Release(&ddraw->IDirectDraw7_iface);
3621 impl->ifaceToRelease = NULL;
3624 return hr;
3627 static HRESULT WINAPI ddraw1_CreatePalette(IDirectDraw *iface, DWORD flags,
3628 PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3630 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3631 HRESULT hr;
3633 TRACE("iface %p, flags %#lx, entries %p, palette %p, outer_unknown %p.\n",
3634 iface, flags, entries, palette, outer_unknown);
3636 hr = ddraw7_CreatePalette(&ddraw->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3637 if (SUCCEEDED(hr) && *palette)
3639 struct ddraw_palette *impl = impl_from_IDirectDrawPalette(*palette);
3640 IDirectDraw7_Release(&ddraw->IDirectDraw7_iface);
3641 impl->ifaceToRelease = NULL;
3644 return hr;
3647 /*****************************************************************************
3648 * IDirectDraw7::DuplicateSurface
3650 * Duplicates a surface. The surface memory points to the same memory as
3651 * the original surface, and it's released when the last surface referencing
3652 * it is released. I guess that's beyond Wine's surface management right now
3653 * (Idea: create a new DDraw surface with the same WineD3DSurface. I need a
3654 * test application to implement this)
3656 * Params:
3657 * Src: Address of the source surface
3658 * Dest: Address to write the new surface pointer to
3660 * Returns:
3661 * See IDirectDraw7::CreateSurface
3663 *****************************************************************************/
3664 static HRESULT WINAPI ddraw7_DuplicateSurface(IDirectDraw7 *iface,
3665 IDirectDrawSurface7 *Src, IDirectDrawSurface7 **Dest)
3667 struct ddraw_surface *src_surface = unsafe_impl_from_IDirectDrawSurface7(Src);
3669 FIXME("iface %p, src %p, dst %p partial stub!\n", iface, Src, Dest);
3671 /* For now, simply create a new, independent surface */
3672 return IDirectDraw7_CreateSurface(iface, &src_surface->surface_desc, Dest, NULL);
3675 static HRESULT WINAPI ddraw4_DuplicateSurface(IDirectDraw4 *iface, IDirectDrawSurface4 *src,
3676 IDirectDrawSurface4 **dst)
3678 struct ddraw_surface *src_impl = unsafe_impl_from_IDirectDrawSurface4(src);
3679 struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
3680 struct ddraw_surface *dst_impl;
3681 IDirectDrawSurface7 *dst7;
3682 HRESULT hr;
3684 TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3686 hr = ddraw7_DuplicateSurface(&ddraw->IDirectDraw7_iface,
3687 src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3688 if (FAILED(hr))
3690 *dst = NULL;
3691 return hr;
3693 dst_impl = impl_from_IDirectDrawSurface7(dst7);
3694 *dst = &dst_impl->IDirectDrawSurface4_iface;
3695 IDirectDrawSurface4_AddRef(*dst);
3696 IDirectDrawSurface7_Release(dst7);
3698 return hr;
3701 static HRESULT WINAPI ddraw2_DuplicateSurface(IDirectDraw2 *iface,
3702 IDirectDrawSurface *src, IDirectDrawSurface **dst)
3704 struct ddraw_surface *src_impl = unsafe_impl_from_IDirectDrawSurface(src);
3705 struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
3706 struct ddraw_surface *dst_impl;
3707 IDirectDrawSurface7 *dst7;
3708 HRESULT hr;
3710 TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3712 hr = ddraw7_DuplicateSurface(&ddraw->IDirectDraw7_iface,
3713 src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3714 if (FAILED(hr))
3715 return hr;
3716 dst_impl = impl_from_IDirectDrawSurface7(dst7);
3717 *dst = &dst_impl->IDirectDrawSurface_iface;
3718 IDirectDrawSurface_AddRef(*dst);
3719 IDirectDrawSurface7_Release(dst7);
3721 return hr;
3724 static HRESULT WINAPI ddraw1_DuplicateSurface(IDirectDraw *iface, IDirectDrawSurface *src,
3725 IDirectDrawSurface **dst)
3727 struct ddraw_surface *src_impl = unsafe_impl_from_IDirectDrawSurface(src);
3728 struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3729 struct ddraw_surface *dst_impl;
3730 IDirectDrawSurface7 *dst7;
3731 HRESULT hr;
3733 TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3735 hr = ddraw7_DuplicateSurface(&ddraw->IDirectDraw7_iface,
3736 src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3737 if (FAILED(hr))
3738 return hr;
3739 dst_impl = impl_from_IDirectDrawSurface7(dst7);
3740 *dst = &dst_impl->IDirectDrawSurface_iface;
3741 IDirectDrawSurface_AddRef(*dst);
3742 IDirectDrawSurface7_Release(dst7);
3744 return hr;
3747 /*****************************************************************************
3748 * IDirect3D7::EnumDevices
3750 * The EnumDevices method for IDirect3D7. It enumerates all supported
3751 * D3D7 devices. Currently the T&L, HAL and RGB devices are enumerated.
3753 * Params:
3754 * callback: Function to call for each enumerated device
3755 * context: Pointer to pass back to the app
3757 * Returns:
3758 * D3D_OK, or the return value of the GetCaps call
3760 *****************************************************************************/
3761 static HRESULT WINAPI d3d7_EnumDevices(IDirect3D7 *iface, LPD3DENUMDEVICESCALLBACK7 callback, void *context)
3763 struct ddraw *ddraw = impl_from_IDirect3D7(iface);
3764 D3DDEVICEDESC7 device_desc7;
3765 DWORD dev_caps;
3766 HRESULT hr;
3767 size_t i;
3769 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3771 if (!callback)
3772 return DDERR_INVALIDPARAMS;
3774 wined3d_mutex_lock();
3776 if (FAILED(hr = ddraw_get_d3dcaps(ddraw, &device_desc7)))
3778 wined3d_mutex_unlock();
3779 return hr;
3781 dev_caps = device_desc7.dwDevCaps;
3783 for (i = 0; i < ARRAY_SIZE(device_list7); i++)
3785 HRESULT ret;
3787 device_desc7.deviceGUID = *device_list7[i].device_guid;
3788 device_desc7.dwDevCaps = dev_caps & ~device_list7[i].unsupported_caps;
3789 ret = callback(device_list7[i].interface_name, device_list7[i].device_name, &device_desc7, context);
3790 if (ret != DDENUMRET_OK)
3792 TRACE("Application cancelled the enumeration.\n");
3793 wined3d_mutex_unlock();
3794 return D3D_OK;
3798 TRACE("End of enumeration.\n");
3800 wined3d_mutex_unlock();
3802 return D3D_OK;
3805 /*****************************************************************************
3806 * IDirect3D3::EnumDevices
3808 * Enumerates all supported Direct3DDevice interfaces. This is the
3809 * implementation for Direct3D 1 to Direc3D 3, Version 7 has its own.
3811 * Versions 1, 2 and 3
3813 * Params:
3814 * callback: Application-provided routine to call for each enumerated device
3815 * Context: Pointer to pass to the callback
3817 * Returns:
3818 * D3D_OK on success,
3819 * The result of IDirect3DImpl_GetCaps if it failed
3821 *****************************************************************************/
3822 static HRESULT WINAPI d3d3_EnumDevices(IDirect3D3 *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3824 static CHAR wined3d_description[] = "Wine D3DDevice using WineD3D and OpenGL";
3826 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
3827 D3DDEVICEDESC device_desc1, hal_desc, hel_desc;
3828 D3DDEVICEDESC7 device_desc7;
3829 HRESULT hr;
3831 /* Some games (Motoracer 2 demo) have the bad idea to modify the device
3832 * name string. Let's put the string in a sufficiently sized array in
3833 * writable memory. */
3834 char device_name[50];
3835 strcpy(device_name,"Direct3D HEL");
3837 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3839 if (!callback)
3840 return DDERR_INVALIDPARAMS;
3842 wined3d_mutex_lock();
3844 if (FAILED(hr = ddraw_get_d3dcaps(ddraw, &device_desc7)))
3846 wined3d_mutex_unlock();
3847 return hr;
3849 ddraw_d3dcaps1_from_7(&device_desc1, &device_desc7);
3851 /* Do I have to enumerate the reference id? Note from old d3d7:
3852 * "It seems that enumerating the reference IID on Direct3D 1 games
3853 * (AvP / Motoracer2) breaks them". So do not enumerate this iid in V1
3855 * There's a registry key HKLM\Software\Microsoft\Direct3D\Drivers,
3856 * EnumReference which enables / disables enumerating the reference
3857 * rasterizer. It's a DWORD, 0 means disabled, 2 means enabled. The
3858 * enablerefrast.reg and disablerefrast.reg files in the DirectX 7.0 sdk
3859 * demo directory suggest this.
3861 * Some games(GTA 2) seem to use the second enumerated device, so I have
3862 * to enumerate at least 2 devices. So enumerate the reference device to
3863 * have 2 devices.
3865 * Other games (Rollcage) tell emulation and hal device apart by certain
3866 * flags. Rollcage expects D3DPTEXTURECAPS_POW2 to be set (yeah, it is a
3867 * limitation flag), and it refuses all devices that have the perspective
3868 * flag set. This way it refuses the emulation device, and HAL devices
3869 * never have POW2 unset in d3d7 on windows. */
3870 if (ddraw->d3dversion != 1)
3872 /* Tomb Raider 3 overwrites the reference device description buffer
3873 * with its own custom string. Reserve some extra space in the array
3874 * to avoid a buffer overrun. */
3875 static CHAR reference_description[64] = "RGB Direct3D emulation";
3877 TRACE("Enumerating WineD3D D3DDevice interface.\n");
3878 hal_desc = device_desc1;
3879 hel_desc = device_desc1;
3880 /* The rgb device has the pow2 flag set in the hel caps, but not in the hal caps. */
3881 hal_desc.dpcLineCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3882 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3883 hal_desc.dpcTriCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3884 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3885 /* RGB, RAMP and MMX devices have a HAL dcmColorModel of 0 */
3886 hal_desc.dcmColorModel = 0;
3887 /* RGB, RAMP and MMX devices cannot report HAL hardware flags */
3888 hal_desc.dwFlags = 0;
3889 /* RGB, REF, RAMP and MMX devices don't report hardware transform and lighting capability */
3890 hal_desc.dwDevCaps &= ~(D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX | D3DDEVCAPS_HWRASTERIZATION);
3891 hel_desc.dwDevCaps &= ~(D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX | D3DDEVCAPS_HWRASTERIZATION);
3893 hr = callback((GUID *)&IID_IDirect3DRGBDevice, reference_description,
3894 device_name, &hal_desc, &hel_desc, context);
3895 if (hr != D3DENUMRET_OK)
3897 TRACE("Application cancelled the enumeration.\n");
3898 wined3d_mutex_unlock();
3899 return D3D_OK;
3903 strcpy(device_name,"Direct3D HAL");
3905 TRACE("Enumerating HAL Direct3D device.\n");
3906 hal_desc = device_desc1;
3907 hel_desc = device_desc1;
3909 /* The hal device does not have the pow2 flag set in hel, but in hal. */
3910 hel_desc.dpcLineCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3911 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3912 hel_desc.dpcTriCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3913 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3914 /* HAL devices have a HEL dcmColorModel of 0 */
3915 hel_desc.dcmColorModel = 0;
3916 /* HAL devices report hardware transform and lighting capability, but not in hel */
3917 hel_desc.dwDevCaps &= ~(D3DDEVCAPS_HWTRANSFORMANDLIGHT | D3DDEVCAPS_DRAWPRIMITIVES2EX);
3919 hr = callback((GUID *)&IID_IDirect3DHALDevice, wined3d_description,
3920 device_name, &hal_desc, &hel_desc, context);
3921 if (hr != D3DENUMRET_OK)
3923 TRACE("Application cancelled the enumeration.\n");
3924 wined3d_mutex_unlock();
3925 return D3D_OK;
3928 TRACE("End of enumeration.\n");
3930 wined3d_mutex_unlock();
3932 return D3D_OK;
3935 static HRESULT WINAPI d3d2_EnumDevices(IDirect3D2 *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3937 struct ddraw *ddraw = impl_from_IDirect3D2(iface);
3939 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3941 return d3d3_EnumDevices(&ddraw->IDirect3D3_iface, callback, context);
3944 static HRESULT WINAPI d3d1_EnumDevices(IDirect3D *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3946 struct ddraw *ddraw = impl_from_IDirect3D(iface);
3948 TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3950 return d3d3_EnumDevices(&ddraw->IDirect3D3_iface, callback, context);
3953 /*****************************************************************************
3954 * IDirect3D3::CreateLight
3956 * Creates an IDirect3DLight interface. This interface is used in
3957 * Direct3D3 or earlier for lighting. In Direct3D7 it has been replaced
3958 * by the DIRECT3DLIGHT7 structure. Wine's Direct3DLight implementation
3959 * uses the IDirect3DDevice7 interface with D3D7 lights.
3961 * Versions 1, 2 and 3
3963 * Params:
3964 * light: Address to store the new interface pointer
3965 * outer_unknown: Basically for aggregation, but ddraw doesn't support it.
3966 * Must be NULL
3968 * Returns:
3969 * D3D_OK on success
3970 * DDERR_OUTOFMEMORY if memory allocation failed
3971 * CLASS_E_NOAGGREGATION if outer_unknown != NULL
3973 *****************************************************************************/
3974 static HRESULT WINAPI d3d3_CreateLight(IDirect3D3 *iface, IDirect3DLight **light,
3975 IUnknown *outer_unknown)
3977 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
3978 struct d3d_light *object;
3980 TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
3982 if (outer_unknown)
3983 return CLASS_E_NOAGGREGATION;
3985 if (!(object = calloc(1, sizeof(*object))))
3987 ERR("Failed to allocate light memory.\n");
3988 return DDERR_OUTOFMEMORY;
3991 d3d_light_init(object, ddraw);
3993 TRACE("Created light %p.\n", object);
3994 *light = &object->IDirect3DLight_iface;
3996 return D3D_OK;
3999 static HRESULT WINAPI d3d2_CreateLight(IDirect3D2 *iface, IDirect3DLight **light, IUnknown *outer_unknown)
4001 struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4003 TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
4005 return d3d3_CreateLight(&ddraw->IDirect3D3_iface, light, outer_unknown);
4008 static HRESULT WINAPI d3d1_CreateLight(IDirect3D *iface, IDirect3DLight **light, IUnknown *outer_unknown)
4010 struct ddraw *ddraw = impl_from_IDirect3D(iface);
4012 TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
4014 return d3d3_CreateLight(&ddraw->IDirect3D3_iface, light, outer_unknown);
4017 /*****************************************************************************
4018 * IDirect3D3::CreateMaterial
4020 * Creates an IDirect3DMaterial interface. This interface is used by Direct3D3
4021 * and older versions. The IDirect3DMaterial implementation wraps its
4022 * functionality to IDirect3DDevice7::SetMaterial and friends.
4024 * Versions 1, 2 and 3
4026 * Params:
4027 * material: Address to store the new interface's pointer to
4028 * outer_unknown: Basically for aggregation, but ddraw doesn't support it.
4029 * Must be NULL
4031 * Returns:
4032 * D3D_OK on success
4033 * DDERR_OUTOFMEMORY if memory allocation failed
4034 * CLASS_E_NOAGGREGATION if outer_unknown != NULL
4036 *****************************************************************************/
4037 static HRESULT WINAPI d3d3_CreateMaterial(IDirect3D3 *iface, IDirect3DMaterial3 **material,
4038 IUnknown *outer_unknown)
4040 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4041 struct d3d_material *object;
4043 TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4045 if (outer_unknown) return CLASS_E_NOAGGREGATION;
4047 object = d3d_material_create(ddraw);
4048 if (!object)
4050 ERR("Failed to allocate material memory.\n");
4051 return DDERR_OUTOFMEMORY;
4054 TRACE("Created material %p.\n", object);
4055 *material = &object->IDirect3DMaterial3_iface;
4057 return D3D_OK;
4060 static HRESULT WINAPI d3d2_CreateMaterial(IDirect3D2 *iface, IDirect3DMaterial2 **material,
4061 IUnknown *outer_unknown)
4063 struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4064 struct d3d_material *object;
4066 TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4068 object = d3d_material_create(ddraw);
4069 if (!object)
4071 ERR("Failed to allocate material memory.\n");
4072 return DDERR_OUTOFMEMORY;
4075 TRACE("Created material %p.\n", object);
4076 *material = &object->IDirect3DMaterial2_iface;
4078 return D3D_OK;
4081 static HRESULT WINAPI d3d1_CreateMaterial(IDirect3D *iface, IDirect3DMaterial **material,
4082 IUnknown *outer_unknown)
4084 struct ddraw *ddraw = impl_from_IDirect3D(iface);
4085 struct d3d_material *object;
4087 TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4089 object = d3d_material_create(ddraw);
4090 if (!object)
4092 ERR("Failed to allocate material memory.\n");
4093 return DDERR_OUTOFMEMORY;
4096 TRACE("Created material %p.\n", object);
4097 *material = &object->IDirect3DMaterial_iface;
4099 return D3D_OK;
4102 /*****************************************************************************
4103 * IDirect3D3::CreateViewport
4105 * Creates an IDirect3DViewport interface. This interface is used
4106 * by Direct3D and earlier versions for Viewport management. In Direct3D7
4107 * it has been replaced by a viewport structure and
4108 * IDirect3DDevice7::*Viewport. Wine's IDirect3DViewport implementation
4109 * uses the IDirect3DDevice7 methods for its functionality
4111 * Params:
4112 * Viewport: Address to store the new interface pointer
4113 * outer_unknown: Basically for aggregation, but ddraw doesn't support it.
4114 * Must be NULL
4116 * Returns:
4117 * D3D_OK on success
4118 * DDERR_OUTOFMEMORY if memory allocation failed
4119 * CLASS_E_NOAGGREGATION if outer_unknown != NULL
4121 *****************************************************************************/
4122 static HRESULT WINAPI d3d3_CreateViewport(IDirect3D3 *iface, IDirect3DViewport3 **viewport,
4123 IUnknown *outer_unknown)
4125 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4126 struct d3d_viewport *object;
4128 TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4130 if (outer_unknown) return CLASS_E_NOAGGREGATION;
4132 if (!(object = calloc(1, sizeof(*object))))
4134 ERR("Failed to allocate viewport memory.\n");
4135 return DDERR_OUTOFMEMORY;
4138 d3d_viewport_init(object, ddraw);
4140 TRACE("Created viewport %p.\n", object);
4141 *viewport = &object->IDirect3DViewport3_iface;
4143 return D3D_OK;
4146 static HRESULT WINAPI d3d2_CreateViewport(IDirect3D2 *iface, IDirect3DViewport2 **viewport, IUnknown *outer_unknown)
4148 struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4150 TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4152 return d3d3_CreateViewport(&ddraw->IDirect3D3_iface, (IDirect3DViewport3 **)viewport,
4153 outer_unknown);
4156 static HRESULT WINAPI d3d1_CreateViewport(IDirect3D *iface, IDirect3DViewport **viewport, IUnknown *outer_unknown)
4158 struct ddraw *ddraw = impl_from_IDirect3D(iface);
4160 TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4162 return d3d3_CreateViewport(&ddraw->IDirect3D3_iface, (IDirect3DViewport3 **)viewport,
4163 outer_unknown);
4166 static HRESULT ddraw_find_device(struct ddraw *ddraw, const D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr,
4167 unsigned int guid_count, const GUID * const *guids, DWORD device_desc_size)
4169 struct ddraw_find_device_result_v1
4171 DWORD size;
4172 GUID guid;
4173 D3DDEVICEDESC_V1 hw_desc;
4174 D3DDEVICEDESC_V1 sw_desc;
4175 } *fdr1;
4176 struct ddraw_find_device_result_v2
4178 DWORD size;
4179 GUID guid;
4180 D3DDEVICEDESC_V2 hw_desc;
4181 D3DDEVICEDESC_V2 sw_desc;
4182 } *fdr2;
4183 D3DDEVICEDESC7 desc7;
4184 D3DDEVICEDESC desc1;
4185 unsigned int i;
4186 HRESULT hr;
4188 TRACE("ddraw %p, fds %p, fdr %p, guid_count %u, guids %p, device_desc_size %lu.\n",
4189 ddraw, fds, fdr, guid_count, guids, device_desc_size);
4191 if (!fds || !fdr)
4192 return DDERR_INVALIDPARAMS;
4194 if (fds->dwSize != sizeof(*fds))
4196 WARN("Got invalid search structure size %lu.\n", fds->dwSize);
4197 return DDERR_INVALIDPARAMS;
4200 if (fdr->dwSize != sizeof(*fdr) && fdr->dwSize != sizeof(*fdr2) && fdr->dwSize != sizeof(*fdr1))
4202 WARN("Got invalid result structure size %lu.\n", fdr->dwSize);
4203 return DDERR_INVALIDPARAMS;
4206 if (fds->dwFlags & D3DFDS_COLORMODEL)
4207 WARN("Ignoring colour model %#lx.\n", fds->dcmColorModel);
4209 if (fds->dwFlags & D3DFDS_GUID)
4211 BOOL found = FALSE;
4213 TRACE("Trying to match GUID %s.\n", debugstr_guid(&fds->guid));
4215 if ((ddraw->flags & DDRAW_NO3D) && IsEqualGUID(&fds->guid, &IID_IDirect3DHALDevice))
4217 WARN("HAL device not available without 3D support.\n");
4218 return DDERR_NOTFOUND;
4221 for (i = 0; i < guid_count; ++i)
4223 if (IsEqualGUID(guids[i], &fds->guid))
4225 found = TRUE;
4226 break;
4230 if (!found)
4232 WARN("Failed to match GUID %s.\n", debugstr_guid(&fds->guid));
4233 return DDERR_NOTFOUND;
4237 /* Get the caps */
4238 if (FAILED(hr = ddraw_get_d3dcaps(ddraw, &desc7)))
4239 return hr;
4241 /* Now return our own GUID */
4242 ddraw_d3dcaps1_from_7(&desc1, &desc7);
4243 fdr->guid = IID_D3DDEVICE_WineD3D;
4245 /* Note that "device_desc_size" doesn't necessarily have any relation to
4246 * the actual structure size. However, this matches the behaviour of
4247 * Windows since at least Windows 2000. */
4248 if (fdr->dwSize == sizeof(*fdr1))
4250 fdr1 = (struct ddraw_find_device_result_v1 *)fdr;
4251 memcpy(&fdr1->hw_desc, &desc1, sizeof(fdr1->hw_desc));
4252 fdr1->hw_desc.dwSize = device_desc_size;
4253 memcpy(&fdr1->sw_desc, &desc1, sizeof(fdr1->sw_desc));
4254 fdr1->sw_desc.dwSize = device_desc_size;
4256 else if (fdr->dwSize == sizeof(*fdr2))
4258 fdr2 = (struct ddraw_find_device_result_v2 *)fdr;
4259 memcpy(&fdr2->hw_desc, &desc1, sizeof(fdr2->hw_desc));
4260 fdr2->hw_desc.dwSize = device_desc_size;
4261 memcpy(&fdr2->sw_desc, &desc1, sizeof(fdr2->sw_desc));
4262 fdr2->sw_desc.dwSize = device_desc_size;
4264 else
4266 fdr->ddHwDesc = desc1;
4267 fdr->ddHwDesc.dwSize = device_desc_size;
4268 fdr->ddSwDesc = desc1;
4269 fdr->ddSwDesc.dwSize = device_desc_size;
4272 TRACE("Returning Wine's wined3d device with (undumped) capabilities.\n");
4274 return D3D_OK;
4277 static HRESULT WINAPI d3d3_FindDevice(IDirect3D3 *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4279 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4280 static const GUID * const guids[] =
4282 &IID_D3DDEVICE_WineD3D,
4283 &IID_IDirect3DHALDevice,
4284 &IID_IDirect3DRGBDevice,
4287 TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4289 return ddraw_find_device(ddraw, fds, fdr, ARRAY_SIZE(guids), guids, sizeof(D3DDEVICEDESC_V3));
4292 static HRESULT WINAPI d3d2_FindDevice(IDirect3D2 *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4294 struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4295 static const GUID * const guids[] =
4297 &IID_D3DDEVICE_WineD3D,
4298 &IID_IDirect3DHALDevice,
4299 &IID_IDirect3DMMXDevice,
4300 &IID_IDirect3DRGBDevice,
4301 &IID_IDirect3DRampDevice,
4304 TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4306 return ddraw_find_device(ddraw, fds, fdr, ARRAY_SIZE(guids), guids, sizeof(D3DDEVICEDESC_V2));
4309 static HRESULT WINAPI d3d1_FindDevice(IDirect3D *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4311 struct ddraw *ddraw = impl_from_IDirect3D(iface);
4312 static const GUID * const guids[] =
4314 &IID_D3DDEVICE_WineD3D,
4315 &IID_IDirect3DHALDevice,
4316 &IID_IDirect3DRGBDevice,
4317 &IID_IDirect3DRampDevice,
4320 TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4322 return ddraw_find_device(ddraw, fds, fdr, ARRAY_SIZE(guids), guids, sizeof(D3DDEVICEDESC_V1));
4325 /*****************************************************************************
4326 * IDirect3D7::CreateDevice
4328 * Creates an IDirect3DDevice7 interface.
4330 * Versions 2, 3 and 7. IDirect3DDevice 1 interfaces are interfaces to
4331 * DirectDraw surfaces and are created with
4332 * IDirectDrawSurface::QueryInterface. This method uses CreateDevice to
4333 * create the device object and QueryInterfaces for IDirect3DDevice
4335 * Params:
4336 * refiid: IID of the device to create
4337 * Surface: Initial rendertarget
4338 * Device: Address to return the interface pointer
4340 * Returns:
4341 * D3D_OK on success
4342 * DDERR_OUTOFMEMORY if memory allocation failed
4343 * DDERR_INVALIDPARAMS if a device exists already
4345 *****************************************************************************/
4346 static HRESULT WINAPI d3d7_CreateDevice(IDirect3D7 *iface, REFCLSID riid,
4347 IDirectDrawSurface7 *surface, IDirect3DDevice7 **device)
4349 struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface7(surface);
4350 struct ddraw *ddraw = impl_from_IDirect3D7(iface);
4351 struct d3d_device *object;
4352 HRESULT hr;
4354 TRACE("iface %p, riid %s, surface %p, device %p.\n", iface, debugstr_guid(riid), surface, device);
4356 wined3d_mutex_lock();
4357 if (SUCCEEDED(hr = d3d_device_create(ddraw, riid, target, (IUnknown *)surface, 7, &object, NULL)))
4359 *device = &object->IDirect3DDevice7_iface;
4361 else
4363 WARN("Failed to create device, hr %#lx.\n", hr);
4364 *device = NULL;
4366 wined3d_mutex_unlock();
4368 return hr;
4371 static HRESULT WINAPI d3d3_CreateDevice(IDirect3D3 *iface, REFCLSID riid,
4372 IDirectDrawSurface4 *surface, IDirect3DDevice3 **device, IUnknown *outer_unknown)
4374 struct ddraw_surface *surface_impl = unsafe_impl_from_IDirectDrawSurface4(surface);
4375 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4376 struct d3d_device *device_impl;
4377 HRESULT hr;
4379 TRACE("iface %p, riid %s, surface %p, device %p, outer_unknown %p.\n",
4380 iface, debugstr_guid(riid), surface, device, outer_unknown);
4382 if (outer_unknown)
4383 return CLASS_E_NOAGGREGATION;
4385 wined3d_mutex_lock();
4386 if (SUCCEEDED(hr = d3d_device_create(ddraw, riid, surface_impl, (IUnknown *)surface, 3, &device_impl, NULL)))
4388 *device = &device_impl->IDirect3DDevice3_iface;
4390 else
4392 WARN("Failed to create device, hr %#lx.\n", hr);
4393 *device = NULL;
4395 wined3d_mutex_unlock();
4397 return hr;
4400 static HRESULT WINAPI d3d2_CreateDevice(IDirect3D2 *iface, REFCLSID riid,
4401 IDirectDrawSurface *surface, IDirect3DDevice2 **device)
4403 struct ddraw_surface *surface_impl = unsafe_impl_from_IDirectDrawSurface(surface);
4404 struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4405 struct d3d_device *device_impl;
4406 HRESULT hr;
4408 TRACE("iface %p, riid %s, surface %p, device %p.\n",
4409 iface, debugstr_guid(riid), surface, device);
4411 wined3d_mutex_lock();
4412 if (SUCCEEDED(hr = d3d_device_create(ddraw, riid, surface_impl, (IUnknown *)surface, 2, &device_impl, NULL)))
4414 *device = &device_impl->IDirect3DDevice2_iface;
4416 else
4418 WARN("Failed to create device, hr %#lx.\n", hr);
4419 *device = NULL;
4421 wined3d_mutex_unlock();
4423 return hr;
4426 /*****************************************************************************
4427 * IDirect3D7::CreateVertexBuffer
4429 * Creates a new vertex buffer object and returns a IDirect3DVertexBuffer7
4430 * interface.
4432 * Versions 3 and 7
4434 * Params:
4435 * desc: Requested Vertex buffer properties
4436 * vertex_buffer: Address to return the interface pointer at
4437 * flags: Some flags, should be 0
4439 * Returns
4440 * D3D_OK on success
4441 * DDERR_OUTOFMEMORY if memory allocation failed
4442 * DDERR_INVALIDPARAMS if desc or vertex_buffer is NULL
4444 *****************************************************************************/
4445 static HRESULT WINAPI d3d7_CreateVertexBuffer(IDirect3D7 *iface, D3DVERTEXBUFFERDESC *desc,
4446 IDirect3DVertexBuffer7 **vertex_buffer, DWORD flags)
4448 struct ddraw *ddraw = impl_from_IDirect3D7(iface);
4449 struct d3d_vertex_buffer *object;
4450 HRESULT hr;
4452 TRACE("iface %p, desc %p, vertex_buffer %p, flags %#lx.\n",
4453 iface, desc, vertex_buffer, flags);
4455 if (!vertex_buffer || !desc) return DDERR_INVALIDPARAMS;
4457 hr = d3d_vertex_buffer_create(&object, ddraw, desc);
4458 if (hr == D3D_OK)
4460 TRACE("Created vertex buffer %p.\n", object);
4461 *vertex_buffer = &object->IDirect3DVertexBuffer7_iface;
4463 else
4464 WARN("Failed to create vertex buffer, hr %#lx.\n", hr);
4466 return hr;
4469 static HRESULT WINAPI d3d3_CreateVertexBuffer(IDirect3D3 *iface, D3DVERTEXBUFFERDESC *desc,
4470 IDirect3DVertexBuffer **vertex_buffer, DWORD flags, IUnknown *outer_unknown)
4472 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4473 struct d3d_vertex_buffer *object;
4474 HRESULT hr;
4476 TRACE("iface %p, desc %p, vertex_buffer %p, flags %#lx, outer_unknown %p.\n",
4477 iface, desc, vertex_buffer, flags, outer_unknown);
4479 if (outer_unknown)
4480 return CLASS_E_NOAGGREGATION;
4481 if (!vertex_buffer || !desc)
4482 return DDERR_INVALIDPARAMS;
4484 hr = d3d_vertex_buffer_create(&object, ddraw, desc);
4485 if (hr == D3D_OK)
4487 TRACE("Created vertex buffer %p.\n", object);
4488 *vertex_buffer = (IDirect3DVertexBuffer *)&object->IDirect3DVertexBuffer7_iface;
4490 else
4491 WARN("Failed to create vertex buffer, hr %#lx.\n", hr);
4493 return hr;
4496 /*****************************************************************************
4497 * IDirect3D7::EnumZBufferFormats
4499 * Enumerates all supported Z buffer pixel formats
4501 * Versions 3 and 7
4503 * Params:
4504 * device_iid:
4505 * callback: callback to call for each pixel format
4506 * context: Pointer to pass back to the callback
4508 * Returns:
4509 * D3D_OK on success
4510 * DDERR_INVALIDPARAMS if callback is NULL
4512 *****************************************************************************/
4513 static HRESULT WINAPI d3d7_EnumZBufferFormats(IDirect3D7 *iface, REFCLSID device_iid,
4514 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
4516 struct ddraw *ddraw = impl_from_IDirect3D7(iface);
4517 struct wined3d_display_mode mode;
4518 enum wined3d_device_type type;
4519 unsigned int i;
4520 HRESULT hr;
4522 /* Order matters. Specifically, BattleZone II (full version) expects the
4523 * 16-bit depth formats to be listed before the 24 and 32 ones. */
4524 static const enum wined3d_format_id formats[] =
4526 WINED3DFMT_S1_UINT_D15_UNORM,
4527 WINED3DFMT_D16_UNORM,
4528 WINED3DFMT_X8D24_UNORM,
4529 WINED3DFMT_S4X4_UINT_D24_UNORM,
4530 WINED3DFMT_D24_UNORM_S8_UINT,
4531 WINED3DFMT_D32_UNORM,
4534 TRACE("iface %p, device_iid %s, callback %p, context %p.\n",
4535 iface, debugstr_guid(device_iid), callback, context);
4537 if (!callback) return DDERR_INVALIDPARAMS;
4539 if (IsEqualGUID(device_iid, &IID_IDirect3DHALDevice)
4540 || IsEqualGUID(device_iid, &IID_IDirect3DTnLHalDevice)
4541 || IsEqualGUID(device_iid, &IID_D3DDEVICE_WineD3D))
4543 TRACE("Asked for HAL device.\n");
4544 type = WINED3D_DEVICE_TYPE_HAL;
4546 else if (IsEqualGUID(device_iid, &IID_IDirect3DRGBDevice)
4547 || IsEqualGUID(device_iid, &IID_IDirect3DMMXDevice))
4549 TRACE("Asked for SW device.\n");
4550 type = WINED3D_DEVICE_TYPE_SW;
4552 else if (IsEqualGUID(device_iid, &IID_IDirect3DRefDevice))
4554 TRACE("Asked for REF device.\n");
4555 type = WINED3D_DEVICE_TYPE_REF;
4557 else if (IsEqualGUID(device_iid, &IID_IDirect3DNullDevice))
4559 TRACE("Asked for NULLREF device.\n");
4560 type = WINED3D_DEVICE_TYPE_NULLREF;
4562 else
4564 FIXME("Unexpected device GUID %s.\n", debugstr_guid(device_iid));
4565 type = WINED3D_DEVICE_TYPE_HAL;
4568 wined3d_mutex_lock();
4569 /* We need an adapter format from somewhere to please wined3d and WGL.
4570 * Use the current display mode. So far all cards offer the same depth
4571 * stencil format for all modes, but if some do not and applications do
4572 * not like that we'll have to find some workaround, like iterating over
4573 * all imaginable formats and collecting all the depth stencil formats we
4574 * can get. */
4575 if (FAILED(hr = wined3d_output_get_display_mode(ddraw->wined3d_output, &mode, NULL)))
4577 ERR("Failed to get display mode, hr %#lx.\n", hr);
4578 wined3d_mutex_unlock();
4579 return hr;
4582 for (i = 0; i < ARRAY_SIZE(formats); ++i)
4584 if (SUCCEEDED(wined3d_check_device_format(ddraw->wined3d, ddraw->wined3d_adapter, type,
4585 mode.format_id, 0, WINED3D_BIND_DEPTH_STENCIL, WINED3D_RTYPE_TEXTURE_2D, formats[i])))
4587 DDPIXELFORMAT pformat;
4589 memset(&pformat, 0, sizeof(pformat));
4590 pformat.dwSize = sizeof(pformat);
4591 ddrawformat_from_wined3dformat(&pformat, formats[i]);
4593 TRACE("Enumerating wined3d format %#x.\n", formats[i]);
4594 hr = callback(&pformat, context);
4595 if (hr != DDENUMRET_OK)
4597 TRACE("Format enumeration cancelled by application.\n");
4598 wined3d_mutex_unlock();
4599 return D3D_OK;
4604 /* Historically some windows drivers used dwZBufferBitDepth=24 for WINED3DFMT_X8D24_UNORM,
4605 * while others used dwZBufferBitDepth=32. In either case the pitch matches a 32 bits per
4606 * pixel format, so we use dwZBufferBitDepth=32. Some games expect 24. Windows Vista and
4607 * newer enumerate both versions, so we do the same(bug 22434) */
4608 if (SUCCEEDED(wined3d_check_device_format(ddraw->wined3d, ddraw->wined3d_adapter, type, mode.format_id,
4609 0, WINED3D_BIND_DEPTH_STENCIL, WINED3D_RTYPE_TEXTURE_2D, WINED3DFMT_X8D24_UNORM)))
4611 DDPIXELFORMAT x8d24 =
4613 sizeof(x8d24), DDPF_ZBUFFER, 0,
4614 {24}, {0x00000000}, {0x00ffffff}, {0x00000000}
4616 TRACE("Enumerating WINED3DFMT_X8D24_UNORM, dwZBufferBitDepth=24 version\n");
4617 callback(&x8d24, context);
4620 TRACE("End of enumeration.\n");
4622 wined3d_mutex_unlock();
4624 return D3D_OK;
4627 static HRESULT WINAPI d3d3_EnumZBufferFormats(IDirect3D3 *iface, REFCLSID device_iid,
4628 LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
4630 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4632 TRACE("iface %p, device_iid %s, callback %p, context %p.\n",
4633 iface, debugstr_guid(device_iid), callback, context);
4635 return d3d7_EnumZBufferFormats(&ddraw->IDirect3D7_iface, device_iid, callback, context);
4638 /*****************************************************************************
4639 * IDirect3D7::EvictManagedTextures
4641 * Removes all managed textures (=surfaces with DDSCAPS2_TEXTUREMANAGE or
4642 * DDSCAPS2_D3DTEXTUREMANAGE caps) to be removed from video memory.
4644 * Versions 3 and 7
4646 * Returns:
4647 * D3D_OK, because it's a stub
4649 *****************************************************************************/
4650 static HRESULT WINAPI d3d7_EvictManagedTextures(IDirect3D7 *iface)
4652 struct ddraw *ddraw = impl_from_IDirect3D7(iface);
4654 TRACE("iface %p!\n", iface);
4656 wined3d_mutex_lock();
4657 if (ddraw->flags & DDRAW_D3D_INITIALIZED)
4658 wined3d_device_evict_managed_resources(ddraw->wined3d_device);
4659 wined3d_mutex_unlock();
4661 return D3D_OK;
4664 static HRESULT WINAPI d3d3_EvictManagedTextures(IDirect3D3 *iface)
4666 struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4668 TRACE("iface %p.\n", iface);
4670 return d3d7_EvictManagedTextures(&ddraw->IDirect3D7_iface);
4673 /*****************************************************************************
4674 * IDirectDraw7 VTable
4675 *****************************************************************************/
4676 static const struct IDirectDraw7Vtbl ddraw7_vtbl =
4678 /* IUnknown */
4679 ddraw7_QueryInterface,
4680 ddraw7_AddRef,
4681 ddraw7_Release,
4682 /* IDirectDraw */
4683 ddraw7_Compact,
4684 ddraw7_CreateClipper,
4685 ddraw7_CreatePalette,
4686 ddraw7_CreateSurface,
4687 ddraw7_DuplicateSurface,
4688 ddraw7_EnumDisplayModes,
4689 ddraw7_EnumSurfaces,
4690 ddraw7_FlipToGDISurface,
4691 ddraw7_GetCaps,
4692 ddraw7_GetDisplayMode,
4693 ddraw7_GetFourCCCodes,
4694 ddraw7_GetGDISurface,
4695 ddraw7_GetMonitorFrequency,
4696 ddraw7_GetScanLine,
4697 ddraw7_GetVerticalBlankStatus,
4698 ddraw7_Initialize,
4699 ddraw7_RestoreDisplayMode,
4700 ddraw7_SetCooperativeLevel,
4701 ddraw7_SetDisplayMode,
4702 ddraw7_WaitForVerticalBlank,
4703 /* IDirectDraw2 */
4704 ddraw7_GetAvailableVidMem,
4705 /* IDirectDraw3 */
4706 ddraw7_GetSurfaceFromDC,
4707 /* IDirectDraw4 */
4708 ddraw7_RestoreAllSurfaces,
4709 ddraw7_TestCooperativeLevel,
4710 ddraw7_GetDeviceIdentifier,
4711 /* IDirectDraw7 */
4712 ddraw7_StartModeTest,
4713 ddraw7_EvaluateMode
4716 static const struct IDirectDraw4Vtbl ddraw4_vtbl =
4718 /* IUnknown */
4719 ddraw4_QueryInterface,
4720 ddraw4_AddRef,
4721 ddraw4_Release,
4722 /* IDirectDraw */
4723 ddraw4_Compact,
4724 ddraw4_CreateClipper,
4725 ddraw4_CreatePalette,
4726 ddraw4_CreateSurface,
4727 ddraw4_DuplicateSurface,
4728 ddraw4_EnumDisplayModes,
4729 ddraw4_EnumSurfaces,
4730 ddraw4_FlipToGDISurface,
4731 ddraw4_GetCaps,
4732 ddraw4_GetDisplayMode,
4733 ddraw4_GetFourCCCodes,
4734 ddraw4_GetGDISurface,
4735 ddraw4_GetMonitorFrequency,
4736 ddraw4_GetScanLine,
4737 ddraw4_GetVerticalBlankStatus,
4738 ddraw4_Initialize,
4739 ddraw4_RestoreDisplayMode,
4740 ddraw4_SetCooperativeLevel,
4741 ddraw4_SetDisplayMode,
4742 ddraw4_WaitForVerticalBlank,
4743 /* IDirectDraw2 */
4744 ddraw4_GetAvailableVidMem,
4745 /* IDirectDraw3 */
4746 ddraw4_GetSurfaceFromDC,
4747 /* IDirectDraw4 */
4748 ddraw4_RestoreAllSurfaces,
4749 ddraw4_TestCooperativeLevel,
4750 ddraw4_GetDeviceIdentifier,
4753 static const struct IDirectDraw2Vtbl ddraw2_vtbl =
4755 /* IUnknown */
4756 ddraw2_QueryInterface,
4757 ddraw2_AddRef,
4758 ddraw2_Release,
4759 /* IDirectDraw */
4760 ddraw2_Compact,
4761 ddraw2_CreateClipper,
4762 ddraw2_CreatePalette,
4763 ddraw2_CreateSurface,
4764 ddraw2_DuplicateSurface,
4765 ddraw2_EnumDisplayModes,
4766 ddraw2_EnumSurfaces,
4767 ddraw2_FlipToGDISurface,
4768 ddraw2_GetCaps,
4769 ddraw2_GetDisplayMode,
4770 ddraw2_GetFourCCCodes,
4771 ddraw2_GetGDISurface,
4772 ddraw2_GetMonitorFrequency,
4773 ddraw2_GetScanLine,
4774 ddraw2_GetVerticalBlankStatus,
4775 ddraw2_Initialize,
4776 ddraw2_RestoreDisplayMode,
4777 ddraw2_SetCooperativeLevel,
4778 ddraw2_SetDisplayMode,
4779 ddraw2_WaitForVerticalBlank,
4780 /* IDirectDraw2 */
4781 ddraw2_GetAvailableVidMem,
4784 /* Bad Mojo Redux expects this vtbl to be writable. */
4785 static struct IDirectDrawVtbl ddraw1_vtbl =
4787 /* IUnknown */
4788 ddraw1_QueryInterface,
4789 ddraw1_AddRef,
4790 ddraw1_Release,
4791 /* IDirectDraw */
4792 ddraw1_Compact,
4793 ddraw1_CreateClipper,
4794 ddraw1_CreatePalette,
4795 ddraw1_CreateSurface,
4796 ddraw1_DuplicateSurface,
4797 ddraw1_EnumDisplayModes,
4798 ddraw1_EnumSurfaces,
4799 ddraw1_FlipToGDISurface,
4800 ddraw1_GetCaps,
4801 ddraw1_GetDisplayMode,
4802 ddraw1_GetFourCCCodes,
4803 ddraw1_GetGDISurface,
4804 ddraw1_GetMonitorFrequency,
4805 ddraw1_GetScanLine,
4806 ddraw1_GetVerticalBlankStatus,
4807 ddraw1_Initialize,
4808 ddraw1_RestoreDisplayMode,
4809 ddraw1_SetCooperativeLevel,
4810 ddraw1_SetDisplayMode,
4811 ddraw1_WaitForVerticalBlank,
4814 static const struct IDirect3D7Vtbl d3d7_vtbl =
4816 /* IUnknown methods */
4817 d3d7_QueryInterface,
4818 d3d7_AddRef,
4819 d3d7_Release,
4820 /* IDirect3D7 methods */
4821 d3d7_EnumDevices,
4822 d3d7_CreateDevice,
4823 d3d7_CreateVertexBuffer,
4824 d3d7_EnumZBufferFormats,
4825 d3d7_EvictManagedTextures
4828 static const struct IDirect3D3Vtbl d3d3_vtbl =
4830 /* IUnknown methods */
4831 d3d3_QueryInterface,
4832 d3d3_AddRef,
4833 d3d3_Release,
4834 /* IDirect3D3 methods */
4835 d3d3_EnumDevices,
4836 d3d3_CreateLight,
4837 d3d3_CreateMaterial,
4838 d3d3_CreateViewport,
4839 d3d3_FindDevice,
4840 d3d3_CreateDevice,
4841 d3d3_CreateVertexBuffer,
4842 d3d3_EnumZBufferFormats,
4843 d3d3_EvictManagedTextures
4846 static const struct IDirect3D2Vtbl d3d2_vtbl =
4848 /* IUnknown methods */
4849 d3d2_QueryInterface,
4850 d3d2_AddRef,
4851 d3d2_Release,
4852 /* IDirect3D2 methods */
4853 d3d2_EnumDevices,
4854 d3d2_CreateLight,
4855 d3d2_CreateMaterial,
4856 d3d2_CreateViewport,
4857 d3d2_FindDevice,
4858 d3d2_CreateDevice
4861 static const struct IDirect3DVtbl d3d1_vtbl =
4863 /* IUnknown methods */
4864 d3d1_QueryInterface,
4865 d3d1_AddRef,
4866 d3d1_Release,
4867 /* IDirect3D methods */
4868 d3d1_Initialize,
4869 d3d1_EnumDevices,
4870 d3d1_CreateLight,
4871 d3d1_CreateMaterial,
4872 d3d1_CreateViewport,
4873 d3d1_FindDevice
4876 /*****************************************************************************
4877 * ddraw_find_decl
4879 * Finds the WineD3D vertex declaration for a specific fvf, and creates one
4880 * if none was found.
4882 * This function is in ddraw.c and the DDraw object space because D3D7
4883 * vertex buffers are created using the IDirect3D interface to the ddraw
4884 * object, so they can be valid across D3D devices(theoretically. The ddraw
4885 * object also owns the wined3d device
4887 * Parameters:
4888 * This: Device
4889 * fvf: Fvf to find the decl for
4891 * Returns:
4892 * NULL in case of an error, the vertex declaration for the FVF otherwise.
4894 *****************************************************************************/
4895 struct wined3d_vertex_declaration *ddraw_find_decl(struct ddraw *This, DWORD fvf)
4897 struct wined3d_vertex_declaration *pDecl = NULL;
4898 HRESULT hr;
4899 int p, low, high; /* deliberately signed */
4900 struct FvfToDecl *convertedDecls = This->decls;
4902 TRACE("Searching for declaration for fvf %08lx... ", fvf);
4904 low = 0;
4905 high = This->numConvertedDecls - 1;
4906 while(low <= high) {
4907 p = (low + high) >> 1;
4908 TRACE("%d ", p);
4909 if(convertedDecls[p].fvf == fvf) {
4910 TRACE("found %p\n", convertedDecls[p].decl);
4911 return convertedDecls[p].decl;
4912 } else if(convertedDecls[p].fvf < fvf) {
4913 low = p + 1;
4914 } else {
4915 high = p - 1;
4918 TRACE("not found. Creating and inserting at position %d.\n", low);
4920 hr = wined3d_vertex_declaration_create_from_fvf(This->wined3d_device,
4921 fvf, This, &ddraw_null_wined3d_parent_ops, &pDecl);
4922 if (hr != S_OK) return NULL;
4924 if (This->declArraySize == This->numConvertedDecls)
4926 unsigned int grow = max(This->declArraySize / 2, 8);
4928 if (!(convertedDecls = realloc(convertedDecls,
4929 (This->numConvertedDecls + grow) * sizeof(*convertedDecls))))
4931 wined3d_vertex_declaration_decref(pDecl);
4932 return NULL;
4934 This->decls = convertedDecls;
4935 This->declArraySize += grow;
4938 memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(convertedDecls[0]) * (This->numConvertedDecls - low));
4939 convertedDecls[low].decl = pDecl;
4940 convertedDecls[low].fvf = fvf;
4941 This->numConvertedDecls++;
4943 TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls);
4944 return pDecl;
4947 static inline struct ddraw *ddraw_from_device_parent(struct wined3d_device_parent *device_parent)
4949 return CONTAINING_RECORD(device_parent, struct ddraw, device_parent);
4952 static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
4953 struct wined3d_device *device)
4955 TRACE("device_parent %p, device %p.\n", device_parent, device);
4958 /* This is run from device_process_message() in wined3d, we can't take the
4959 * wined3d mutex. */
4960 /* FIXME: We only get mode change notifications in exclusive mode, but we
4961 * should mark surfaces as lost on mode changes in DDSCL_NORMAL mode as well. */
4962 static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent)
4964 struct ddraw *ddraw = ddraw_from_device_parent(device_parent);
4965 struct wined3d_output_desc output_desc;
4966 RECT *r;
4968 TRACE("device_parent %p.\n", device_parent);
4970 if (!(ddraw->cooperative_level & DDSCL_EXCLUSIVE) || !ddraw->swapchain_window)
4972 TRACE("Nothing to resize.\n");
4973 return;
4976 if (FAILED(wined3d_output_get_desc(ddraw->wined3d_output, &output_desc)))
4978 ERR("Failed to get output description.\n");
4979 return;
4982 r = &output_desc.desktop_rect;
4983 TRACE("Resizing window %p to %s.\n", ddraw->swapchain_window, wine_dbgstr_rect(r));
4985 if (!SetWindowPos(ddraw->swapchain_window, HWND_TOP, r->left, r->top,
4986 r->right - r->left, r->bottom - r->top, SWP_SHOWWINDOW | SWP_NOACTIVATE))
4987 ERR("Failed to resize window.\n");
4989 InterlockedCompareExchange(&ddraw->device_state, DDRAW_DEVICE_STATE_NOT_RESTORED, DDRAW_DEVICE_STATE_OK);
4992 static void CDECL device_parent_activate(struct wined3d_device_parent *device_parent, BOOL activate)
4994 struct ddraw *ddraw = ddraw_from_device_parent(device_parent);
4996 TRACE("device_parent %p, activate %#x.\n", device_parent, activate);
4998 if (!activate)
5000 ddraw->device_state = DDRAW_DEVICE_STATE_LOST;
5001 exclusive_window = NULL;
5003 else
5005 InterlockedCompareExchange(&ddraw->device_state, DDRAW_DEVICE_STATE_NOT_RESTORED, DDRAW_DEVICE_STATE_LOST);
5009 void ddraw_update_lost_surfaces(struct ddraw *ddraw)
5011 struct ddraw_surface *surface;
5013 /* Railroad Tycoon 2 tries to restore surfaces from within a
5014 * WM_QUERYNEWPALETTE message handler and expects it to succeed. We
5015 * haven't received the WM_ACTIVATEAPP message by that point, so the
5016 * device state is still DDRAW_DEVICE_STATE_LOST, even though we are in
5017 * the foreground. */
5018 if (ddraw->device_state == DDRAW_DEVICE_STATE_LOST)
5020 HWND window = ddraw->focuswindow ? ddraw->focuswindow : ddraw->dest_window;
5022 if (window && GetForegroundWindow() == window)
5023 ddraw->device_state = DDRAW_DEVICE_STATE_NOT_RESTORED;
5026 if (ddraw->device_state != DDRAW_DEVICE_STATE_NOT_RESTORED)
5027 return;
5029 LIST_FOR_EACH_ENTRY(surface, &ddraw->surface_list, struct ddraw_surface, surface_list_entry)
5031 surface->is_lost = ddraw_surface_can_be_lost(surface);
5033 ddraw->device_state = DDRAW_DEVICE_STATE_OK;
5036 static HRESULT CDECL device_parent_texture_sub_resource_created(struct wined3d_device_parent *device_parent,
5037 enum wined3d_resource_type type, struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
5038 void **parent, const struct wined3d_parent_ops **parent_ops)
5040 TRACE("device_parent %p, type %#x, wined3d_texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
5041 device_parent, type, wined3d_texture, sub_resource_idx, parent, parent_ops);
5043 *parent = NULL;
5044 *parent_ops = &ddraw_null_wined3d_parent_ops;
5046 return DD_OK;
5049 static const struct wined3d_device_parent_ops ddraw_wined3d_device_parent_ops =
5051 device_parent_wined3d_device_created,
5052 device_parent_mode_changed,
5053 device_parent_activate,
5054 device_parent_texture_sub_resource_created,
5057 HRESULT ddraw_init(struct ddraw *ddraw, DWORD flags, enum wined3d_device_type device_type)
5059 struct wined3d_caps caps;
5060 HRESULT hr;
5062 static const enum wined3d_feature_level feature_levels[] =
5064 WINED3D_FEATURE_LEVEL_7,
5065 WINED3D_FEATURE_LEVEL_6,
5066 WINED3D_FEATURE_LEVEL_5,
5069 ddraw->IDirectDraw7_iface.lpVtbl = &ddraw7_vtbl;
5070 ddraw->IDirectDraw_iface.lpVtbl = &ddraw1_vtbl;
5071 ddraw->IDirectDraw2_iface.lpVtbl = &ddraw2_vtbl;
5072 ddraw->IDirectDraw4_iface.lpVtbl = &ddraw4_vtbl;
5073 ddraw->IDirect3D_iface.lpVtbl = &d3d1_vtbl;
5074 ddraw->IDirect3D2_iface.lpVtbl = &d3d2_vtbl;
5075 ddraw->IDirect3D3_iface.lpVtbl = &d3d3_vtbl;
5076 ddraw->IDirect3D7_iface.lpVtbl = &d3d7_vtbl;
5077 ddraw->device_parent.ops = &ddraw_wined3d_device_parent_ops;
5078 ddraw->state_parent.ops = &ddraw_swapchain_state_parent_ops;
5079 ddraw->numIfaces = 1;
5080 ddraw->ref7 = 1;
5082 flags |= DDRAW_WINED3D_FLAGS;
5083 if (!(ddraw->wined3d = wined3d_create(flags)))
5085 flags |= WINED3D_NO3D;
5086 if (!(ddraw->wined3d = wined3d_create(flags)))
5088 WARN("Failed to create a wined3d object.\n");
5089 return E_FAIL;
5093 if (!(ddraw->wined3d_adapter = wined3d_get_adapter(ddraw->wined3d, WINED3DADAPTER_DEFAULT)))
5095 WARN("Failed to get the default wined3d adapter.\n");
5096 wined3d_decref(ddraw->wined3d);
5097 return E_FAIL;
5100 if (!(ddraw->wined3d_output = wined3d_adapter_get_output(ddraw->wined3d_adapter, 0)))
5102 WARN("Failed to get the default wined3d output.\n");
5103 wined3d_decref(ddraw->wined3d);
5104 return E_FAIL;
5107 if (FAILED(hr = wined3d_get_device_caps(ddraw->wined3d_adapter, device_type, &caps)))
5109 ERR("Failed to get device caps, hr %#lx.\n", hr);
5110 wined3d_decref(ddraw->wined3d);
5111 return E_FAIL;
5114 if (!(caps.ddraw_caps.caps & WINEDDCAPS_3D))
5116 WARN("Created a wined3d object without 3D support.\n");
5117 ddraw->flags |= DDRAW_NO3D;
5120 if (FAILED(hr = wined3d_device_create(ddraw->wined3d, ddraw->wined3d_adapter, device_type,
5121 NULL, 0, DDRAW_STRIDE_ALIGNMENT, feature_levels, ARRAY_SIZE(feature_levels),
5122 &ddraw->device_parent, &ddraw->wined3d_device)))
5124 WARN("Failed to create a wined3d device, hr %#lx.\n", hr);
5125 wined3d_decref(ddraw->wined3d);
5126 return hr;
5128 ddraw->immediate_context = wined3d_device_get_immediate_context(ddraw->wined3d_device);
5130 list_init(&ddraw->surface_list);
5131 return DD_OK;