imagehlp: Use the IMAGE_FIRST_SECTION helper macro.
[wine.git] / dlls / dxgi / device.c
blob60febf4d8e158736331957f3bc94bd4bfc2d473f
1 /*
2 * Copyright 2008 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "dxgi_private.h"
22 WINE_DEFAULT_DEBUG_CHANNEL(dxgi);
24 static void STDMETHODCALLTYPE dxgi_null_wined3d_object_destroyed(void *parent) {}
26 static const struct wined3d_parent_ops dxgi_null_wined3d_parent_ops =
28 dxgi_null_wined3d_object_destroyed,
31 static inline struct dxgi_device *impl_from_IWineDXGIDevice(IWineDXGIDevice *iface)
33 return CONTAINING_RECORD(iface, struct dxgi_device, IWineDXGIDevice_iface);
36 /* IUnknown methods */
38 static HRESULT STDMETHODCALLTYPE dxgi_device_QueryInterface(IWineDXGIDevice *iface, REFIID riid, void **object)
40 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
42 TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object);
44 if (IsEqualGUID(riid, &IID_IUnknown)
45 || IsEqualGUID(riid, &IID_IDXGIObject)
46 || IsEqualGUID(riid, &IID_IDXGIDevice)
47 || IsEqualGUID(riid, &IID_IDXGIDevice1)
48 || IsEqualGUID(riid, &IID_IDXGIDevice2)
49 || IsEqualGUID(riid, &IID_IDXGIDevice3)
50 || IsEqualGUID(riid, &IID_IWineDXGIDevice))
52 IUnknown_AddRef(iface);
53 *object = iface;
54 return S_OK;
57 if (IsEqualGUID(riid, &IID_IWineDXGISwapChainFactory))
59 IUnknown_AddRef(iface);
60 *object = &device->IWineDXGISwapChainFactory_iface;
61 return S_OK;
64 if (device->child_layer)
66 TRACE("Forwarding to child layer %p.\n", device->child_layer);
67 return IUnknown_QueryInterface(device->child_layer, riid, object);
70 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
72 *object = NULL;
73 return E_NOINTERFACE;
76 static ULONG STDMETHODCALLTYPE dxgi_device_AddRef(IWineDXGIDevice *iface)
78 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
79 ULONG refcount = InterlockedIncrement(&device->refcount);
81 TRACE("%p increasing refcount to %lu\n", device, refcount);
83 return refcount;
86 static ULONG STDMETHODCALLTYPE dxgi_device_Release(IWineDXGIDevice *iface)
88 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
89 ULONG refcount = InterlockedDecrement(&device->refcount);
91 TRACE("%p decreasing refcount to %lu.\n", device, refcount);
93 if (!refcount)
95 if (device->child_layer)
96 IUnknown_Release(device->child_layer);
97 wined3d_mutex_lock();
98 wined3d_swapchain_decref(device->implicit_swapchain);
99 wined3d_device_decref(device->wined3d_device);
100 wined3d_mutex_unlock();
101 IWineDXGIAdapter_Release(device->adapter);
102 wined3d_private_store_cleanup(&device->private_store);
103 heap_free(device);
106 return refcount;
109 /* IDXGIObject methods */
111 static HRESULT STDMETHODCALLTYPE dxgi_device_SetPrivateData(IWineDXGIDevice *iface,
112 REFGUID guid, UINT data_size, const void *data)
114 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
116 TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data);
118 return dxgi_set_private_data(&device->private_store, guid, data_size, data);
121 static HRESULT STDMETHODCALLTYPE dxgi_device_SetPrivateDataInterface(IWineDXGIDevice *iface,
122 REFGUID guid, const IUnknown *object)
124 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
126 TRACE("iface %p, guid %s, object %p.\n", iface, debugstr_guid(guid), object);
128 return dxgi_set_private_data_interface(&device->private_store, guid, object);
131 static HRESULT STDMETHODCALLTYPE dxgi_device_GetPrivateData(IWineDXGIDevice *iface,
132 REFGUID guid, UINT *data_size, void *data)
134 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
136 TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data);
138 return dxgi_get_private_data(&device->private_store, guid, data_size, data);
141 static HRESULT STDMETHODCALLTYPE dxgi_device_GetParent(IWineDXGIDevice *iface, REFIID riid, void **parent)
143 IDXGIAdapter *adapter;
144 HRESULT hr;
146 TRACE("iface %p, riid %s, parent %p.\n", iface, debugstr_guid(riid), parent);
148 hr = IWineDXGIDevice_GetAdapter(iface, &adapter);
149 if (FAILED(hr))
151 ERR("Failed to get adapter, hr %#lx.\n", hr);
152 return hr;
155 hr = IDXGIAdapter_QueryInterface(adapter, riid, parent);
156 IDXGIAdapter_Release(adapter);
158 return hr;
161 /* IDXGIDevice methods */
163 static HRESULT STDMETHODCALLTYPE dxgi_device_GetAdapter(IWineDXGIDevice *iface, IDXGIAdapter **adapter)
165 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
167 TRACE("iface %p, adapter %p.\n", iface, adapter);
169 *adapter = (IDXGIAdapter *)device->adapter;
170 IDXGIAdapter_AddRef(*adapter);
171 return S_OK;
174 static HRESULT STDMETHODCALLTYPE dxgi_device_CreateSurface(IWineDXGIDevice *iface,
175 const DXGI_SURFACE_DESC *desc, UINT surface_count, DXGI_USAGE usage,
176 const DXGI_SHARED_RESOURCE *shared_resource, IDXGISurface **surface)
178 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
179 struct wined3d_resource_desc surface_desc;
180 IWineDXGIDeviceParent *dxgi_device_parent;
181 HRESULT hr;
182 UINT i;
183 UINT j;
185 TRACE("iface %p, desc %p, surface_count %u, usage %#x, shared_resource %p, surface %p.\n",
186 iface, desc, surface_count, usage, shared_resource, surface);
188 hr = IWineDXGIDevice_QueryInterface(iface, &IID_IWineDXGIDeviceParent, (void **)&dxgi_device_parent);
189 if (FAILED(hr))
191 ERR("Device should implement IWineDXGIDeviceParent.\n");
192 return E_FAIL;
195 surface_desc.resource_type = WINED3D_RTYPE_TEXTURE_2D;
196 surface_desc.format = wined3dformat_from_dxgi_format(desc->Format);
197 wined3d_sample_desc_from_dxgi(&surface_desc.multisample_type,
198 &surface_desc.multisample_quality, &desc->SampleDesc);
199 surface_desc.bind_flags = wined3d_bind_flags_from_dxgi_usage(usage);
200 surface_desc.usage = 0;
201 surface_desc.access = WINED3D_RESOURCE_ACCESS_GPU;
202 surface_desc.width = desc->Width;
203 surface_desc.height = desc->Height;
204 surface_desc.depth = 1;
205 surface_desc.size = 0;
207 wined3d_mutex_lock();
208 memset(surface, 0, surface_count * sizeof(*surface));
209 for (i = 0; i < surface_count; ++i)
211 struct wined3d_texture *wined3d_texture;
213 if (FAILED(hr = wined3d_texture_create(device->wined3d_device, &surface_desc,
214 1, 1, 0, NULL, NULL, &dxgi_null_wined3d_parent_ops, &wined3d_texture)))
216 ERR("Failed to create wined3d texture, hr %#lx.\n", hr);
217 goto fail;
220 if (FAILED(hr = IWineDXGIDeviceParent_register_swapchain_texture(
221 dxgi_device_parent, wined3d_texture, 0, &surface[i])))
223 wined3d_texture_decref(wined3d_texture);
224 ERR("Failed to create parent swapchain texture, hr %#lx.\n", hr);
225 goto fail;
227 wined3d_texture_decref(wined3d_texture);
229 TRACE("Created IDXGISurface %p (%u/%u).\n", surface[i], i + 1, surface_count);
231 wined3d_mutex_unlock();
232 IWineDXGIDeviceParent_Release(dxgi_device_parent);
234 return S_OK;
236 fail:
237 wined3d_mutex_unlock();
238 for (j = 0; j < i; ++j)
240 IDXGISurface_Release(surface[i]);
242 IWineDXGIDeviceParent_Release(dxgi_device_parent);
243 return hr;
246 static HRESULT STDMETHODCALLTYPE dxgi_device_QueryResourceResidency(IWineDXGIDevice *iface,
247 IUnknown *const *resources, DXGI_RESIDENCY *residency, UINT resource_count)
249 FIXME("iface %p, resources %p, residency %p, resource_count %u stub!\n",
250 iface, resources, residency, resource_count);
252 return E_NOTIMPL;
255 static HRESULT STDMETHODCALLTYPE dxgi_device_SetGPUThreadPriority(IWineDXGIDevice *iface, INT priority)
257 FIXME("iface %p, priority %d stub!\n", iface, priority);
259 return E_NOTIMPL;
262 static HRESULT STDMETHODCALLTYPE dxgi_device_GetGPUThreadPriority(IWineDXGIDevice *iface, INT *priority)
264 FIXME("iface %p, priority %p stub!\n", iface, priority);
266 return E_NOTIMPL;
269 static HRESULT STDMETHODCALLTYPE dxgi_device_SetMaximumFrameLatency(IWineDXGIDevice *iface, UINT max_latency)
271 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
273 TRACE("iface %p, max_latency %u.\n", iface, max_latency);
275 if (max_latency > DXGI_FRAME_LATENCY_MAX)
276 return DXGI_ERROR_INVALID_CALL;
278 wined3d_mutex_lock();
279 wined3d_device_set_max_frame_latency(device->wined3d_device, max_latency);
280 wined3d_mutex_unlock();
282 return S_OK;
285 static HRESULT STDMETHODCALLTYPE dxgi_device_GetMaximumFrameLatency(IWineDXGIDevice *iface, UINT *max_latency)
287 struct dxgi_device *device = impl_from_IWineDXGIDevice(iface);
289 TRACE("iface %p, max_latency %p.\n", iface, max_latency);
291 if (!max_latency)
292 return DXGI_ERROR_INVALID_CALL;
294 wined3d_mutex_lock();
295 *max_latency = wined3d_device_get_max_frame_latency(device->wined3d_device);
296 wined3d_mutex_unlock();
298 return S_OK;
301 static HRESULT STDMETHODCALLTYPE dxgi_device_OfferResources(IWineDXGIDevice *iface, UINT resource_count,
302 IDXGIResource * const *resources, DXGI_OFFER_RESOURCE_PRIORITY priority)
304 FIXME("iface %p, resource_count %u, resources %p, priority %u stub!\n", iface, resource_count,
305 resources, priority);
307 return E_NOTIMPL;
310 static HRESULT STDMETHODCALLTYPE dxgi_device_ReclaimResources(IWineDXGIDevice *iface, UINT resource_count,
311 IDXGIResource * const *resources, BOOL *discarded)
313 FIXME("iface %p, resource_count %u, resources %p, discarded %p stub!\n", iface, resource_count,
314 resources, discarded);
316 return E_NOTIMPL;
319 static HRESULT STDMETHODCALLTYPE dxgi_device_EnqueueSetEvent(IWineDXGIDevice *iface, HANDLE event)
321 FIXME("iface %p, event %p stub!\n", iface, event);
323 return E_NOTIMPL;
326 static void STDMETHODCALLTYPE dxgi_device_Trim(IWineDXGIDevice *iface)
328 FIXME("iface %p stub!\n", iface);
331 /* IWineDXGIDevice methods */
333 static HRESULT STDMETHODCALLTYPE dxgi_device_create_resource(IWineDXGIDevice *iface,
334 struct wined3d_resource *wined3d_resource, DXGI_USAGE usage,
335 const DXGI_SHARED_RESOURCE *shared_resource, IUnknown *outer, BOOL needs_surface, void **resource)
337 struct dxgi_resource *object;
338 HRESULT hr;
340 TRACE("iface %p, wined3d_resource %p, usage %#x, shared_resource %p, outer %p, needs_surface %d, "
341 "resource %p.\n", iface, wined3d_resource, usage, shared_resource, outer, needs_surface,
342 resource);
344 if (!(object = heap_alloc_zero(sizeof(*object))))
346 ERR("Failed to allocate DXGI resource object memory.\n");
347 return E_OUTOFMEMORY;
350 if (FAILED(hr = dxgi_resource_init(object, (IDXGIDevice *)iface, outer, needs_surface, wined3d_resource)))
352 WARN("Failed to initialize resource, hr %#lx.\n", hr);
353 heap_free(object);
354 return hr;
357 TRACE("Created resource %p.\n", object);
358 *resource = outer ? &object->IUnknown_iface : (IUnknown *)&object->IDXGIResource_iface;
360 return S_OK;
363 static const struct IWineDXGIDeviceVtbl dxgi_device_vtbl =
365 /* IUnknown methods */
366 dxgi_device_QueryInterface,
367 dxgi_device_AddRef,
368 dxgi_device_Release,
369 /* IDXGIObject methods */
370 dxgi_device_SetPrivateData,
371 dxgi_device_SetPrivateDataInterface,
372 dxgi_device_GetPrivateData,
373 dxgi_device_GetParent,
374 /* IDXGIDevice methods */
375 dxgi_device_GetAdapter,
376 dxgi_device_CreateSurface,
377 dxgi_device_QueryResourceResidency,
378 dxgi_device_SetGPUThreadPriority,
379 dxgi_device_GetGPUThreadPriority,
380 /* IDXGIDevice1 methods */
381 dxgi_device_SetMaximumFrameLatency,
382 dxgi_device_GetMaximumFrameLatency,
383 /* IDXGIDevice2 methods */
384 dxgi_device_OfferResources,
385 dxgi_device_ReclaimResources,
386 dxgi_device_EnqueueSetEvent,
387 /* IDXGIDevice3 methods */
388 dxgi_device_Trim,
389 /* IWineDXGIDevice methods */
390 dxgi_device_create_resource,
393 static inline struct dxgi_device *impl_from_IWineDXGISwapChainFactory(IWineDXGISwapChainFactory *iface)
395 return CONTAINING_RECORD(iface, struct dxgi_device, IWineDXGISwapChainFactory_iface);
398 static HRESULT STDMETHODCALLTYPE dxgi_swapchain_factory_QueryInterface(IWineDXGISwapChainFactory *iface,
399 REFIID iid, void **out)
401 struct dxgi_device *device = impl_from_IWineDXGISwapChainFactory(iface);
403 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
405 return dxgi_device_QueryInterface(&device->IWineDXGIDevice_iface, iid, out);
408 static ULONG STDMETHODCALLTYPE dxgi_swapchain_factory_AddRef(IWineDXGISwapChainFactory *iface)
410 struct dxgi_device *device = impl_from_IWineDXGISwapChainFactory(iface);
412 TRACE("iface %p.\n", iface);
414 return dxgi_device_AddRef(&device->IWineDXGIDevice_iface);
417 static ULONG STDMETHODCALLTYPE dxgi_swapchain_factory_Release(IWineDXGISwapChainFactory *iface)
419 struct dxgi_device *device = impl_from_IWineDXGISwapChainFactory(iface);
421 TRACE("iface %p.\n", iface);
423 return dxgi_device_Release(&device->IWineDXGIDevice_iface);
426 static HRESULT STDMETHODCALLTYPE dxgi_swapchain_factory_create_swapchain(IWineDXGISwapChainFactory *iface,
427 IDXGIFactory *factory, HWND window, const DXGI_SWAP_CHAIN_DESC1 *desc,
428 const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, IDXGIOutput *output, IDXGISwapChain1 **swapchain)
430 struct dxgi_device *device = impl_from_IWineDXGISwapChainFactory(iface);
431 struct wined3d_swapchain_desc wined3d_desc;
432 struct IDXGIOutput *containing_output;
433 struct dxgi_factory *dxgi_factory;
434 struct d3d11_swapchain *object;
435 HRESULT hr;
437 TRACE("iface %p, factory %p, window %p, desc %p, fullscreen_desc %p, output %p, swapchain %p.\n",
438 iface, factory, window, desc, fullscreen_desc, output, swapchain);
440 if (!(dxgi_factory = unsafe_impl_from_IDXGIFactory(factory)))
442 WARN("Factory %p is not a valid dxgi factory.\n", factory);
443 return E_FAIL;
446 if (FAILED(hr = dxgi_get_output_from_window(&dxgi_factory->IWineDXGIFactory_iface, window, &containing_output)))
448 WARN("Failed to get output from window %p, hr %#lx.\n", window, hr);
449 return hr;
452 hr = wined3d_swapchain_desc_from_dxgi(&wined3d_desc, containing_output, window, desc,
453 fullscreen_desc);
454 IDXGIOutput_Release(containing_output);
455 if (FAILED(hr))
456 return hr;
458 if (!(object = heap_alloc_zero(sizeof(*object))))
460 ERR("Failed to allocate swapchain memory.\n");
461 return E_OUTOFMEMORY;
464 if (FAILED(hr = d3d11_swapchain_init(object, device, &wined3d_desc)))
466 WARN("Failed to initialise swapchain, hr %#lx.\n", hr);
467 heap_free(object);
468 return hr;
471 TRACE("Created swapchain %p.\n", object);
473 *swapchain = &object->IDXGISwapChain1_iface;
475 return S_OK;
478 static const struct IWineDXGISwapChainFactoryVtbl dxgi_swapchain_factory_vtbl =
480 dxgi_swapchain_factory_QueryInterface,
481 dxgi_swapchain_factory_AddRef,
482 dxgi_swapchain_factory_Release,
483 dxgi_swapchain_factory_create_swapchain,
486 HRESULT dxgi_device_init(struct dxgi_device *device, struct dxgi_device_layer *layer,
487 IDXGIFactory *factory, IDXGIAdapter *adapter,
488 const D3D_FEATURE_LEVEL *feature_levels, unsigned int level_count)
490 struct wined3d_device_parent *wined3d_device_parent;
491 struct wined3d_swapchain_desc swapchain_desc;
492 IWineDXGIDeviceParent *dxgi_device_parent;
493 struct dxgi_adapter *dxgi_adapter;
494 struct dxgi_factory *dxgi_factory;
495 struct dxgi_output *dxgi_output;
496 struct IDXGIOutput *output;
497 void *layer_base;
498 HWND window;
499 HRESULT hr;
501 if (!(dxgi_factory = unsafe_impl_from_IDXGIFactory(factory)))
503 WARN("This is not the factory we're looking for.\n");
504 return E_FAIL;
507 if (!(dxgi_adapter = unsafe_impl_from_IDXGIAdapter(adapter)))
509 WARN("This is not the adapter we're looking for.\n");
510 return E_FAIL;
513 device->IWineDXGIDevice_iface.lpVtbl = &dxgi_device_vtbl;
514 device->IWineDXGISwapChainFactory_iface.lpVtbl = &dxgi_swapchain_factory_vtbl;
515 device->refcount = 1;
516 wined3d_mutex_lock();
517 wined3d_private_store_init(&device->private_store);
519 layer_base = device + 1;
521 if (FAILED(hr = layer->create(layer->id, &layer_base, 0,
522 device, &IID_IUnknown, (void **)&device->child_layer)))
524 WARN("Failed to create device, returning %#lx.\n", hr);
525 wined3d_private_store_cleanup(&device->private_store);
526 wined3d_mutex_unlock();
527 return hr;
530 if (FAILED(hr = IWineDXGIDevice_QueryInterface(&device->IWineDXGIDevice_iface,
531 &IID_IWineDXGIDeviceParent, (void **)&dxgi_device_parent)))
533 ERR("DXGI device should implement IWineDXGIDeviceParent.\n");
534 IUnknown_Release(device->child_layer);
535 wined3d_private_store_cleanup(&device->private_store);
536 wined3d_mutex_unlock();
537 return hr;
539 wined3d_device_parent = IWineDXGIDeviceParent_get_wined3d_device_parent(dxgi_device_parent);
540 IWineDXGIDeviceParent_Release(dxgi_device_parent);
542 if (FAILED(hr = wined3d_device_create(dxgi_factory->wined3d,
543 dxgi_adapter->wined3d_adapter, WINED3D_DEVICE_TYPE_HAL, NULL, 0, 4,
544 (const enum wined3d_feature_level *)feature_levels, level_count,
545 wined3d_device_parent, &device->wined3d_device)))
547 WARN("Failed to create a wined3d device, returning %#lx.\n", hr);
548 IUnknown_Release(device->child_layer);
549 wined3d_private_store_cleanup(&device->private_store);
550 wined3d_mutex_unlock();
551 return hr;
554 window = dxgi_factory_get_device_window(dxgi_factory);
555 if (FAILED(hr = dxgi_get_output_from_window(&dxgi_factory->IWineDXGIFactory_iface, window, &output)))
557 ERR("Failed to get output from window %p.\n", window);
558 wined3d_device_decref(device->wined3d_device);
559 IUnknown_Release(device->child_layer);
560 wined3d_private_store_cleanup(&device->private_store);
561 wined3d_mutex_unlock();
562 return hr;
564 dxgi_output = unsafe_impl_from_IDXGIOutput(output);
566 memset(&swapchain_desc, 0, sizeof(swapchain_desc));
567 swapchain_desc.swap_effect = WINED3D_SWAP_EFFECT_DISCARD;
568 swapchain_desc.device_window = window;
569 swapchain_desc.windowed = TRUE;
570 swapchain_desc.flags = WINED3D_SWAPCHAIN_IMPLICIT;
571 swapchain_desc.output = dxgi_output->wined3d_output;
572 IDXGIOutput_Release(output);
574 if (FAILED(hr = wined3d_swapchain_create(device->wined3d_device, &swapchain_desc,
575 NULL, NULL, &dxgi_null_wined3d_parent_ops, &device->implicit_swapchain)))
577 ERR("Failed to create implicit swapchain, hr %#lx.\n", hr);
578 wined3d_device_decref(device->wined3d_device);
579 IUnknown_Release(device->child_layer);
580 wined3d_private_store_cleanup(&device->private_store);
581 wined3d_mutex_unlock();
582 return E_OUTOFMEMORY;
585 wined3d_mutex_unlock();
587 device->adapter = &dxgi_adapter->IWineDXGIAdapter_iface;
588 IWineDXGIAdapter_AddRef(device->adapter);
590 return S_OK;