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"
28 extern "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 
38 struct GalliumDXGIOutput;
39 struct GalliumDXGIAdapter;
40 struct GalliumDXGISwapChain;
41 struct GalliumDXGIFactory;
42 
43 static HRESULT GalliumDXGISwapChainCreate(GalliumDXGIFactory* factory, IUnknown* device, const DXGI_SWAP_CHAIN_DESC& desc, IDXGISwapChain** out_swap_chain);
44 static HRESULT GalliumDXGIAdapterCreate(GalliumDXGIFactory* adapter, const struct native_platform* platform, void* dpy, IDXGIAdapter1** out_adapter);
45 static HRESULT GalliumDXGIOutputCreate(GalliumDXGIAdapter* adapter, const std::string& name, const struct native_connector* connector, IDXGIOutput** out_output);
46 static void GalliumDXGISwapChainRevalidate(IDXGISwapChain* swap_chain);
47 
48 template<typename Base = IDXGIObject, typename Parent = IDXGIObject>
49 struct GalliumDXGIObject : public GalliumPrivateDataComObject<Base>
50 {
51 	ComPtr<Parent> parent;
52 
GalliumDXGIObjectGalliumDXGIObject53 	GalliumDXGIObject(Parent* p_parent = 0)
54 	{
55 		this->parent = p_parent;
56 	}
57 
GetParentGalliumDXGIObject58 	virtual HRESULT STDMETHODCALLTYPE GetParent(
59 		REFIID riid,
60 		void **out_parent)
61 	{
62 		return parent->QueryInterface(riid, out_parent);
63 	}
64 };
65 
66 COM_INTERFACE(IGalliumDXGIBackend, IUnknown)
67 
68 // TODO: somehow check whether the window is fully obscured or not
69 struct GalliumDXGIIdentityBackend : public GalliumComObject<IGalliumDXGIBackend>
70 {
BeginPresentGalliumDXGIIdentityBackend71 	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 
EndPresentGalliumDXGIIdentityBackend93 	virtual void STDMETHODCALLTYPE EndPresent(
94 		HWND hwnd,
95 		void* present_cookie
96 	)
97 	{}
98 
TestPresentGalliumDXGIIdentityBackend99 	virtual HRESULT STDMETHODCALLTYPE TestPresent(HWND hwnd)
100 	{
101 		return S_OK;
102 	}
103 
GetPresentSizeGalliumDXGIIdentityBackend104         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
117 struct GalliumDXGIX11IdentityBackend : public GalliumDXGIIdentityBackend
118 {
119 	Display* dpy;
120 
GalliumDXGIX11IdentityBackendGalliumDXGIX11IdentityBackend121 	GalliumDXGIX11IdentityBackend(Display* dpy)
122 	: dpy(dpy)
123 	{}
124 
GetPresentSizeGalliumDXGIX11IdentityBackend125 	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 
139 struct 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 
GalliumDXGIFactoryGalliumDXGIFactory147 	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 
EnumAdaptersGalliumDXGIFactory158 	virtual HRESULT STDMETHODCALLTYPE EnumAdapters(
159 		UINT adapter,
160 		IDXGIAdapter **out_adapter)
161 	{
162 		return EnumAdapters1(adapter, (IDXGIAdapter1**)out_adapter);
163 	}
164 
EnumAdapters1GalliumDXGIFactory165 	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 	 */
MakeWindowAssociationGalliumDXGIFactory199 	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 
GetWindowAssociationGalliumDXGIFactory208 	virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation(
209 		HWND *pwindow_handle)
210 	{
211 		*pwindow_handle = associated_window;
212 		return S_OK;
213 	}
214 
CreateSwapChainGalliumDXGIFactory215 	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 
CreateSoftwareAdapterGalliumDXGIFactory223 	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 */
IsCurrentGalliumDXGIFactory233 	virtual BOOL STDMETHODCALLTYPE IsCurrent( void)
234 	{
235 		return TRUE;
236 	}
237 };
238 
239 struct 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 
GalliumDXGIAdapterGalliumDXGIAdapter254 	GalliumDXGIAdapter(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy)
255 	{
256 		this->parent = factory;
257 
258 		display = platform->create_display(dpy, FALSE);
259 		if(!display)
260                    display = platform->create_display(dpy, TRUE);
261                 if (display) {
262                    display->user_data = this;
263                    if (!display->init_screen(display)) {
264                       display->destroy(display);
265                       display = NULL;
266                    }
267                 }
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 
handle_invalid_surfaceGalliumDXGIAdapter315 	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 
~GalliumDXGIAdapterGalliumDXGIAdapter320 	~GalliumDXGIAdapter()
321 	{
322 		display->destroy(display);
323 		free(configs);
324 		free(connectors);
325 	}
326 
EnumOutputsGalliumDXGIAdapter327 	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 
GetDescGalliumDXGIAdapter344 	virtual HRESULT STDMETHODCALLTYPE GetDesc(
345 		DXGI_ADAPTER_DESC *desc)
346 	{
347 		memcpy(desc, &desc, sizeof(*desc));
348 		return S_OK;
349 	}
350 
GetDesc1GalliumDXGIAdapter351 	virtual HRESULT STDMETHODCALLTYPE GetDesc1(
352 		DXGI_ADAPTER_DESC1 *desc)
353 	{
354 		memcpy(desc, &desc, sizeof(*desc));
355 		return S_OK;
356 	}
357 
CheckInterfaceSupportGalliumDXGIAdapter358 	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 
GetGalliumScreenGalliumDXGIAdapter371 	pipe_screen* STDMETHODCALLTYPE GetGalliumScreen()
372 	{
373 		return display->screen;
374 	}
375 
GetGalliumReferenceSoftwareScreenGalliumDXGIAdapter376 	pipe_screen* STDMETHODCALLTYPE GetGalliumReferenceSoftwareScreen()
377 	{
378 		// TODO: give a softpipe screen
379 		return display->screen;
380 	}
381 
GetGalliumFastSoftwareScreenGalliumDXGIAdapter382 	pipe_screen* STDMETHODCALLTYPE GetGalliumFastSoftwareScreen()
383 	{
384 		// TODO: give an llvmpipe screen
385 		return display->screen;
386 	}
387 };
388 
389 
390 struct 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 
GalliumDXGIOutputGalliumDXGIOutput399 	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 		{
439 use_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 
~GalliumDXGIOutputGalliumDXGIOutput450 	~GalliumDXGIOutput()
451 	{
452 		delete [] dxgi_modes;
453 		free(modes);
454 		if(gamma)
455 			delete gamma;
456 	}
457 
GetDescGalliumDXGIOutput458 	virtual HRESULT STDMETHODCALLTYPE GetDesc(
459 		DXGI_OUTPUT_DESC *out_desc)
460 	{
461 		*out_desc = desc;
462 		return S_OK;
463 	}
464 
GetDisplayModeListGalliumDXGIOutput465 	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 
FindClosestMatchingModeGalliumDXGIOutput503 	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 
WaitForVBlankGalliumDXGIOutput528 	virtual HRESULT STDMETHODCALLTYPE WaitForVBlank( void)
529 	{
530 		return S_OK;
531 	}
532 
TakeOwnershipGalliumDXGIOutput533 	virtual HRESULT STDMETHODCALLTYPE TakeOwnership(
534 		IUnknown *device,
535 		BOOL exclusive)
536 	{
537 		return S_OK;
538 	}
539 
ReleaseOwnershipGalliumDXGIOutput540 	virtual void STDMETHODCALLTYPE ReleaseOwnership( void)
541 	{
542 	}
543 
GetGammaControlCapabilitiesGalliumDXGIOutput544 	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 
SetGammaControlGalliumDXGIOutput551 	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 
GetGammaControlGalliumDXGIOutput560 	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 
SetDisplaySurfaceGalliumDXGIOutput579 	virtual HRESULT STDMETHODCALLTYPE SetDisplaySurface(
580 		IDXGISurface *scanout_surface)
581 	{
582 		return E_NOTIMPL;
583 	}
584 
GetDisplaySurfaceDataGalliumDXGIOutput585 	virtual HRESULT STDMETHODCALLTYPE GetDisplaySurfaceData(
586 		IDXGISurface *destination)
587 	{
588 		return E_NOTIMPL;
589 	}
590 
GetFrameStatisticsGalliumDXGIOutput591 	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 
724 static 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 
731 struct 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 
dxgi_blitterdxgi_blitter746 	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.depth_clip = 1;
758 		rs_state.flatshade = 1;
759 		rasterizer = pipe->create_rasterizer_state(pipe, &rs_state);
760 
761 		struct pipe_blend_state blendd;
762 		memset(&blendd, 0, sizeof(blendd));
763 		blendd.rt[0].colormask = PIPE_MASK_RGBA;
764 		blend = pipe->create_blend_state(pipe, &blendd);
765 
766 		struct pipe_depth_stencil_alpha_state zsad;
767 		memset(&zsad, 0, sizeof(zsad));
768 		zsa = pipe->create_depth_stencil_alpha_state(pipe, &zsad);
769 
770 		struct pipe_vertex_element velem[2];
771 		memset(&velem[0], 0, sizeof(velem[0]) * 2);
772 		velem[0].src_offset = 0;
773 		velem[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
774 		velem[1].src_offset = 8;
775 		velem[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
776 		elements = pipe->create_vertex_elements_state(pipe, 2, &velem[0]);
777 
778 		for(unsigned stretch = 0; stretch < 2; ++stretch)
779 		{
780 			struct pipe_sampler_state sampler_state;
781 			memset(&sampler_state, 0, sizeof(sampler_state));
782 			sampler_state.min_img_filter = stretch ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
783 			sampler_state.mag_img_filter = stretch ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
784 			sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
785 			sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
786 			sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
787 			sampler_state.normalized_coords = normalized;
788 
789 			sampler[stretch] = pipe->create_sampler_state(pipe, &sampler_state);
790 		}
791 
792 		fs = util_make_fragment_tex_shader(pipe, normalized ? TGSI_TEXTURE_2D : TGSI_TEXTURE_RECT, TGSI_INTERPOLATE_LINEAR);
793 
794 		const unsigned semantic_names[] = { TGSI_SEMANTIC_POSITION, TGSI_SEMANTIC_GENERIC };
795 		const unsigned semantic_indices[] = { 0, 0 };
796 		vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names, semantic_indices);
797 
798 		vbuf.buffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER,
799 						 PIPE_USAGE_STREAM, sizeof(quad_data));
800 		vbuf.buffer_offset = 0;
801 		vbuf.stride = 4 * sizeof(float);
802 		pipe_buffer_write(pipe, vbuf.buffer, 0, sizeof(quad_data), quad_data);
803 
804 		memset(&clip, 0, sizeof(clip));
805 
806 		memset(&draw, 0, sizeof(draw));
807 		draw.mode = PIPE_PRIM_QUADS;
808 		draw.count = 4;
809 		draw.instance_count = 1;
810 		draw.max_index = ~0;
811 	}
812 
blitdxgi_blitter813 	void blit(struct pipe_surface* surf, struct pipe_sampler_view* view, unsigned x, unsigned y, unsigned w, unsigned h)
814 	{
815 		struct pipe_framebuffer_state fb;
816 		memset(&fb, 0, sizeof(fb));
817 		fb.nr_cbufs = 1;
818 		fb.cbufs[0] = surf;
819 		fb.width = surf->width;
820 		fb.height = surf->height;
821 
822 		struct pipe_viewport_state viewport;
823 		float half_width = w * 0.5f;
824 		float half_height = h * 0.5f;
825 		viewport.scale[0] = half_width;
826 		viewport.scale[1] = half_height;
827 		viewport.scale[2] = 1.0f;
828 		viewport.scale[3] = 1.0f;
829 		viewport.translate[0] = x + half_width;
830 		viewport.translate[1] = y + half_height;
831 		viewport.translate[2] = 0.0f;
832 		viewport.translate[3] = 1.0f;
833 
834 		bool stretch = view->texture->width0 != w || view->texture->height0 != h;
835 		if(pipe->render_condition)
836 			pipe->render_condition(pipe, 0, 0);
837 		pipe->set_framebuffer_state(pipe, &fb);
838 		pipe->bind_fragment_sampler_states(pipe, 1, &sampler[stretch]);
839 		pipe->set_viewport_state(pipe, &viewport);
840 		pipe->set_clip_state(pipe, &clip);
841 		pipe->bind_rasterizer_state(pipe, rasterizer);
842 		pipe->bind_depth_stencil_alpha_state(pipe, zsa);
843 		pipe->bind_blend_state(pipe, blend);
844 		pipe->bind_vertex_elements_state(pipe, elements);
845 		pipe->set_vertex_buffers(pipe, 1, &vbuf);
846 		pipe->bind_fs_state(pipe, fs);
847 		pipe->bind_vs_state(pipe, vs);
848 		if(pipe->bind_gs_state)
849 			pipe->bind_gs_state(pipe, 0);
850 		if(pipe->set_stream_output_targets)
851 			pipe->set_stream_output_targets(pipe, 0, NULL, 0);
852 		pipe->set_fragment_sampler_views(pipe, 1, &view);
853 
854 		pipe->draw_vbo(pipe, &draw);
855 	}
856 
~dxgi_blitterdxgi_blitter857 	~dxgi_blitter()
858 	{
859 		pipe->delete_blend_state(pipe, blend);
860 		pipe->delete_rasterizer_state(pipe, rasterizer);
861 		pipe->delete_depth_stencil_alpha_state(pipe, zsa);
862 		pipe->delete_sampler_state(pipe, sampler[0]);
863 		pipe->delete_sampler_state(pipe, sampler[1]);
864 		pipe->delete_vertex_elements_state(pipe, elements);
865 		pipe->delete_vs_state(pipe, vs);
866 		pipe->delete_fs_state(pipe, fs);
867 		pipe->screen->resource_destroy(pipe->screen, vbuf.buffer);
868 	}
869 };
870 
871 struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory>
872 {
873 	ComPtr<IDXGIDevice>dxgi_device;
874 	ComPtr<IGalliumDevice>gallium_device;
875 	ComPtr<GalliumDXGIAdapter> adapter;
876 	ComPtr<IDXGIOutput> target;
877 
878 	DXGI_SWAP_CHAIN_DESC desc;
879 
880 	struct native_surface* surface;
881 	const struct native_config* config;
882 
883 	void* window;
884 	struct pipe_resource* resources[NUM_NATIVE_ATTACHMENTS];
885 	int width;
886 	int height;
887 	unsigned seq_num;
888 	bool ever_validated;
889 	bool needs_validation;
890 	unsigned present_count;
891 
892 	ComPtr<IDXGISurface> buffer0;
893 	struct pipe_resource* gallium_buffer0;
894 	struct pipe_sampler_view* gallium_buffer0_view;
895 
896 	struct pipe_context* pipe;
897 	bool owns_pipe;
898 
899 	BOOL fullscreen;
900 
901 	std::auto_ptr<dxgi_blitter> blitter;
902 	bool formats_compatible;
903 
GalliumDXGISwapChainGalliumDXGISwapChain904 	GalliumDXGISwapChain(GalliumDXGIFactory* factory, IUnknown* p_device, const DXGI_SWAP_CHAIN_DESC& p_desc)
905 	: GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory>(factory), desc(p_desc), surface(0)
906 	{
907 		HRESULT hr;
908 
909 		hr = p_device->QueryInterface(IID_IGalliumDevice, (void**)&gallium_device);
910 		if(!SUCCEEDED(hr))
911 			throw hr;
912 
913 		hr = p_device->QueryInterface(IID_IDXGIDevice, (void**)&dxgi_device);
914 		if(!SUCCEEDED(hr))
915 			throw hr;
916 
917 		hr = dxgi_device->GetAdapter((IDXGIAdapter**)&adapter);
918 		if(!SUCCEEDED(hr))
919 			throw hr;
920 
921 		memset(resources, 0, sizeof(resources));
922 
923 		if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL && desc.BufferCount != 1)
924 		{
925 			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;
926 			// change the returned desc, so that the application might perhaps notice what we did and react well
927 			desc.BufferCount = 1;
928 		}
929 
930 		pipe = gallium_device->GetGalliumContext();
931 		owns_pipe = false;
932 		if(!pipe)
933 		{
934 			pipe = adapter->display->screen->context_create(adapter->display->screen, 0);
935 			owns_pipe = true;
936 		}
937 
938 		blitter.reset(new dxgi_blitter(pipe));
939 		window = 0;
940 
941 		hr = resolve_zero_width_height(true);
942 		if(!SUCCEEDED(hr))
943 			throw hr;
944 	}
945 
init_for_windowGalliumDXGISwapChain946 	void init_for_window()
947 	{
948 		if(surface)
949 		{
950 			surface->destroy(surface);
951 			surface = 0;
952 		}
953 
954 		unsigned config_num;
955 		if(!strcmp(parent->platform->name, "X11"))
956 		{
957 			XWindowAttributes xwa;
958 			XGetWindowAttributes((Display*)parent->display, (Window)window, &xwa);
959 			assert(adapter->configs_by_native_visual_id.count(xwa.visual->visualid));
960 			config_num = adapter->configs_by_native_visual_id[xwa.visual->visualid];
961 		}
962 		else
963 		{
964 			enum pipe_format format = dxgi_to_pipe_format[desc.BufferDesc.Format];
965 			if(!adapter->configs_by_pipe_format.count(format))
966 			{
967 				if(adapter->configs_by_pipe_format.empty())
968 					throw E_FAIL;
969 				// TODO: choose the best match
970 				format = (pipe_format)adapter->configs_by_pipe_format.begin()->first;
971 			}
972 			// TODO: choose the best config
973 			config_num = adapter->configs_by_pipe_format.find(format)->second;
974 		}
975 
976 		config = adapter->configs[config_num];
977 		surface = adapter->display->create_window_surface(adapter->display, (EGLNativeWindowType)window, config);
978 		surface->user_data = this;
979 
980 		width = 0;
981 		height = 0;
982 		seq_num = 0;
983 		present_count = 0;
984 		needs_validation = true;
985 		ever_validated = false;
986 
987 		formats_compatible = util_is_format_compatible(
988 				util_format_description(dxgi_to_pipe_format[desc.BufferDesc.Format]),
989 				util_format_description(config->color_format));
990 	}
991 
~GalliumDXGISwapChainGalliumDXGISwapChain992 	~GalliumDXGISwapChain()
993 	{
994 		if(owns_pipe)
995 			pipe->destroy(pipe);
996 	}
997 
GetDeviceGalliumDXGISwapChain998 	virtual HRESULT STDMETHODCALLTYPE GetDevice(
999 		REFIID riid,
1000 		void **pdevice)
1001 	{
1002 		return dxgi_device->QueryInterface(riid, pdevice);
1003 	}
1004 
create_buffer0GalliumDXGISwapChain1005 	HRESULT create_buffer0()
1006 	{
1007 		HRESULT hr;
1008 		ComPtr<IDXGISurface> new_buffer0;
1009 		DXGI_USAGE usage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT;
1010 		if(desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD)
1011 			usage |= DXGI_USAGE_DISCARD_ON_PRESENT;
1012 		// for our blitter
1013 		usage |= DXGI_USAGE_SHADER_INPUT;
1014 
1015 		DXGI_SURFACE_DESC surface_desc;
1016 		surface_desc.Format = desc.BufferDesc.Format;
1017 		surface_desc.Width = desc.BufferDesc.Width;
1018 		surface_desc.Height = desc.BufferDesc.Height;
1019 		surface_desc.SampleDesc = desc.SampleDesc;
1020 		hr = dxgi_device->CreateSurface(&surface_desc, 1, usage, 0, &new_buffer0);
1021 		if(!SUCCEEDED(hr))
1022 			return hr;
1023 
1024 		ComPtr<IGalliumResource> gallium_resource;
1025 		hr = new_buffer0->QueryInterface(IID_IGalliumResource, (void**)&gallium_resource);
1026 		if(!SUCCEEDED(hr))
1027 			return hr;
1028 
1029 		struct pipe_resource* new_gallium_buffer0 = gallium_resource->GetGalliumResource();
1030 		if(!new_gallium_buffer0)
1031 			return E_FAIL;
1032 
1033 		buffer0.reset(new_buffer0.steal());
1034 		gallium_buffer0 = new_gallium_buffer0;
1035 		struct pipe_sampler_view templat;
1036 		memset(&templat, 0, sizeof(templat));
1037 		templat.texture = gallium_buffer0;
1038 		templat.swizzle_r = 0;
1039 		templat.swizzle_g = 1;
1040 		templat.swizzle_b = 2;
1041 		templat.swizzle_a = 3;
1042 		templat.format = gallium_buffer0->format;
1043 		gallium_buffer0_view = pipe->create_sampler_view(pipe, gallium_buffer0, &templat);
1044 		return S_OK;
1045 	}
1046 
validateGalliumDXGISwapChain1047 	bool validate()
1048 	{
1049 		unsigned new_seq_num;
1050 		needs_validation = false;
1051 
1052 		if(!surface->validate(surface, (1 << NATIVE_ATTACHMENT_BACK_LEFT) | (1 << NATIVE_ATTACHMENT_FRONT_LEFT), &new_seq_num, resources, &width, &height))
1053 			return false;
1054 
1055 		if(!ever_validated || seq_num != new_seq_num)
1056 		{
1057 			seq_num = new_seq_num;
1058 			ever_validated = true;
1059 		}
1060 		return true;
1061 	}
1062 
resolve_zero_width_heightGalliumDXGISwapChain1063 	HRESULT resolve_zero_width_height(bool force = false)
1064 	{
1065 		if(!force && desc.BufferDesc.Width && desc.BufferDesc.Height)
1066 			return S_OK;
1067 
1068 		unsigned width, height;
1069 		HRESULT hr = parent->backend->GetPresentSize(desc.OutputWindow, &width, &height);
1070 		if(!SUCCEEDED(hr))
1071 			return hr;
1072 
1073 		// On Windows, 8 is used, and a debug message saying so gets printed
1074 		if(!width)
1075 			width = 8;
1076 		if(!height)
1077 			height = 8;
1078 
1079 		if(!desc.BufferDesc.Width)
1080 			desc.BufferDesc.Width = width;
1081 		if(!desc.BufferDesc.Height)
1082 			desc.BufferDesc.Height = height;
1083 		return S_OK;
1084 	}
1085 
PresentGalliumDXGISwapChain1086 	virtual HRESULT STDMETHODCALLTYPE Present(
1087 		UINT sync_interval,
1088 		UINT flags)
1089 	{
1090 		HRESULT hr;
1091 		if(flags & DXGI_PRESENT_TEST)
1092 			return parent->backend->TestPresent(desc.OutputWindow);
1093 
1094 		if(!buffer0)
1095 		{
1096 			HRESULT hr = create_buffer0();
1097 			if(!SUCCEEDED(hr))
1098 				return hr;
1099 		}
1100 
1101 		void* cur_window = 0;
1102 		RECT rect;
1103 		RGNDATA* rgndata;
1104 		BOOL preserve_aspect_ratio;
1105 		unsigned dst_w, dst_h;
1106 		bool db;
1107 		struct pipe_resource* dst;
1108 		struct pipe_resource* src;
1109 		struct pipe_surface* dst_surface;
1110 		struct native_present_control ctrl;
1111 
1112 		void* present_cookie;
1113 		hr = parent->backend->BeginPresent(desc.OutputWindow, &present_cookie, &cur_window, &rect, &rgndata, &preserve_aspect_ratio);
1114 		if(hr != S_OK)
1115 			return hr;
1116 
1117 		if(!cur_window || rect.left >= rect.right || rect.top >= rect.bottom)
1118 			goto end_present;
1119 
1120 		if(cur_window != window)
1121 		{
1122 			window = cur_window;
1123 			init_for_window();
1124 		}
1125 
1126 		if(needs_validation)
1127 		{
1128 			if(!validate())
1129 				return DXGI_ERROR_DEVICE_REMOVED;
1130 		}
1131 
1132 		db = !!(config->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT));
1133 		dst = resources[db ? NATIVE_ATTACHMENT_BACK_LEFT : NATIVE_ATTACHMENT_FRONT_LEFT];
1134 		src = gallium_buffer0;
1135 		dst_surface = 0;
1136 
1137 		assert(src);
1138 		assert(dst);
1139 
1140 		/* TODO: sharing the context for blitting won't work correctly if queries are active
1141 		 * Hopefully no one is crazy enough to keep queries active while presenting, expecting
1142 		 * sensible results.
1143 		 * We could alternatively force using another context, but that might cause inefficiency issues
1144 		 */
1145 
1146 		if((unsigned)rect.right > dst->width0)
1147 			rect.right = dst->width0;
1148 		if((unsigned)rect.bottom > dst->height0)
1149 			rect.bottom = dst->height0;
1150 		if(rect.left > rect.right)
1151 			rect.left = rect.right;
1152 		if(rect.top > rect.bottom)
1153 			rect.top = rect.bottom;
1154 
1155 		if(rect.left >= rect.right && rect.top >= rect.bottom)
1156 			goto end_present;
1157 
1158 		dst_w = rect.right - rect.left;
1159 		dst_h = rect.bottom - rect.top;
1160 
1161 		// TODO: add support for rgndata
1162 //		if(preserve_aspect_ratio || !rgndata)
1163 		if(1)
1164 		{
1165 			unsigned blit_x, blit_y, blit_w, blit_h;
1166 			static const union pipe_color_union black = { { 0, 0, 0, 0 } };
1167 
1168 			if(!formats_compatible || src->width0 != dst_w || src->height0 != dst_h) {
1169 				struct pipe_surface templat;
1170 				templat.usage = PIPE_BIND_RENDER_TARGET;
1171 				templat.format = dst->format;
1172 				templat.u.tex.level = 0;
1173 				templat.u.tex.first_layer = 0;
1174 				templat.u.tex.last_layer = 0;
1175 				dst_surface = pipe->create_surface(pipe, dst, &templat);
1176 			}
1177 
1178 			if(preserve_aspect_ratio)
1179 			{
1180 				int delta = src->width0 * dst_h - dst_w * src->height0;
1181 				if(delta > 0)
1182 				{
1183 					blit_w = dst_w;
1184 					blit_h = dst_w * src->height0 / src->width0;
1185 				}
1186 				else if(delta < 0)
1187 				{
1188 					blit_w = dst_h * src->width0 / src->height0;
1189 					blit_h = dst_h;
1190 				}
1191 				else
1192 				{
1193 					blit_w = dst_w;
1194 					blit_h = dst_h;
1195 				}
1196 
1197 				blit_x = (dst_w - blit_w) >> 1;
1198 				blit_y = (dst_h - blit_h) >> 1;
1199 			}
1200 			else
1201 			{
1202 				blit_x = 0;
1203 				blit_y = 0;
1204 				blit_w = dst_w;
1205 				blit_h = dst_h;
1206 			}
1207 
1208 			if(blit_x)
1209 				pipe->clear_render_target(pipe, dst_surface, &black, rect.left, rect.top, blit_x, dst_h);
1210 			if(blit_y)
1211 				pipe->clear_render_target(pipe, dst_surface, &black, rect.left, rect.top, dst_w, blit_y);
1212 
1213 			if(formats_compatible && blit_w == src->width0 && blit_h == src->height0)
1214 			{
1215 				pipe_box box;
1216 				box.x = box.y = box.z = 0;
1217 				box.width = blit_w;
1218 				box.height = blit_h;
1219 				box.depth = 1;
1220 				pipe->resource_copy_region(pipe, dst, 0, rect.left, rect.top, 0, src, 0, &box);
1221 			}
1222 			else
1223 			{
1224 				blitter->blit(dst_surface, gallium_buffer0_view, rect.left + blit_x, rect.top + blit_y, blit_w, blit_h);
1225 				if(!owns_pipe)
1226 					gallium_device->RestoreGalliumState();
1227 			}
1228 
1229 			if(blit_w != dst_w)
1230 				pipe->clear_render_target(pipe, dst_surface, &black, rect.left + blit_x + blit_w, rect.top, dst_w - blit_x - blit_w, dst_h);
1231 			if(blit_h != dst_h)
1232 				pipe->clear_render_target(pipe, dst_surface, &black, rect.left, rect.top + blit_y + blit_h, dst_w, dst_h - blit_y - blit_h);
1233 		}
1234 
1235 		if(dst_surface)
1236 			pipe->surface_destroy(pipe, dst_surface);
1237 
1238                 pipe->flush(pipe, 0);
1239 
1240 		memset(&ctrl, 0, sizeof(ctrl));
1241 		ctrl.natt = (db) ? NATIVE_ATTACHMENT_BACK_LEFT : NATIVE_ATTACHMENT_FRONT_LEFT;
1242 		if(!surface->present(surface, &ctrl))
1243 			return DXGI_ERROR_DEVICE_REMOVED;
1244 
1245 end_present:
1246 		parent->backend->EndPresent(desc.OutputWindow, present_cookie);
1247 
1248 		++present_count;
1249 		return S_OK;
1250 	}
1251 
GetBufferGalliumDXGISwapChain1252 	virtual HRESULT STDMETHODCALLTYPE GetBuffer(
1253 			UINT Buffer,
1254 			REFIID riid,
1255 			void **ppSurface)
1256 	{
1257 		if(Buffer > 0)
1258 		{
1259 			if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL)
1260 				std::cerr << "DXGI unimplemented: GetBuffer(n) with n > 0 not supported, returning buffer 0 instead!" << std::endl;
1261 			else
1262 				std::cerr << "DXGI error: in GetBuffer(n), n must be 0 for DXGI_SWAP_EFFECT_DISCARD\n" << std::endl;
1263 		}
1264 
1265 		if(!buffer0)
1266 		{
1267 			HRESULT hr = create_buffer0();
1268 			if(!SUCCEEDED(hr))
1269 				return hr;
1270 		}
1271 		return buffer0->QueryInterface(riid, ppSurface);
1272 	}
1273 
1274 	/* TODO: implement somehow */
SetFullscreenStateGalliumDXGISwapChain1275 	virtual HRESULT STDMETHODCALLTYPE SetFullscreenState(
1276 		BOOL fullscreen,
1277 		IDXGIOutput *target)
1278 	{
1279 		fullscreen = fullscreen;
1280 		target = target;
1281 		return S_OK;
1282 	}
1283 
GetFullscreenStateGalliumDXGISwapChain1284 	virtual HRESULT STDMETHODCALLTYPE GetFullscreenState(
1285 		BOOL *out_fullscreen,
1286 		IDXGIOutput **out_target)
1287 	{
1288 		if(out_fullscreen)
1289 			*out_fullscreen = fullscreen;
1290 		if(out_target)
1291 			*out_target = target.ref();
1292 		return S_OK;
1293 	}
1294 
GetDescGalliumDXGISwapChain1295 	virtual HRESULT STDMETHODCALLTYPE GetDesc(
1296 		DXGI_SWAP_CHAIN_DESC *out_desc)
1297 	{
1298 		*out_desc = desc;
1299 		return S_OK;
1300 	}
1301 
ResizeBuffersGalliumDXGISwapChain1302 	virtual HRESULT STDMETHODCALLTYPE ResizeBuffers(
1303 		UINT buffer_count,
1304 		UINT width,
1305 		UINT height,
1306 		DXGI_FORMAT new_format,
1307 		UINT swap_chain_flags)
1308 	{
1309 		if(buffer0)
1310 		{
1311 			buffer0.p->AddRef();
1312 			ULONG v = buffer0.p->Release();
1313 			// we must fail if there are any references to buffer0 other than ours
1314 			if(v > 1)
1315 				return E_FAIL;
1316 			pipe_sampler_view_reference(&gallium_buffer0_view, 0);
1317 			buffer0 = (IUnknown*)NULL;
1318 			gallium_buffer0 = 0;
1319 		}
1320 
1321 		if(desc.SwapEffect != DXGI_SWAP_EFFECT_SEQUENTIAL)
1322 			desc.BufferCount = buffer_count;
1323 		desc.BufferDesc.Format = new_format;
1324 		desc.BufferDesc.Width = width;
1325 		desc.BufferDesc.Height = height;
1326 		desc.Flags = swap_chain_flags;
1327 		return resolve_zero_width_height();
1328 	}
1329 
ResizeTargetGalliumDXGISwapChain1330 	virtual HRESULT STDMETHODCALLTYPE ResizeTarget(
1331 		const DXGI_MODE_DESC *out_new_target_parameters)
1332 	{
1333 		/* TODO: implement */
1334 		return S_OK;
1335 	}
1336 
GetContainingOutputGalliumDXGISwapChain1337 	virtual HRESULT STDMETHODCALLTYPE GetContainingOutput(
1338 		IDXGIOutput **out_output)
1339 	{
1340 		*out_output = adapter->outputs[0].ref();
1341 		return S_OK;
1342 	}
1343 
GetFrameStatisticsGalliumDXGISwapChain1344 	virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics(
1345 		DXGI_FRAME_STATISTICS *out_stats)
1346 	{
1347 		memset(out_stats, 0, sizeof(*out_stats));
1348 #ifdef _WIN32
1349 		QueryPerformanceCounter(&out_stats->SyncQPCTime);
1350 #endif
1351 		out_stats->PresentCount = present_count;
1352 		out_stats->PresentRefreshCount = present_count;
1353 		out_stats->SyncRefreshCount = present_count;
1354 		return S_OK;
1355 	}
1356 
GetLastPresentCountGalliumDXGISwapChain1357 	virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(
1358 		UINT *last_present_count)
1359 	{
1360 		*last_present_count = present_count;
1361 		return S_OK;
1362 	}
1363 };
1364 
GalliumDXGISwapChainRevalidate(IDXGISwapChain * swap_chain)1365 static void GalliumDXGISwapChainRevalidate(IDXGISwapChain* swap_chain)
1366 {
1367 	((GalliumDXGISwapChain*)swap_chain)->needs_validation = true;
1368 }
1369 
GalliumDXGIAdapterCreate(GalliumDXGIFactory * factory,const struct native_platform * platform,void * dpy,IDXGIAdapter1 ** out_adapter)1370 static HRESULT GalliumDXGIAdapterCreate(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy, IDXGIAdapter1** out_adapter)
1371 {
1372 	try
1373 	{
1374 		*out_adapter = new GalliumDXGIAdapter(factory, platform, dpy);
1375 		return S_OK;
1376 	}
1377 	catch(HRESULT hr)
1378 	{
1379 		return hr;
1380 	}
1381 }
1382 
GalliumDXGIOutputCreate(GalliumDXGIAdapter * adapter,const std::string & name,const struct native_connector * connector,IDXGIOutput ** out_output)1383 static HRESULT GalliumDXGIOutputCreate(GalliumDXGIAdapter* adapter, const std::string& name, const struct native_connector* connector, IDXGIOutput** out_output)
1384 {
1385 	try
1386 	{
1387 		*out_output = new GalliumDXGIOutput(adapter, name, connector);
1388 		return S_OK;
1389 	}
1390 	catch(HRESULT hr)
1391 	{
1392 		return hr;
1393 	}
1394 }
1395 
GalliumDXGISwapChainCreate(GalliumDXGIFactory * factory,IUnknown * device,const DXGI_SWAP_CHAIN_DESC & desc,IDXGISwapChain ** out_swap_chain)1396 static HRESULT GalliumDXGISwapChainCreate(GalliumDXGIFactory* factory, IUnknown* device, const DXGI_SWAP_CHAIN_DESC& desc, IDXGISwapChain** out_swap_chain)
1397 {
1398 	try
1399 	{
1400 		*out_swap_chain = new GalliumDXGISwapChain(factory, device, desc);
1401 		return S_OK;
1402 	}
1403 	catch(HRESULT hr)
1404 	{
1405 		return hr;
1406 	}
1407 }
1408 
1409 struct dxgi_binding
1410 {
1411 	const struct native_platform* platform;
1412 	void* display;
1413 	IGalliumDXGIBackend* backend;
1414 };
1415 
1416 static dxgi_binding dxgi_default_binding;
1417 static __thread dxgi_binding dxgi_thread_binding;
1418 static const struct native_event_handler dxgi_event_handler = {
1419    GalliumDXGIAdapter::handle_invalid_surface,
1420    dxgi_loader_create_drm_screen,
1421    dxgi_loader_create_sw_screen
1422 };
1423 
GalliumDXGIUseNothing()1424 void STDMETHODCALLTYPE GalliumDXGIUseNothing()
1425 {
1426 	dxgi_thread_binding.platform = 0;
1427 	dxgi_thread_binding.display = 0;
1428 	if(dxgi_thread_binding.backend)
1429 		dxgi_thread_binding.backend->Release();
1430 	dxgi_thread_binding.backend = 0;
1431 }
1432 
1433 #ifdef GALLIUM_DXGI_USE_X11
GalliumDXGIUseX11Display(Display * dpy,IGalliumDXGIBackend * backend)1434 void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, IGalliumDXGIBackend* backend)
1435 {
1436 	GalliumDXGIUseNothing();
1437 	dxgi_thread_binding.platform = native_get_x11_platform(&dxgi_event_handler);
1438 	dxgi_thread_binding.display = dpy;
1439 
1440 	if(backend)
1441 	{
1442 		dxgi_thread_binding.backend = backend;
1443 		backend->AddRef();
1444 	}
1445 }
1446 #endif
1447 
1448 /*
1449 #ifdef GALLIUM_DXGI_USE_DRM
1450 void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd)
1451 {
1452 	GalliumDXGIUseNothing();
1453 	dxgi_thread_binding.platform = native_get_drm_platform(&dxgi_event_handler);
1454 	dxgi_thread_binding.display = (void*)fd;
1455 	dxgi_thread_binding.backend = 0;
1456 }
1457 #endif
1458 
1459 #ifdef GALLIUM_DXGI_USE_FBDEV
1460 void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd)
1461 {
1462 	GalliumDXGIUseNothing();
1463 	dxgi_thread_binding.platform = native_get_fbdev_platform(&dxgi_event_handler);
1464 	dxgi_thread_binding.display = (void*)fd;
1465 	dxgi_thread_binding.backend = 0;
1466 }
1467 #endif
1468 
1469 #ifdef GALLIUM_DXGI_USE_GDI
1470 void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie)
1471 {
1472 	GalliumDXGIUseNothing();
1473 	dxgi_thread_binding.platform = native_get_gdi_platform(&dxgi_event_handler);
1474 	dxgi_thread_binding.display = (void*)hdc;
1475 	dxgi_thread_binding.backend = 0;
1476 }
1477 #endif
1478 */
GalliumDXGIMakeDefault()1479 void STDMETHODCALLTYPE GalliumDXGIMakeDefault()
1480 {
1481 	if(dxgi_default_binding.backend)
1482 		dxgi_default_binding.backend->Release();
1483 	dxgi_default_binding = dxgi_thread_binding;
1484 	if(dxgi_default_binding.backend)
1485 		dxgi_default_binding.backend->AddRef();
1486 }
1487 
1488  /* TODO: why did Microsoft add this? should we do something different for DXGI 1.0 and 1.1?
1489  * Or perhaps what they actually mean is "only create a single factory in your application"?
1490  * TODO: should we use a singleton here, so we never have multiple DXGI objects for the same thing? */
CreateDXGIFactory1(REFIID riid,void ** out_factory)1491  HRESULT STDMETHODCALLTYPE CreateDXGIFactory1(
1492 		REFIID riid,
1493 		void **out_factory
1494 )
1495  {
1496 	 GalliumDXGIFactory* factory;
1497 	 *out_factory = 0;
1498 	 if(dxgi_thread_binding.platform)
1499 		 factory = new GalliumDXGIFactory(dxgi_thread_binding.platform, dxgi_thread_binding.display, dxgi_thread_binding.backend);
1500 	 else if(dxgi_default_binding.platform)
1501 		 factory = new GalliumDXGIFactory(dxgi_default_binding.platform, dxgi_default_binding.display, dxgi_default_binding.backend);
1502 	 else
1503 		 factory = new GalliumDXGIFactory(native_get_x11_platform(&dxgi_event_handler), NULL, NULL);
1504 	 HRESULT hres = factory->QueryInterface(riid, out_factory);
1505 	 factory->Release();
1506 	 return hres;
1507  }
1508 
CreateDXGIFactory(REFIID riid,void ** out_factor)1509  HRESULT STDMETHODCALLTYPE CreateDXGIFactory(
1510 		 REFIID riid,
1511 		 void **out_factor
1512 )
1513  {
1514 	 return CreateDXGIFactory1(riid, out_factor);
1515  }
1516