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