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