dxgi_native.cpp revision 92617aeac109481258f0c3863d09c1b8903d438b
1/**************************************************************************
2 *
3 * Copyright 2010 Luca Barbieri
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27#include "dxgi_private.h"
28extern "C" {
29#include "native.h"
30#include <util/u_format.h>
31#include <util/u_inlines.h>
32#include <util/u_simple_shaders.h>
33#include <pipe/p_shader_tokens.h>
34}
35#include <iostream>
36#include <memory>
37
38struct GalliumDXGIOutput;
39struct GalliumDXGIAdapter;
40struct GalliumDXGISwapChain;
41struct GalliumDXGIFactory;
42
43static HRESULT GalliumDXGISwapChainCreate(GalliumDXGIFactory* factory, IUnknown* device, const DXGI_SWAP_CHAIN_DESC& desc, IDXGISwapChain** ppSwapChain);
44static HRESULT GalliumDXGIAdapterCreate(GalliumDXGIFactory* adapter, const struct native_platform* platform, void* dpy, IDXGIAdapter1** ppAdapter);
45static HRESULT GalliumDXGIOutputCreate(GalliumDXGIAdapter* adapter, const std::string& name, const struct native_connector* connector, IDXGIOutput** ppOutput);
46static void GalliumDXGISwapChainRevalidate(IDXGISwapChain* swap_chain);
47
48template<typename Base = IDXGIObject, typename Parent = IDXGIObject>
49struct GalliumDXGIObject : public GalliumPrivateDataComObject<Base>
50{
51	ComPtr<Parent> parent;
52
53	GalliumDXGIObject(Parent* p_parent = 0)
54	{
55		this->parent = p_parent;
56	}
57
58        virtual HRESULT STDMETHODCALLTYPE GetParent(
59            __in  REFIID riid,
60            __out  void **ppParent)
61        {
62        	return parent->QueryInterface(riid, ppParent);
63        }
64};
65
66static void* STDMETHODCALLTYPE identity_resolver(void* cookie, HWND hwnd)
67{
68	return (void*)hwnd;
69}
70
71struct GalliumDXGIFactory : public GalliumDXGIObject<IDXGIFactory1, IUnknown>
72{
73        HWND associated_window;
74	const struct native_platform* platform;
75	void* display;
76	PFNHWNDRESOLVER resolver;
77	void* resolver_cookie;
78
79        GalliumDXGIFactory(const struct native_platform* platform, void* display, PFNHWNDRESOLVER resolver, void* resolver_cookie)
80        : GalliumDXGIObject((IUnknown*)NULL), platform(platform), display(display), resolver(resolver ? resolver : identity_resolver), resolver_cookie(resolver_cookie)
81        {}
82
83        virtual HRESULT STDMETHODCALLTYPE EnumAdapters(
84        	UINT Adapter,
85        	__out  IDXGIAdapter **ppAdapter)
86	{
87		return EnumAdapters1(Adapter, (IDXGIAdapter1**)ppAdapter);
88	}
89
90        virtual HRESULT STDMETHODCALLTYPE EnumAdapters1(
91        	UINT Adapter,
92        	__out  IDXGIAdapter1 **ppAdapter)
93        {
94        	*ppAdapter = 0;
95		if(Adapter == 0)
96		{
97			return GalliumDXGIAdapterCreate(this, platform, display, ppAdapter);
98		}
99#if 0
100		// TODO: enable this
101        	if(platform == native_get_x11_platform())
102        	{
103        		unsigned nscreens = ScreenCount((Display*)display);
104        		if(Adapter < nscreens)
105        		{
106        			unsigned def_screen = DefaultScreen(display);
107        			if(Adapter <= def_screen)
108        				--Adapter;
109        			*ppAdapter = GalliumDXGIAdapterCreate(this, platform, display, Adapter);
110        			return S_OK;
111        		}
112        	}
113#endif
114		return DXGI_ERROR_NOT_FOUND;
115        }
116
117        /* TODO: this is a mysterious underdocumented magic API
118         * Can we have multiple windows associated?
119         * Can we have multiple windows associated if we use multiple factories?
120         * If so, what should GetWindowAssociation return?
121         * If not, does a new swapchain steal the association?
122         * Does this act for existing swapchains? For new swapchains?
123         */
124        virtual HRESULT STDMETHODCALLTYPE MakeWindowAssociation(
125        	HWND WindowHandle,
126        	UINT Flags)
127        {
128        	/* TODO: actually implement, for Wine, X11 and KMS*/
129        	associated_window = WindowHandle;
130        	return S_OK;
131        }
132
133        virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation(
134        	__out  HWND *pWindowHandle)
135        {
136        	*pWindowHandle = associated_window;
137        	return S_OK;
138        }
139
140        virtual HRESULT STDMETHODCALLTYPE CreateSwapChain(
141        	__in  IUnknown *pDevice,
142        	__in  DXGI_SWAP_CHAIN_DESC *pDesc,
143        	__out  IDXGISwapChain **ppSwapChain)
144        {
145        	return GalliumDXGISwapChainCreate(this, pDevice, *pDesc, ppSwapChain);
146        }
147
148        virtual HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter(
149            HMODULE Module,
150            __out  IDXGIAdapter **ppAdapter)
151        {
152        	/* TODO: ignore the module, and just create a Gallium software screen */
153        	*ppAdapter = 0;
154        	return E_NOTIMPL;
155        }
156
157        /* TODO: support hotplug */
158        virtual BOOL STDMETHODCALLTYPE IsCurrent( void)
159        {
160        	return TRUE;
161        }
162};
163
164struct GalliumDXGIAdapter
165	: public GalliumMultiComObject<
166		  GalliumDXGIObject<IDXGIAdapter1, GalliumDXGIFactory>,
167		  IGalliumAdapter>
168{
169	struct native_display* display;
170	const struct native_config** configs;
171	std::unordered_multimap<unsigned, unsigned> configs_by_pipe_format;
172	std::unordered_map<unsigned, unsigned> configs_by_native_visual_id;
173	const struct native_connector** connectors;
174	unsigned num_configs;
175	DXGI_ADAPTER_DESC1 desc;
176	std::vector<ComPtr<IDXGIOutput> > outputs;
177	int num_outputs;
178	struct native_event_handler handler;
179
180	GalliumDXGIAdapter(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy)
181	{
182		this->parent = factory;
183
184		handler.invalid_surface = handle_invalid_surface;
185		handler.new_drm_screen = dxgi_loader_create_drm_screen;
186		handler.new_sw_screen = dxgi_loader_create_sw_screen;
187		display = platform->create_display(dpy, &handler, this);
188		if(!display)
189			throw E_FAIL;
190		memset(&desc, 0, sizeof(desc));
191		std::string s = std::string("GalliumD3D on ") + display->screen->get_name(display->screen) + " by " + display->screen->get_vendor(display->screen);
192
193		/* hopefully no one will decide to use UTF-8 in Gallium name/vendor strings */
194		for(int i = 0; i < std::min((int)s.size(), 127); ++i)
195			desc.Description[i] = (WCHAR)s[i];
196
197		// TODO: add an interface to get these; for now, return mid/low values
198		desc.DedicatedVideoMemory = 256 << 20;
199		desc.DedicatedSystemMemory = 256 << 20;
200		desc.SharedSystemMemory = 1024 << 20;
201
202		// TODO: we should actually use an unique ID instead
203		*(void**)&desc.AdapterLuid = dpy;
204
205		configs = display->get_configs(display, (int*)&num_configs);
206		for(unsigned i = 0; i < num_configs; ++i)
207		{
208			if(configs[i]->window_bit)
209			{
210				configs_by_pipe_format.insert(std::make_pair(configs[i]->color_format, i));
211				configs_by_native_visual_id[configs[i]->native_visual_id] = i;
212			}
213		}
214
215		connectors = 0;
216		num_outputs = 0;
217
218		if(display->modeset)
219		{
220			int num_crtcs;
221
222			connectors = display->modeset->get_connectors(display, &num_outputs, &num_crtcs);
223			if(!connectors)
224				num_outputs = 0;
225			else if(!num_outputs)
226			{
227				free(connectors);
228				connectors = 0;
229			}
230		}
231		if(!num_outputs)
232			num_outputs = 1;
233	}
234
235	static void handle_invalid_surface(struct native_display *ndpy, struct native_surface *nsurf, unsigned int seq_num)
236	{
237		GalliumDXGISwapChainRevalidate((IDXGISwapChain*)nsurf->user_data);
238	}
239
240	~GalliumDXGIAdapter()
241	{
242		free(configs);
243		free(connectors);
244	}
245
246        virtual HRESULT STDMETHODCALLTYPE EnumOutputs(
247        	UINT Output,
248        	__out  IDXGIOutput **ppOutput)
249	{
250        	if(Output >= (unsigned)num_outputs)
251        		return DXGI_ERROR_NOT_FOUND;
252
253        	if(connectors)
254        	{
255        		std::ostringstream ss;
256        		ss << "Output #" << Output;
257			return GalliumDXGIOutputCreate(this, ss.str(), connectors[Output], ppOutput);
258        	}
259        	else
260        		return GalliumDXGIOutputCreate(this, "Unique output", NULL, ppOutput);
261	}
262
263        virtual HRESULT STDMETHODCALLTYPE GetDesc(
264        	__out  DXGI_ADAPTER_DESC *pDesc)
265        {
266        	memcpy(pDesc, &desc, sizeof(*pDesc));
267        	return S_OK;
268        }
269
270        virtual HRESULT STDMETHODCALLTYPE GetDesc1(
271        	__out  DXGI_ADAPTER_DESC1 *pDesc)
272        {
273        	memcpy(pDesc, &desc, sizeof(*pDesc));
274        	return S_OK;
275        }
276
277        virtual HRESULT STDMETHODCALLTYPE CheckInterfaceSupport(
278            __in  REFGUID InterfaceName,
279            __out  LARGE_INTEGER *pUMDVersion)
280        {
281        	// these number was taken from Windows 7 with Catalyst 10.8: its meaning is unclear
282        	if(InterfaceName == IID_ID3D11Device || InterfaceName == IID_ID3D10Device1 || InterfaceName == IID_ID3D10Device)
283        	{
284        		pUMDVersion->QuadPart = 0x00080011000a0411ULL;
285        		return S_OK;
286        	}
287        	return DXGI_ERROR_UNSUPPORTED;
288        }
289
290        pipe_screen* STDMETHODCALLTYPE GetGalliumScreen()
291        {
292        	return display->screen;
293        }
294
295        pipe_screen* STDMETHODCALLTYPE GetGalliumReferenceSoftwareScreen()
296        {
297        	// TODO: give a softpipe screen
298        	return display->screen;
299        }
300
301        pipe_screen* STDMETHODCALLTYPE GetGalliumFastSoftwareScreen()
302	{
303		// TODO: give an llvmpipe screen
304		return display->screen;
305	}
306};
307
308
309struct GalliumDXGIOutput : public GalliumDXGIObject<IDXGIOutput, GalliumDXGIAdapter>
310{
311	DXGI_OUTPUT_DESC desc;
312	const struct native_mode** modes;
313	DXGI_MODE_DESC* dxgi_modes;
314	unsigned num_modes;
315	const struct native_connector* connector;
316	DXGI_GAMMA_CONTROL* gamma;
317
318	GalliumDXGIOutput(GalliumDXGIAdapter* adapter, std::string name, const struct native_connector* connector = 0)
319	: GalliumDXGIObject(adapter), connector(connector)
320	{
321		memset(&desc, 0, sizeof(desc));
322		for(unsigned i = 0; i < std::min(name.size(), sizeof(desc.DeviceName) - 1); ++i)
323			desc.DeviceName[i] = name[i];
324		desc.AttachedToDesktop = TRUE;
325		/* TODO: should put an HMONITOR in desc.Monitor */
326
327		gamma = 0;
328		num_modes = 0;
329		modes = 0;
330		if(connector)
331		{
332			modes = parent->display->modeset->get_modes(parent->display, connector, (int*)&num_modes);
333			if(modes && num_modes)
334			{
335				dxgi_modes = new DXGI_MODE_DESC[num_modes];
336				for(unsigned i = 0; i < num_modes; ++i)
337				{
338					dxgi_modes[i].Width = modes[i]->width;
339					dxgi_modes[i].Height = modes[i]->height;
340					dxgi_modes[i].RefreshRate.Numerator = modes[i]->refresh_rate;
341					dxgi_modes[i].RefreshRate.Denominator = 1;
342					dxgi_modes[i].Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
343					dxgi_modes[i].ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
344				}
345			}
346			else
347			{
348				if(modes)
349				{
350					free(modes);
351					modes = 0;
352				}
353				goto use_fake_mode;
354			}
355		}
356		else
357		{
358use_fake_mode:
359			dxgi_modes = new DXGI_MODE_DESC[1];
360			dxgi_modes[0].Width = 1920;
361			dxgi_modes[0].Height = 1200;
362			dxgi_modes[0].RefreshRate.Numerator = 60;
363			dxgi_modes[0].RefreshRate.Denominator = 1;
364			dxgi_modes[0].Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
365			dxgi_modes[0].ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
366		}
367	}
368
369	~GalliumDXGIOutput()
370	{
371		delete [] dxgi_modes;
372		free(modes);
373		if(gamma)
374			delete gamma;
375	}
376
377	virtual HRESULT STDMETHODCALLTYPE GetDesc(
378		__out  DXGI_OUTPUT_DESC *pDesc)
379	{
380		*pDesc = desc;
381		return S_OK;
382	}
383
384	virtual HRESULT STDMETHODCALLTYPE GetDisplayModeList(
385		DXGI_FORMAT EnumFormat,
386		UINT Flags,
387		__inout  UINT *pNumModes,
388		__out_ecount_part_opt(*pNumModes,*pNumModes)  DXGI_MODE_DESC *pDesc)
389	{
390		/* TODO: should we return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE when we don't
391		 * support modesetting instead of fake modes?
392		 */
393		pipe_format format = dxgi_to_pipe_format[EnumFormat];
394		if(parent->configs_by_pipe_format.count(format))
395		{
396			if(!pDesc)
397			{
398				*pNumModes = num_modes;
399				return S_OK;
400			}
401
402			unsigned copy_modes = std::min(num_modes, *pNumModes);
403			for(unsigned i = 0; i < copy_modes; ++i)
404			{
405				pDesc[i] = dxgi_modes[i];
406				pDesc[i].Format = EnumFormat;
407			}
408			*pNumModes = num_modes;
409
410			if(copy_modes < num_modes)
411				return DXGI_ERROR_MORE_DATA;
412			else
413				return S_OK;
414		}
415		else
416		{
417			*pNumModes = 0;
418			return S_OK;
419		}
420	}
421
422	virtual HRESULT STDMETHODCALLTYPE FindClosestMatchingMode(
423		__in  const DXGI_MODE_DESC *pModeToMatch,
424		__out  DXGI_MODE_DESC *pClosestMatch,
425		__in_opt  IUnknown *pConcernedDevice)
426	{
427		/* TODO: actually implement this */
428		DXGI_FORMAT dxgi_format = pModeToMatch->Format;
429		enum pipe_format format = dxgi_to_pipe_format[dxgi_format];
430		init_pipe_to_dxgi_format();
431		if(!parent->configs_by_pipe_format.count(format))
432		{
433			if(!pConcernedDevice)
434				return E_FAIL;
435			else
436			{
437				format = parent->configs[0]->color_format;
438				dxgi_format = pipe_to_dxgi_format[format];
439			}
440		}
441
442		*pClosestMatch = dxgi_modes[0];
443		pClosestMatch->Format = dxgi_format;
444		return S_OK;
445	}
446
447	virtual HRESULT STDMETHODCALLTYPE WaitForVBlank( void)
448	{
449		return S_OK;
450	}
451
452	virtual HRESULT STDMETHODCALLTYPE TakeOwnership(
453		__in  IUnknown *pDevice,
454		BOOL Exclusive)
455	{
456		return S_OK;
457	}
458
459	virtual void STDMETHODCALLTYPE ReleaseOwnership( void)
460	{
461	}
462
463	virtual HRESULT STDMETHODCALLTYPE GetGammaControlCapabilities(
464		__out  DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps)
465	{
466		memset(pGammaCaps, 0, sizeof(*pGammaCaps));
467		return S_OK;
468	}
469
470	virtual HRESULT STDMETHODCALLTYPE SetGammaControl(
471			__in  const DXGI_GAMMA_CONTROL *pArray)
472	{
473		if(!gamma)
474			gamma = new DXGI_GAMMA_CONTROL;
475		*gamma = *pArray;
476		return S_OK;
477	}
478
479	virtual HRESULT STDMETHODCALLTYPE GetGammaControl(
480			__out  DXGI_GAMMA_CONTROL *pArray)
481	{
482		if(gamma)
483			*pArray = *gamma;
484		else
485		{
486			pArray->Scale.Red = 1;
487			pArray->Scale.Green = 1;
488			pArray->Scale.Blue = 1;
489			pArray->Offset.Red = 0;
490			pArray->Offset.Green = 0;
491			pArray->Offset.Blue = 0;
492			for(unsigned i = 0; i <= 1024; ++i)
493				pArray->GammaCurve[i].Red = pArray->GammaCurve[i].Green = pArray->GammaCurve[i].Blue = (float)i / 1024.0;
494		}
495		return S_OK;
496	}
497
498	virtual HRESULT STDMETHODCALLTYPE SetDisplaySurface(
499		__in  IDXGISurface *pScanoutSurface)
500	{
501		return E_NOTIMPL;
502	}
503
504	virtual HRESULT STDMETHODCALLTYPE GetDisplaySurfaceData(
505		__in  IDXGISurface *pDestination)
506	{
507		return E_NOTIMPL;
508	}
509
510	virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics(
511		__out  DXGI_FRAME_STATISTICS *pStats)
512	{
513		memset(pStats, 0, sizeof(*pStats));
514#ifdef _WIN32
515		QueryPerformanceCounter(&pStats->SyncQPCTime);
516#endif
517		return E_NOTIMPL;
518	}
519};
520
521/* Swap chain are rather complex, and Microsoft's documentation is rather
522 * lacking. As far as I know, this is the most thorough publicly available
523 * description of how swap chains work, based on multiple sources and
524 * experimentation.
525 *
526 * There are two modes (called "swap effects") that a swap chain can operate in:
527 * discard and sequential.
528 *
529 * In discard mode, things always look as if there is a single buffer, which
530 * you can get with GetBuffers(0).
531 * The 2D texture returned by GetBuffers(0) and can only be
532 * used as a render target view and for resource copies, since no CPU access
533 * flags are set and only the D3D11_BIND_RENDER_TARGET bind flag is set.
534 * On Present, it is copied to the actual display
535 * surface and the contents become undefined.
536 * D3D may internally use multiple buffers, but you can't observe this, except
537 * by looking at the buffer contents after Present (but those are undefined).
538 * If it uses multiple buffers internally, then it will normally use BufferCount buffers
539 * (this has latency implications).
540 * Discard mode seems to internally use a single buffer in windowed mode,
541 * even if DWM is enabled, and BufferCount buffers in fullscreen mode.
542 *
543 * In sequential mode, the runtime alllocates BufferCount buffers.
544 * You can get each with GetBuffers(n).
545 * GetBuffers(0) ALWAYS points to the backbuffer to be presented and has the
546 * same usage constraints as the discard mode.
547 * GetBuffer(n) with n > 0 points to resources that are identical to buffer 0, but
548 * are classified as "read-only resources" (due to DXGI_USAGE_READ_ONLY),
549 * meaning that you can't create render target views on them, or use them as
550 * a CopyResource/CopySubresourceRegion  destination.
551 * It appears the only valid operation is to use them as a source for CopyResource
552 * and CopySubresourceRegion as well as just waiting for them to become
553 * buffer 0 again.
554 * Buffer n - 1 is always displayed on screen.
555 * When you call Present(), the contents of the buffers are rotated, so that buffer 0
556 * goes to buffer n - 1, and is thus displayed, and buffer 1 goes to buffer 0, becomes
557 * the accessible back buffer.
558 * The resources themselves are NOT rotated, so that you can still render on the
559 * same ID3D11Texture2D*, and views based on it, that you got before Present().
560 *
561 * Present seems to happen by either copying the relevant buffer into the window,
562 * or alternatively making it the current one, either by programming the CRTC or
563 * by sending the resource name to the DWM compositor.
564 *
565 * Hence, you can call GetBuffer(0) once and keep using the same ID3D11Texture2D*
566 * and ID3D11RenderTargetView* (and other views if needed) you got from it.
567 *
568 * If the window gets resized, DXGI will then "emulate" all successive presentations,
569 * by using a stretched blit automatically.
570 * Thus, you should handle WM_SIZE and call ResizeBuffers to update the DXGI
571 * swapchain buffers size to the new window size.
572 * Doing so requires you to release all GetBuffers() results and anything referencing
573 * them, including views and Direct3D11 deferred context command lists (this is
574 * documented).
575 *
576 * How does Microsoft implement the rotation behavior?
577 * It turns out that it does it by calling RotateResourceIdentitiesDXGI in the user-mode
578 * DDI driver.
579 * This will rotate the kernel buffer handle, or possibly rotate the GPU virtual memory
580 * mappings.
581 *
582 * The reason this is done by driver instead of by the runtime appears to be that
583 * this is necessary to support driver-provided command list support, since otherwise
584 * the command list would not always target the current backbuffer, since it would
585 * be done at the driver level, while only the runtime knows about the rotation.
586 *
587 * OK, so how do we implement this in Gallium?
588 *
589 * There are three strategies:
590 * 1. Use a single buffer, and always copy it to a window system provided buffer, or
591 *    just give the buffer to the window system if it supports that
592 * 2. Rotate the buffers in the D3D1x implementation, and recreate and rebind the views.
593 *     Don't support driver-provided command lists
594 * 3. Add this rotation functionality to the Gallium driver, with the idea that it would rotate
595 *    remap GPU virtual memory, so that virtual address are unchanged, but the physical
596 *    ones are rotated (so that pushbuffers remain valid).
597 *    If the driver does not support this, either fall back to (1), or have a layer doing this,
598 *    putting a deferred context layer over this intermediate layer.
599 *
600 * (2) is not acceptable since it prevents an optimal implementation.
601 *  (3) is the ideal solution, but it is complicated.
602 *
603 * Hence, we implement (1) for now, and will switch to (3) later.
604 *
605 * Note that (1) doesn't really work for DXGI_SWAP_EFFECT_SEQUENTIAL with more
606 * than one buffer, so we just pretend we got asked for a single buffer in that case
607 * Fortunately, no one seems to rely on that, so we'll just not implement it at first, and
608 * later perform the rotation with blits.
609 * Once we switch to (3), we'll just use real rotation to do it..
610 *
611 * DXGI_SWAP_EFFECT_SEQUENTIAL with more than one buffer is of dubious use
612 * anyway, since you can only render or write to buffer 0, and other buffers can apparently
613 * be used only as sources for copies.
614 * I was unable to find any code using it either in DirectX SDK examples, or on the web.
615 *
616 * It seems the only reason you would use it is to not have to redraw from scratch, while
617 * also possibly avoid a copy compared to BufferCount == 1, assuming that your
618 * application is OK with having to redraw starting not from the last frame, but from
619 * one/two/more frames behind it.
620 *
621 * A better design would forbid the user specifying BufferCount explicitly, and
622 * would instead let the application give an upper bound on how old the buffer can
623 * become after presentation, with "infinite" being equivalent to discard.
624 * The runtime would then tell the application with frame number the buffer switched to
625 * after present.
626 * In addition, in a better design, the application would be allowed to specify the
627 * number of buffers available, having all them usable for rendering, so that things
628 * like video players could efficiently decode frames in parallel.
629 * Present would in such a better design gain a way to specify the number of buffers
630 * to present.
631 *
632 * Other miscellaneous info:
633 * DXGI_PRESENT_DO_NOT_SEQUENCE causes DXGI to hold the frame for another
634 * vblank interval without rotating the resource data.
635 *
636 * References:
637 * "DXGI Overview" in MSDN
638 * IDXGISwapChain documentation on MSDN
639 * "RotateResourceIdentitiesDXGI" on MSDN
640 * http://forums.xna.com/forums/p/42362/266016.aspx
641 */
642
643static float quad_data[] = {
644	-1, -1, 0, 0,
645	-1, 1, 0, 1,
646	1, 1, 1, 1,
647	1, -1, 1, 0,
648};
649
650struct dxgi_blitter
651{
652	pipe_context* pipe;
653	bool normalized;
654	void* fs;
655	void* vs;
656	void* sampler[2];
657	void* elements;
658	void* blend;
659	void* rasterizer;
660	void* zsa;
661	struct pipe_clip_state clip;
662	struct pipe_vertex_buffer vbuf;
663	struct pipe_draw_info draw;
664
665	dxgi_blitter(pipe_context* pipe)
666	: pipe(pipe)
667	{
668		//normalized = !!pipe->screen->get_param(pipe, PIPE_CAP_NPOT_TEXTURES);
669		// TODO: need to update buffer in unnormalized case
670		normalized = true;
671
672		struct pipe_rasterizer_state rs_state;
673		memset(&rs_state, 0, sizeof(rs_state));
674		rs_state.cull_face = PIPE_FACE_NONE;
675		rs_state.gl_rasterization_rules = 1;
676		rs_state.flatshade = 1;
677		rasterizer = pipe->create_rasterizer_state(pipe, &rs_state);
678
679		struct pipe_blend_state blendd;
680		blendd.rt[0].colormask = PIPE_MASK_RGBA;
681		blend = pipe->create_blend_state(pipe, &blendd);
682
683		struct pipe_depth_stencil_alpha_state zsad;
684		memset(&zsad, 0, sizeof(zsad));
685		zsa = pipe->create_depth_stencil_alpha_state(pipe, &zsad);
686
687		struct pipe_vertex_element velem[2];
688		memset(&velem[0], 0, sizeof(velem[0]) * 2);
689		velem[0].src_offset = 0;
690		velem[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
691		velem[1].src_offset = 8;
692		velem[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
693		elements = pipe->create_vertex_elements_state(pipe, 2, &velem[0]);
694
695		for(unsigned stretch = 0; stretch < 2; ++stretch)
696		{
697			struct pipe_sampler_state sampler_state;
698			memset(&sampler_state, 0, sizeof(sampler_state));
699			sampler_state.min_img_filter = stretch ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
700			sampler_state.mag_img_filter = stretch ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
701			sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
702			sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
703			sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
704			sampler_state.normalized_coords = normalized;
705
706			sampler[stretch] = pipe->create_sampler_state(pipe, &sampler_state);
707		}
708
709		fs = util_make_fragment_tex_shader(pipe, normalized ? TGSI_TEXTURE_2D : TGSI_TEXTURE_RECT, TGSI_INTERPOLATE_LINEAR);
710
711		const unsigned semantic_names[] = { TGSI_SEMANTIC_POSITION, TGSI_SEMANTIC_GENERIC };
712		const unsigned semantic_indices[] = { 0, 0 };
713		vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names, semantic_indices);
714
715		vbuf.buffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER, sizeof(quad_data));
716		vbuf.buffer_offset = 0;
717		vbuf.max_index = ~0;
718		vbuf.stride = 4 * sizeof(float);
719		pipe_buffer_write(pipe, vbuf.buffer, 0, sizeof(quad_data), quad_data);
720
721		memset(&clip, 0, sizeof(clip));
722
723		memset(&draw, 0, sizeof(draw));
724		draw.mode = PIPE_PRIM_QUADS;
725		draw.count = 4;
726		draw.instance_count = 1;
727		draw.max_index = ~0;
728	}
729
730	void blit(struct pipe_surface* surf, struct pipe_sampler_view* view, unsigned x, unsigned y, unsigned w, unsigned h)
731	{
732		struct pipe_framebuffer_state fb;
733		memset(&fb, 0, sizeof(fb));
734		fb.nr_cbufs = 1;
735		fb.cbufs[0] = surf;
736		fb.width = surf->width;
737		fb.height = surf->height;
738
739		struct pipe_viewport_state viewport;
740		float half_width = w * 0.5f;
741		float half_height = h * 0.5f;
742		viewport.scale[0] = half_width;
743		viewport.scale[1] = half_height;
744		viewport.scale[2] = 1.0f;
745		viewport.scale[3] = 1.0f;
746		viewport.translate[0] = x + half_width;
747		viewport.translate[1] = y + half_height;
748		viewport.translate[2] = 0.0f;
749		viewport.translate[3] = 1.0f;
750
751		bool stretch = view->texture->width0 != w || view->texture->height0 != h;
752		if(pipe->render_condition)
753			pipe->render_condition(pipe, 0, 0);
754		pipe->set_framebuffer_state(pipe, &fb);
755		pipe->bind_fragment_sampler_states(pipe, 1, &sampler[stretch]);
756		pipe->set_viewport_state(pipe, &viewport);
757		pipe->set_clip_state(pipe, &clip);
758		pipe->bind_rasterizer_state(pipe, rasterizer);
759		pipe->bind_depth_stencil_alpha_state(pipe, zsa);
760		pipe->bind_blend_state(pipe, blend);
761		pipe->bind_vertex_elements_state(pipe, elements);
762		pipe->set_vertex_buffers(pipe, 1, &vbuf);
763		pipe->bind_fs_state(pipe, fs);
764		pipe->bind_vs_state(pipe, vs);
765		if(pipe->bind_gs_state)
766			pipe->bind_gs_state(pipe, 0);
767		if(pipe->bind_stream_output_state)
768			pipe->bind_stream_output_state(pipe, 0);
769		pipe->set_fragment_sampler_views(pipe, 1, &view);
770
771		pipe->draw_vbo(pipe, &draw);
772	}
773
774	~dxgi_blitter()
775	{
776		pipe->delete_blend_state(pipe, blend);
777		pipe->delete_rasterizer_state(pipe, rasterizer);
778		pipe->delete_depth_stencil_alpha_state(pipe, zsa);
779		pipe->delete_sampler_state(pipe, sampler[0]);
780		pipe->delete_sampler_state(pipe, sampler[1]);
781		pipe->delete_vertex_elements_state(pipe, elements);
782		pipe->delete_vs_state(pipe, vs);
783		pipe->delete_fs_state(pipe, fs);
784		pipe->screen->resource_destroy(pipe->screen, vbuf.buffer);
785	}
786};
787
788struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory>
789{
790	ComPtr<IDXGIDevice>dxgi_device;
791	ComPtr<IGalliumDevice>gallium_device;
792	ComPtr<GalliumDXGIAdapter> adapter;
793	ComPtr<IDXGIOutput> target;
794
795	struct native_surface* surface;
796	const struct native_config* config;
797
798	struct pipe_resource* resources[NUM_NATIVE_ATTACHMENTS];
799	int width;
800	int height;
801	unsigned seq_num;
802	bool ever_validated;
803	bool needs_validation;
804	unsigned present_count;
805
806	ComPtr<IDXGISurface> buffer0;
807	struct pipe_resource* gallium_buffer0;
808	struct pipe_sampler_view* gallium_buffer0_view;
809
810	DXGI_SWAP_CHAIN_DESC desc;
811
812	struct pipe_context* pipe;
813	bool owns_pipe;
814
815	BOOL fullscreen;
816
817	std::auto_ptr<dxgi_blitter> blitter;
818	bool formats_compatible;
819
820	GalliumDXGISwapChain(GalliumDXGIFactory* factory, IUnknown* p_device, const DXGI_SWAP_CHAIN_DESC& p_desc)
821	: GalliumDXGIObject(factory), desc(p_desc)
822	{
823		HRESULT hr;
824
825		hr = p_device->QueryInterface(IID_IGalliumDevice, (void**)&gallium_device);
826		if(!SUCCEEDED(hr))
827			throw hr;
828
829		hr = p_device->QueryInterface(IID_IDXGIDevice, (void**)&dxgi_device);
830		if(!SUCCEEDED(hr))
831			throw hr;
832
833		hr = dxgi_device->GetAdapter((IDXGIAdapter**)&adapter);
834		if(!SUCCEEDED(hr))
835			throw hr;
836
837		void* win = factory->resolver(factory->resolver_cookie, desc.OutputWindow);
838
839		unsigned config_num;
840		if(!strcmp(factory->platform->name, "X11"))
841		{
842			XWindowAttributes xwa;
843			XGetWindowAttributes((Display*)factory->display, (Window)win, &xwa);
844			config_num = adapter->configs_by_native_visual_id[xwa.visual->visualid];
845		}
846		else
847		{
848			enum pipe_format format = dxgi_to_pipe_format[desc.BufferDesc.Format];
849			if(!adapter->configs_by_pipe_format.count(format))
850			{
851				if(adapter->configs_by_pipe_format.empty())
852					throw E_FAIL;
853				// TODO: choose the best match
854				format = (pipe_format)adapter->configs_by_pipe_format.begin()->first;
855			}
856			// TODO: choose the best config
857			config_num = adapter->configs_by_pipe_format.find(format)->second;
858		}
859
860		config = adapter->configs[config_num];
861		surface = adapter->display->create_window_surface(adapter->display, (EGLNativeWindowType)win, config);
862		surface->user_data = this;
863
864		width = 0;
865		height = 0;
866		seq_num = 0;
867		present_count = 0;
868		needs_validation = true;
869		ever_validated = false;
870
871		if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL && desc.BufferCount != 1)
872		{
873			std::cerr << "Gallium DXGI: if DXGI_SWAP_EFFECT_SEQUENTIAL is specified, only BufferCount == 1 is implemented, but " << desc.BufferCount  << " was specified: ignoring this" << std::endl;
874			// change the returned desc, so that the application might perhaps notice what we did and react well
875			desc.BufferCount = 1;
876		}
877
878		pipe = gallium_device->GetGalliumContext();
879		owns_pipe = false;
880		if(!pipe)
881		{
882			pipe = adapter->display->screen->context_create(adapter->display->screen, 0);
883			owns_pipe = true;
884		}
885
886		blitter.reset(new dxgi_blitter(pipe));
887
888		formats_compatible = util_is_format_compatible(
889				util_format_description(dxgi_to_pipe_format[desc.BufferDesc.Format]),
890				util_format_description(config->color_format));
891	}
892
893	~GalliumDXGISwapChain()
894	{
895		if(owns_pipe)
896			pipe->destroy(pipe);
897	}
898
899        virtual HRESULT STDMETHODCALLTYPE GetDevice(
900            __in  REFIID riid,
901            __out  void **ppDevice)
902        {
903        	return dxgi_device->QueryInterface(riid, ppDevice);
904        }
905
906        HRESULT create_buffer0()
907        {
908        	HRESULT hr;
909		ComPtr<IDXGISurface> new_buffer0;
910		DXGI_USAGE usage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT;
911		if(desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD)
912			usage |= DXGI_USAGE_DISCARD_ON_PRESENT;
913		// for our blitter
914		usage |= DXGI_USAGE_SHADER_INPUT;
915
916		DXGI_SURFACE_DESC surface_desc;
917		surface_desc.Format = desc.BufferDesc.Format;
918		surface_desc.Width = desc.BufferDesc.Width;
919		surface_desc.Height = desc.BufferDesc.Height;
920		surface_desc.SampleDesc = desc.SampleDesc;
921		hr = dxgi_device->CreateSurface(&surface_desc, 1, usage, 0, &new_buffer0);
922		if(!SUCCEEDED(hr))
923			return hr;
924
925		ComPtr<IGalliumResource> gallium_resource;
926		hr = new_buffer0->QueryInterface(IID_IGalliumResource, (void**)&gallium_resource);
927		if(!SUCCEEDED(hr))
928			return hr;
929
930		struct pipe_resource* new_gallium_buffer0 = gallium_resource->GetGalliumResource();
931		if(!new_gallium_buffer0)
932			return E_FAIL;
933
934		buffer0.reset(new_buffer0.steal());
935		gallium_buffer0 = new_gallium_buffer0;
936		struct pipe_sampler_view templat;
937		memset(&templat, 0, sizeof(templat));
938		templat.texture = gallium_buffer0;
939		templat.swizzle_r = 0;
940		templat.swizzle_g = 1;
941		templat.swizzle_b = 2;
942		templat.swizzle_a = 3;
943		templat.format = gallium_buffer0->format;
944		gallium_buffer0_view = pipe->create_sampler_view(pipe, gallium_buffer0, &templat);
945		return S_OK;
946        }
947
948	bool validate()
949	{
950		unsigned new_seq_num;
951		needs_validation = false;
952
953		if(!surface->validate(surface, 1 << NATIVE_ATTACHMENT_BACK_LEFT, &new_seq_num, resources, &width, &height))
954			return false;
955
956		if(!ever_validated || seq_num != new_seq_num)
957		{
958			seq_num = new_seq_num;
959			ever_validated = true;
960		}
961		return true;
962	}
963
964	virtual HRESULT STDMETHODCALLTYPE Present(
965		UINT SyncInterval,
966		UINT Flags)
967	{
968		if(Flags & DXGI_PRESENT_TEST)
969			return S_OK;
970
971		if(!buffer0)
972		{
973			HRESULT hr = create_buffer0();
974			if(!SUCCEEDED(hr))
975				return hr;
976		}
977
978		if(needs_validation)
979		{
980			if(!validate())
981				return DXGI_ERROR_DEVICE_REMOVED;
982		}
983
984		bool db = !!(config->buffer_mask & NATIVE_ATTACHMENT_BACK_LEFT);
985		struct pipe_resource* dst = resources[db ? NATIVE_ATTACHMENT_BACK_LEFT : NATIVE_ATTACHMENT_FRONT_LEFT];
986		struct pipe_resource* src = gallium_buffer0;
987		struct pipe_surface* dst_surface = 0;
988
989		/* TODO: sharing the context for blitting won't work correctly if queries are active
990		 * Hopefully no one is crazy enough to keep queries active while presenting, expecting
991		 * sensible results.
992		 * We could alternatively force using another context, but that might cause inefficiency issues
993		 */
994
995		/* Windows DXGI does not scale in an aspect-preserving way, but we do this
996		 * by default, since we can and it's usually what you want
997		 */
998		unsigned blit_x, blit_y, blit_w, blit_h;
999		float black[4] = {0, 0, 0, 0};
1000
1001		if(!formats_compatible || src->width0 != dst->width0 || dst->width0 != src->width0)
1002			dst_surface = pipe->screen->get_tex_surface(pipe->screen, dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET);
1003
1004		int delta = src->width0 * dst->height0 - dst->width0 * src->height0;
1005		if(delta > 0)
1006		{
1007			blit_w = dst->width0;
1008			blit_h = dst->width0 * src->height0 / src->width0;
1009		}
1010		else if(delta < 0)
1011		{
1012			blit_w = dst->height0 * src->width0 / src->height0;
1013			blit_h = dst->height0;
1014		}
1015		else
1016		{
1017			blit_w = dst->width0;
1018			blit_h = dst->height0;
1019		}
1020
1021		blit_x = (dst->width0 - blit_w) >> 1;
1022		blit_y = (dst->height0 - blit_h) >> 1;
1023
1024		if(blit_x)
1025			pipe->clear_render_target(pipe, dst_surface, black, 0, 0, blit_x, dst->height0);
1026		if(blit_y)
1027			pipe->clear_render_target(pipe, dst_surface, black, 0, 0, dst->width0, blit_y);
1028
1029		if(formats_compatible && blit_w == src->width0 && blit_h == src->height0)
1030		{
1031			pipe_subresource sr;
1032			sr.face = 0;
1033			sr.level = 0;
1034			pipe->resource_copy_region(pipe, dst, sr, 0, 0, 0, src, sr, 0, 0, 0, blit_w, blit_h);
1035		}
1036		else
1037		{
1038			blitter->blit(dst_surface, gallium_buffer0_view, blit_x, blit_y, blit_w, blit_h);
1039			if(!owns_pipe)
1040				gallium_device->RestoreGalliumState();
1041		}
1042
1043		if(blit_w != dst->width0)
1044			pipe->clear_render_target(pipe, dst_surface, black, blit_x + blit_w, 0, dst->width0 - blit_x - blit_w, dst->height0);
1045		if(blit_h != dst->height0)
1046			pipe->clear_render_target(pipe, dst_surface, black, 0, blit_y + blit_h, dst->width0, dst->height0 - blit_y - blit_h);
1047
1048		if(dst_surface)
1049			pipe->screen->tex_surface_destroy(dst_surface);
1050
1051		if(db)
1052		{
1053			if(!surface->swap_buffers(surface))
1054				return DXGI_ERROR_DEVICE_REMOVED;
1055		}
1056		else
1057		{
1058			if(!surface->flush_frontbuffer(surface))
1059				return DXGI_ERROR_DEVICE_REMOVED;
1060		}
1061
1062		++present_count;
1063		return S_OK;
1064	}
1065
1066	virtual HRESULT STDMETHODCALLTYPE GetBuffer(
1067		    UINT Buffer,
1068		    __in  REFIID riid,
1069		    __out  void **ppSurface)
1070	{
1071		if(Buffer > 0)
1072		{
1073			if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL)
1074				std::cerr << "DXGI unimplemented: GetBuffer(n) with n > 0 not supported, returning buffer 0 instead!" << std::endl;
1075			else
1076				std::cerr << "DXGI error: in GetBuffer(n), n must be 0 for DXGI_SWAP_EFFECT_DISCARD\n" << std::endl;
1077		}
1078
1079		if(!buffer0)
1080		{
1081			HRESULT hr = create_buffer0();
1082			if(!SUCCEEDED(hr))
1083				return hr;
1084		}
1085		return buffer0->QueryInterface(riid, ppSurface);
1086	}
1087
1088	/* TODO: implement somehow */
1089	virtual HRESULT STDMETHODCALLTYPE SetFullscreenState(
1090		BOOL Fullscreen,
1091		__in_opt  IDXGIOutput *pTarget)
1092	{
1093		fullscreen = Fullscreen;
1094		target = pTarget;
1095		return S_OK;
1096	}
1097
1098	virtual HRESULT STDMETHODCALLTYPE GetFullscreenState(
1099		__out  BOOL *pFullscreen,
1100		__out  IDXGIOutput **ppTarget)
1101	{
1102		if(pFullscreen)
1103			*pFullscreen = fullscreen;
1104		if(ppTarget)
1105			*ppTarget = target.ref();
1106		return S_OK;
1107	}
1108
1109	virtual HRESULT STDMETHODCALLTYPE GetDesc(
1110		__out  DXGI_SWAP_CHAIN_DESC *pDesc)
1111	{
1112		*pDesc = desc;
1113		return S_OK;
1114	}
1115
1116	virtual HRESULT STDMETHODCALLTYPE ResizeBuffers(
1117		UINT BufferCount,
1118		UINT Width,
1119		UINT Height,
1120		DXGI_FORMAT NewFormat,
1121		UINT SwapChainFlags)
1122	{
1123		if(buffer0)
1124		{
1125			buffer0.p->AddRef();
1126			ULONG v = buffer0.p->Release();
1127			// we must fail if there are any references to buffer0 other than ours
1128			if(v > 1)
1129				return E_FAIL;
1130			pipe_sampler_view_reference(&gallium_buffer0_view, 0);
1131			buffer0 = (IUnknown*)NULL;
1132			gallium_buffer0 = 0;
1133		}
1134
1135		if(desc.SwapEffect != DXGI_SWAP_EFFECT_SEQUENTIAL)
1136			desc.BufferCount = BufferCount;
1137		desc.BufferDesc.Format = NewFormat;
1138		desc.BufferDesc.Width = Width;
1139		desc.BufferDesc.Height = Height;
1140		desc.Flags = SwapChainFlags;
1141		return S_OK;
1142	}
1143
1144	virtual HRESULT STDMETHODCALLTYPE ResizeTarget(
1145		const DXGI_MODE_DESC *pNewTargetParameters)
1146	{
1147		/* TODO: implement */
1148		return S_OK;
1149	}
1150
1151	virtual HRESULT STDMETHODCALLTYPE GetContainingOutput(
1152			__out  IDXGIOutput **ppOutput)
1153	{
1154		*ppOutput = adapter->outputs[0].ref();
1155		return S_OK;
1156	}
1157
1158	virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics(
1159			__out  DXGI_FRAME_STATISTICS *pStats)
1160	{
1161		memset(pStats, 0, sizeof(*pStats));
1162#ifdef _WIN32
1163		QueryPerformanceCounter(&pStats->SyncQPCTime);
1164#endif
1165		pStats->PresentCount = present_count;
1166		pStats->PresentRefreshCount = present_count;
1167		pStats->SyncRefreshCount = present_count;
1168		return S_OK;
1169	}
1170
1171	virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(
1172		__out  UINT *pLastPresentCount)
1173	{
1174		*pLastPresentCount = present_count;
1175		return S_OK;
1176	}
1177};
1178
1179static void GalliumDXGISwapChainRevalidate(IDXGISwapChain* swap_chain)
1180{
1181	((GalliumDXGISwapChain*)swap_chain)->needs_validation = true;
1182}
1183
1184static HRESULT GalliumDXGIAdapterCreate(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy, IDXGIAdapter1** pAdapter)
1185{
1186	try
1187	{
1188		*pAdapter = new GalliumDXGIAdapter(factory, platform, dpy);
1189		return S_OK;
1190	}
1191	catch(HRESULT hr)
1192	{
1193		return hr;
1194	}
1195}
1196
1197static HRESULT GalliumDXGIOutputCreate(GalliumDXGIAdapter* adapter, const std::string& name, const struct native_connector* connector, IDXGIOutput** pOutput)
1198{
1199	try
1200	{
1201		*pOutput = new GalliumDXGIOutput(adapter, name, connector);
1202		return S_OK;
1203	}
1204	catch(HRESULT hr)
1205	{
1206		return hr;
1207	}
1208}
1209
1210static HRESULT GalliumDXGISwapChainCreate(GalliumDXGIFactory* factory, IUnknown* device, const DXGI_SWAP_CHAIN_DESC& desc, IDXGISwapChain** pSwapChain)
1211{
1212	try
1213	{
1214		*pSwapChain = new GalliumDXGISwapChain(factory, device, desc);
1215		return S_OK;
1216	}
1217	catch(HRESULT hr)
1218	{
1219		return hr;
1220	}
1221}
1222
1223struct dxgi_binding
1224{
1225	const struct native_platform* platform;
1226	void* display;
1227	PFNHWNDRESOLVER resolver;
1228	void* resolver_cookie;
1229};
1230
1231static dxgi_binding dxgi_default_binding;
1232static __thread dxgi_binding dxgi_thread_binding;
1233
1234void STDMETHODCALLTYPE GalliumDXGIUseNothing()
1235{
1236	dxgi_thread_binding.platform = 0;
1237	dxgi_thread_binding.display = 0;
1238	dxgi_thread_binding.resolver = 0;
1239	dxgi_thread_binding.resolver_cookie = 0;
1240}
1241
1242#ifdef GALLIUM_DXGI_USE_X11
1243void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, PFNHWNDRESOLVER resolver, void* resolver_cookie)
1244{
1245	dxgi_thread_binding.platform = native_get_x11_platform();
1246	dxgi_thread_binding.display = dpy;
1247	dxgi_thread_binding.resolver = resolver;
1248	dxgi_thread_binding.resolver_cookie = resolver_cookie;
1249}
1250#endif
1251
1252#ifdef GALLIUM_DXGI_USE_DRM
1253void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd)
1254{
1255	dxgi_thread_binding.platform = native_get_drm_platform();
1256	dxgi_thread_binding.display = (void*)fd;
1257	dxgi_thread_binding.resolver = 0;
1258	dxgi_thread_binding.resolver_cookie = 0;
1259}
1260#endif
1261
1262#ifdef GALLIUM_DXGI_USE_FBDEV
1263void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd)
1264{
1265	dxgi_thread_binding.platform = native_get_fbdev_platform();
1266	dxgi_thread_binding.display = (void*)fd;
1267	dxgi_thread_binding.resolver = 0;
1268	dxgi_thread_binding.resolver_cookie = 0;
1269}
1270#endif
1271
1272#ifdef GALLIUM_DXGI_USE_GDI
1273void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie)
1274{
1275	dxgi_thread_binding.platform = native_get_gdi_platform();
1276	dxgi_thread_binding.display = (void*)hdc;
1277	dxgi_thread_binding.resolver = resolver;
1278	dxgi_thread_binding.resolver_cookie = resolver_cookie;
1279}
1280#endif
1281
1282void STDMETHODCALLTYPE GalliumDXGIMakeDefault()
1283{
1284	dxgi_default_binding = dxgi_thread_binding;
1285}
1286
1287 /* TODO: why did Microsoft add this? should we do something different for DXGI 1.0 and 1.1?
1288  * Or perhaps what they actually mean is "only create a single factory in your application"?
1289  * TODO: should we use a singleton here, so we never have multiple DXGI objects for the same thing? */
1290 HRESULT STDMETHODCALLTYPE  CreateDXGIFactory1(
1291		__in   REFIID riid,
1292		__out  void **ppFactory
1293)
1294 {
1295	 GalliumDXGIFactory* factory;
1296	 *ppFactory = 0;
1297	 if(dxgi_thread_binding.platform)
1298		 factory = new GalliumDXGIFactory(dxgi_thread_binding.platform, dxgi_thread_binding.display, dxgi_thread_binding.resolver, dxgi_thread_binding.resolver_cookie);
1299	 else if(dxgi_default_binding.platform)
1300		 factory = new GalliumDXGIFactory(dxgi_default_binding.platform, dxgi_default_binding.display, dxgi_default_binding.resolver, dxgi_default_binding.resolver_cookie);
1301	 else
1302		 factory = new GalliumDXGIFactory(native_get_x11_platform(), NULL, NULL, NULL);
1303	 HRESULT hres = factory->QueryInterface(riid, ppFactory);
1304	 factory->Release();
1305	 return hres;
1306 }
1307
1308 HRESULT STDMETHODCALLTYPE  CreateDXGIFactory(
1309		 __in   REFIID riid,
1310		 __out  void **ppFactory
1311)
1312 {
1313	 return CreateDXGIFactory1(riid, ppFactory);
1314 }
1315