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