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