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