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