1 /**************************************************************************
3 * Copyright 2010 Luca Barbieri
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:
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.
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.
25 **************************************************************************/
27 #include "dxgi_private.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>
38 struct GalliumDXGIOutput
;
39 struct GalliumDXGIAdapter
;
40 struct GalliumDXGISwapChain
;
41 struct GalliumDXGIFactory
;
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
);
48 template<typename Base
= IDXGIObject
, typename Parent
= IDXGIObject
>
49 struct GalliumDXGIObject
: public GalliumPrivateDataComObject
<Base
>
51 ComPtr
<Parent
> parent
;
53 GalliumDXGIObject(Parent
* p_parent
= 0)
55 this->parent
= p_parent
;
58 virtual HRESULT STDMETHODCALLTYPE
GetParent(
60 __out
void **ppParent
)
62 return parent
->QueryInterface(riid
, ppParent
);
66 COM_INTERFACE(IGalliumDXGIBackend
, IUnknown
)
68 struct GalliumDXGIIdentityBackend
: public GalliumComObject
<IGalliumDXGIBackend
>
70 virtual void * STDMETHODCALLTYPE
BeginPresent(
75 BOOL
* preserve_aspect_ratio
78 *window
= (void*)hwnd
;
81 rect
->right
= INT_MAX
;
82 rect
->bottom
= INT_MAX
;
85 // yes, because we like things looking good
86 *preserve_aspect_ratio
= TRUE
;
90 virtual void STDMETHODCALLTYPE
EndPresent(
97 struct GalliumDXGIFactory
: public GalliumDXGIObject
<IDXGIFactory1
, IUnknown
>
99 HWND associated_window
;
100 const struct native_platform
* platform
;
102 ComPtr
<IGalliumDXGIBackend
> backend
;
103 void* resolver_cookie
;
105 GalliumDXGIFactory(const struct native_platform
* platform
, void* display
, IGalliumDXGIBackend
* p_backend
)
106 : GalliumDXGIObject
<IDXGIFactory1
, IUnknown
>((IUnknown
*)NULL
), platform(platform
), display(display
)
111 backend
.reset(new GalliumDXGIIdentityBackend());
114 virtual HRESULT STDMETHODCALLTYPE
EnumAdapters(
116 __out IDXGIAdapter
**ppAdapter
)
118 return EnumAdapters1(Adapter
, (IDXGIAdapter1
**)ppAdapter
);
121 virtual HRESULT STDMETHODCALLTYPE
EnumAdapters1(
123 __out IDXGIAdapter1
**ppAdapter
)
128 return GalliumDXGIAdapterCreate(this, platform
, display
, ppAdapter
);
132 if(platform
== native_get_x11_platform())
134 unsigned nscreens
= ScreenCount((Display
*)display
);
135 if(Adapter
< nscreens
)
137 unsigned def_screen
= DefaultScreen(display
);
138 if(Adapter
<= def_screen
)
140 *ppAdapter
= GalliumDXGIAdapterCreate(this, platform
, display
, Adapter
);
145 return DXGI_ERROR_NOT_FOUND
;
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?
155 virtual HRESULT STDMETHODCALLTYPE
MakeWindowAssociation(
159 /* TODO: actually implement, for Wine, X11 and KMS*/
160 associated_window
= WindowHandle
;
164 virtual HRESULT STDMETHODCALLTYPE
GetWindowAssociation(
165 __out HWND
*pWindowHandle
)
167 *pWindowHandle
= associated_window
;
171 virtual HRESULT STDMETHODCALLTYPE
CreateSwapChain(
172 __in IUnknown
*pDevice
,
173 __in DXGI_SWAP_CHAIN_DESC
*pDesc
,
174 __out IDXGISwapChain
**ppSwapChain
)
176 return GalliumDXGISwapChainCreate(this, pDevice
, *pDesc
, ppSwapChain
);
179 virtual HRESULT STDMETHODCALLTYPE
CreateSoftwareAdapter(
181 __out IDXGIAdapter
**ppAdapter
)
183 /* TODO: ignore the module, and just create a Gallium software screen */
188 /* TODO: support hotplug */
189 virtual BOOL STDMETHODCALLTYPE
IsCurrent( void)
195 struct GalliumDXGIAdapter
196 : public GalliumMultiComObject
<
197 GalliumDXGIObject
<IDXGIAdapter1
, GalliumDXGIFactory
>,
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
;
209 struct native_event_handler handler
;
211 GalliumDXGIAdapter(GalliumDXGIFactory
* factory
, const struct native_platform
* platform
, void* dpy
)
213 this->parent
= factory
;
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);
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
);
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
];
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;
233 // TODO: we should actually use an unique ID instead
234 *(void**)&desc
.AdapterLuid
= dpy
;
236 configs
= display
->get_configs(display
, (int*)&num_configs
);
237 for(unsigned i
= 0; i
< num_configs
; ++i
)
239 if(configs
[i
]->window_bit
)
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
;
253 connectors
= display
->modeset
->get_connectors(display
, &num_outputs
, &num_crtcs
);
256 else if(!num_outputs
)
266 static void handle_invalid_surface(struct native_display
*ndpy
, struct native_surface
*nsurf
, unsigned int seq_num
)
268 GalliumDXGISwapChainRevalidate((IDXGISwapChain
*)nsurf
->user_data
);
271 ~GalliumDXGIAdapter()
273 display
->destroy(display
);
278 virtual HRESULT STDMETHODCALLTYPE
EnumOutputs(
280 __out IDXGIOutput
**ppOutput
)
282 if(Output
>= (unsigned)num_outputs
)
283 return DXGI_ERROR_NOT_FOUND
;
287 std::ostringstream ss
;
288 ss
<< "Output #" << Output
;
289 return GalliumDXGIOutputCreate(this, ss
.str(), connectors
[Output
], ppOutput
);
292 return GalliumDXGIOutputCreate(this, "Unique output", NULL
, ppOutput
);
295 virtual HRESULT STDMETHODCALLTYPE
GetDesc(
296 __out DXGI_ADAPTER_DESC
*pDesc
)
298 memcpy(pDesc
, &desc
, sizeof(*pDesc
));
302 virtual HRESULT STDMETHODCALLTYPE
GetDesc1(
303 __out DXGI_ADAPTER_DESC1
*pDesc
)
305 memcpy(pDesc
, &desc
, sizeof(*pDesc
));
309 virtual HRESULT STDMETHODCALLTYPE
CheckInterfaceSupport(
310 __in REFGUID InterfaceName
,
311 __out LARGE_INTEGER
*pUMDVersion
)
313 // these number was taken from Windows 7 with Catalyst 10.8: its meaning is unclear
314 if(InterfaceName
== IID_ID3D11Device
|| InterfaceName
== IID_ID3D10Device1
|| InterfaceName
== IID_ID3D10Device
)
316 pUMDVersion
->QuadPart
= 0x00080011000a0411ULL
;
319 return DXGI_ERROR_UNSUPPORTED
;
322 pipe_screen
* STDMETHODCALLTYPE
GetGalliumScreen()
324 return display
->screen
;
327 pipe_screen
* STDMETHODCALLTYPE
GetGalliumReferenceSoftwareScreen()
329 // TODO: give a softpipe screen
330 return display
->screen
;
333 pipe_screen
* STDMETHODCALLTYPE
GetGalliumFastSoftwareScreen()
335 // TODO: give an llvmpipe screen
336 return display
->screen
;
341 struct GalliumDXGIOutput
: public GalliumDXGIObject
<IDXGIOutput
, GalliumDXGIAdapter
>
343 DXGI_OUTPUT_DESC desc
;
344 const struct native_mode
** modes
;
345 DXGI_MODE_DESC
* dxgi_modes
;
347 const struct native_connector
* connector
;
348 DXGI_GAMMA_CONTROL
* gamma
;
350 GalliumDXGIOutput(GalliumDXGIAdapter
* adapter
, std::string name
, const struct native_connector
* connector
= 0)
351 : GalliumDXGIObject
<IDXGIOutput
, GalliumDXGIAdapter
>(adapter
), connector(connector
)
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 */
364 modes
= parent
->display
->modeset
->get_modes(parent
->display
, connector
, (int*)&num_modes
);
365 if(modes
&& num_modes
)
367 dxgi_modes
= new DXGI_MODE_DESC
[num_modes
];
368 for(unsigned i
= 0; i
< num_modes
; ++i
)
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
;
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
;
403 delete [] dxgi_modes
;
409 virtual HRESULT STDMETHODCALLTYPE
GetDesc(
410 __out DXGI_OUTPUT_DESC
*pDesc
)
416 virtual HRESULT STDMETHODCALLTYPE
GetDisplayModeList(
417 DXGI_FORMAT EnumFormat
,
419 __inout UINT
*pNumModes
,
420 __out_ecount_part_opt(*pNumModes
,*pNumModes
) DXGI_MODE_DESC
*pDesc
)
422 /* TODO: should we return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE when we don't
423 * support modesetting instead of fake modes?
425 pipe_format format
= dxgi_to_pipe_format
[EnumFormat
];
426 if(parent
->configs_by_pipe_format
.count(format
))
430 *pNumModes
= num_modes
;
434 unsigned copy_modes
= std::min(num_modes
, *pNumModes
);
435 for(unsigned i
= 0; i
< copy_modes
; ++i
)
437 pDesc
[i
] = dxgi_modes
[i
];
438 pDesc
[i
].Format
= EnumFormat
;
440 *pNumModes
= num_modes
;
442 if(copy_modes
< num_modes
)
443 return DXGI_ERROR_MORE_DATA
;
454 virtual HRESULT STDMETHODCALLTYPE
FindClosestMatchingMode(
455 __in
const DXGI_MODE_DESC
*pModeToMatch
,
456 __out DXGI_MODE_DESC
*pClosestMatch
,
457 __in_opt IUnknown
*pConcernedDevice
)
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
))
465 if(!pConcernedDevice
)
469 format
= parent
->configs
[0]->color_format
;
470 dxgi_format
= pipe_to_dxgi_format
[format
];
474 *pClosestMatch
= dxgi_modes
[0];
475 pClosestMatch
->Format
= dxgi_format
;
479 virtual HRESULT STDMETHODCALLTYPE
WaitForVBlank( void)
484 virtual HRESULT STDMETHODCALLTYPE
TakeOwnership(
485 __in IUnknown
*pDevice
,
491 virtual void STDMETHODCALLTYPE
ReleaseOwnership( void)
495 virtual HRESULT STDMETHODCALLTYPE
GetGammaControlCapabilities(
496 __out DXGI_GAMMA_CONTROL_CAPABILITIES
*pGammaCaps
)
498 memset(pGammaCaps
, 0, sizeof(*pGammaCaps
));
502 virtual HRESULT STDMETHODCALLTYPE
SetGammaControl(
503 __in
const DXGI_GAMMA_CONTROL
*pArray
)
506 gamma
= new DXGI_GAMMA_CONTROL
;
511 virtual HRESULT STDMETHODCALLTYPE
GetGammaControl(
512 __out DXGI_GAMMA_CONTROL
*pArray
)
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;
530 virtual HRESULT STDMETHODCALLTYPE
SetDisplaySurface(
531 __in IDXGISurface
*pScanoutSurface
)
536 virtual HRESULT STDMETHODCALLTYPE
GetDisplaySurfaceData(
537 __in IDXGISurface
*pDestination
)
542 virtual HRESULT STDMETHODCALLTYPE
GetFrameStatistics(
543 __out DXGI_FRAME_STATISTICS
*pStats
)
545 memset(pStats
, 0, sizeof(*pStats
));
547 QueryPerformanceCounter(&pStats
->SyncQPCTime
);
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
558 * There are two modes (called "swap effects") that a swap chain can operate in:
559 * discard and sequential.
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 BufferCount 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 BufferCount buffers in fullscreen mode.
575 * In sequential mode, the runtime alllocates BufferCount 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
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().
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.
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.
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
608 * How does Microsoft implement the rotation behavior?
609 * It turns out that it does it by calling RotateResourceIdentitiesDXGI in the user-mode
611 * This will rotate the kernel buffer handle, or possibly rotate the GPU virtual memory
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.
619 * OK, so how do we implement this in Gallium?
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.
632 * (2) is not acceptable since it prevents an optimal implementation.
633 * (3) is the ideal solution, but it is complicated.
635 * Hence, we implement (1) for now, and will switch to (3) later.
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..
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.
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 BufferCount == 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.
653 * A better design would forbid the user specifying BufferCount 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
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
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.
669 * "DXGI Overview" in MSDN
670 * IDXGISwapChain documentation on MSDN
671 * "RotateResourceIdentitiesDXGI" on MSDN
672 * http://forums.xna.com/forums/p/42362/266016.aspx
675 static float quad_data
[] = {
693 struct pipe_clip_state clip
;
694 struct pipe_vertex_buffer vbuf
;
695 struct pipe_draw_info draw
;
697 dxgi_blitter(pipe_context
* pipe
)
700 //normalized = !!pipe->screen->get_param(pipe, PIPE_CAP_NPOT_TEXTURES);
701 // TODO: need to update buffer in unnormalized case
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
);
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
);
716 struct pipe_depth_stencil_alpha_state zsad
;
717 memset(&zsad
, 0, sizeof(zsad
));
718 zsa
= pipe
->create_depth_stencil_alpha_state(pipe
, &zsad
);
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]);
728 for(unsigned stretch
= 0; stretch
< 2; ++stretch
)
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
;
739 sampler
[stretch
] = pipe
->create_sampler_state(pipe
, &sampler_state
);
742 fs
= util_make_fragment_tex_shader(pipe
, normalized
? TGSI_TEXTURE_2D
: TGSI_TEXTURE_RECT
, TGSI_INTERPOLATE_LINEAR
);
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
);
748 vbuf
.buffer
= pipe_buffer_create(pipe
->screen
, PIPE_BIND_VERTEX_BUFFER
, sizeof(quad_data
));
749 vbuf
.buffer_offset
= 0;
751 vbuf
.stride
= 4 * sizeof(float);
752 pipe_buffer_write(pipe
, vbuf
.buffer
, 0, sizeof(quad_data
), quad_data
);
754 memset(&clip
, 0, sizeof(clip
));
756 memset(&draw
, 0, sizeof(draw
));
757 draw
.mode
= PIPE_PRIM_QUADS
;
759 draw
.instance_count
= 1;
763 void blit(struct pipe_surface
* surf
, struct pipe_sampler_view
* view
, unsigned x
, unsigned y
, unsigned w
, unsigned h
)
765 struct pipe_framebuffer_state fb
;
766 memset(&fb
, 0, sizeof(fb
));
769 fb
.width
= surf
->width
;
770 fb
.height
= surf
->height
;
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
;
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
);
804 pipe
->draw_vbo(pipe
, &draw
);
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
);
821 struct GalliumDXGISwapChain
: public GalliumDXGIObject
<IDXGISwapChain
, GalliumDXGIFactory
>
823 ComPtr
<IDXGIDevice
>dxgi_device
;
824 ComPtr
<IGalliumDevice
>gallium_device
;
825 ComPtr
<GalliumDXGIAdapter
> adapter
;
826 ComPtr
<IDXGIOutput
> target
;
828 DXGI_SWAP_CHAIN_DESC desc
;
830 struct native_surface
* surface
;
831 const struct native_config
* config
;
834 struct pipe_resource
* resources
[NUM_NATIVE_ATTACHMENTS
];
839 bool needs_validation
;
840 unsigned present_count
;
842 ComPtr
<IDXGISurface
> buffer0
;
843 struct pipe_resource
* gallium_buffer0
;
844 struct pipe_sampler_view
* gallium_buffer0_view
;
846 struct pipe_context
* pipe
;
851 std::auto_ptr
<dxgi_blitter
> blitter
;
852 bool formats_compatible
;
854 GalliumDXGISwapChain(GalliumDXGIFactory
* factory
, IUnknown
* p_device
, const DXGI_SWAP_CHAIN_DESC
& p_desc
)
855 : GalliumDXGIObject
<IDXGISwapChain
, GalliumDXGIFactory
>(factory
), desc(p_desc
), surface(0)
859 hr
= p_device
->QueryInterface(IID_IGalliumDevice
, (void**)&gallium_device
);
863 hr
= p_device
->QueryInterface(IID_IDXGIDevice
, (void**)&dxgi_device
);
867 hr
= dxgi_device
->GetAdapter((IDXGIAdapter
**)&adapter
);
871 memset(resources
, 0, sizeof(resources
));
873 if(desc
.SwapEffect
== DXGI_SWAP_EFFECT_SEQUENTIAL
&& desc
.BufferCount
!= 1)
875 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
;
876 // change the returned desc, so that the application might perhaps notice what we did and react well
877 desc
.BufferCount
= 1;
880 pipe
= gallium_device
->GetGalliumContext();
884 pipe
= adapter
->display
->screen
->context_create(adapter
->display
->screen
, 0);
888 blitter
.reset(new dxgi_blitter(pipe
));
892 void init_for_window()
896 surface
->destroy(surface
);
901 if(!strcmp(parent
->platform
->name
, "X11"))
903 XWindowAttributes xwa
;
904 XGetWindowAttributes((Display
*)parent
->display
, (Window
)window
, &xwa
);
905 config_num
= adapter
->configs_by_native_visual_id
[xwa
.visual
->visualid
];
909 enum pipe_format format
= dxgi_to_pipe_format
[desc
.BufferDesc
.Format
];
910 if(!adapter
->configs_by_pipe_format
.count(format
))
912 if(adapter
->configs_by_pipe_format
.empty())
914 // TODO: choose the best match
915 format
= (pipe_format
)adapter
->configs_by_pipe_format
.begin()->first
;
917 // TODO: choose the best config
918 config_num
= adapter
->configs_by_pipe_format
.find(format
)->second
;
921 config
= adapter
->configs
[config_num
];
922 surface
= adapter
->display
->create_window_surface(adapter
->display
, (EGLNativeWindowType
)window
, config
);
923 surface
->user_data
= this;
929 needs_validation
= true;
930 ever_validated
= false;
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
));
937 ~GalliumDXGISwapChain()
943 virtual HRESULT STDMETHODCALLTYPE
GetDevice(
945 __out
void **ppDevice
)
947 return dxgi_device
->QueryInterface(riid
, ppDevice
);
950 HRESULT
create_buffer0()
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
;
958 usage
|= DXGI_USAGE_SHADER_INPUT
;
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
);
969 ComPtr
<IGalliumResource
> gallium_resource
;
970 hr
= new_buffer0
->QueryInterface(IID_IGalliumResource
, (void**)&gallium_resource
);
974 struct pipe_resource
* new_gallium_buffer0
= gallium_resource
->GetGalliumResource();
975 if(!new_gallium_buffer0
)
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
);
994 unsigned new_seq_num
;
995 needs_validation
= false;
997 if(!surface
->validate(surface
, (1 << NATIVE_ATTACHMENT_BACK_LEFT
) | (1 << NATIVE_ATTACHMENT_FRONT_LEFT
), &new_seq_num
, resources
, &width
, &height
))
1000 if(!ever_validated
|| seq_num
!= new_seq_num
)
1002 seq_num
= new_seq_num
;
1003 ever_validated
= true;
1008 virtual HRESULT STDMETHODCALLTYPE
Present(
1012 if(Flags
& DXGI_PRESENT_TEST
)
1017 HRESULT hr
= create_buffer0();
1022 void* cur_window
= 0;
1025 BOOL preserve_aspect_ratio
;
1026 unsigned dst_w
, dst_h
;
1028 struct pipe_resource
* dst
;
1029 struct pipe_resource
* src
;
1030 struct pipe_surface
* dst_surface
;
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
)
1036 if(cur_window
!= window
)
1038 window
= cur_window
;
1042 if(needs_validation
)
1045 return DXGI_ERROR_DEVICE_REMOVED
;
1048 db
= !!(config
->buffer_mask
& NATIVE_ATTACHMENT_BACK_LEFT
);
1049 dst
= resources
[db
? NATIVE_ATTACHMENT_BACK_LEFT
: NATIVE_ATTACHMENT_FRONT_LEFT
];
1050 src
= gallium_buffer0
;
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
1056 * We could alternatively force using another context, but that might cause inefficiency issues
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
;
1068 if(rect
.left
>= rect
.right
&& rect
.top
>= rect
.bottom
)
1071 dst_w
= rect
.right
- rect
.left
;
1072 dst_h
= rect
.bottom
- rect
.top
;
1074 // TODO: add support for rgndata
1075 // if(preserve_aspect_ratio || !rgndata)
1078 unsigned blit_x
, blit_y
, blit_w
, blit_h
;
1079 float black
[4] = {0, 0, 0, 0};
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
);
1084 if(preserve_aspect_ratio
)
1086 int delta
= src
->width0
* dst_h
- dst_w
* src
->height0
;
1090 blit_h
= dst_w
* src
->height0
/ src
->width0
;
1094 blit_w
= dst_h
* src
->width0
/ src
->height0
;
1103 blit_x
= (dst_w
- blit_w
) >> 1;
1104 blit_y
= (dst_h
- blit_h
) >> 1;
1115 pipe
->clear_render_target(pipe
, dst_surface
, black
, rect
.left
, rect
.top
, blit_x
, dst_h
);
1117 pipe
->clear_render_target(pipe
, dst_surface
, black
, rect
.left
, rect
.top
, dst_w
, blit_y
);
1119 if(formats_compatible
&& blit_w
== src
->width0
&& blit_h
== src
->height0
)
1121 pipe_subresource sr
;
1124 pipe
->resource_copy_region(pipe
, dst
, sr
, rect
.left
, rect
.top
, 0, src
, sr
, 0, 0, 0, blit_w
, blit_h
);
1128 blitter
->blit(dst_surface
, gallium_buffer0_view
, rect
.left
+ blit_x
, rect
.top
+ blit_y
, blit_w
, blit_h
);
1130 gallium_device
->RestoreGalliumState();
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
);
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
);
1140 pipe
->screen
->tex_surface_destroy(dst_surface
);
1144 if(!surface
->swap_buffers(surface
))
1145 return DXGI_ERROR_DEVICE_REMOVED
;
1149 if(!surface
->flush_frontbuffer(surface
))
1150 return DXGI_ERROR_DEVICE_REMOVED
;
1154 parent
->backend
->EndPresent(desc
.OutputWindow
, present_cookie
);
1160 virtual HRESULT STDMETHODCALLTYPE
GetBuffer(
1163 __out
void **ppSurface
)
1167 if(desc
.SwapEffect
== DXGI_SWAP_EFFECT_SEQUENTIAL
)
1168 std::cerr
<< "DXGI unimplemented: GetBuffer(n) with n > 0 not supported, returning buffer 0 instead!" << std::endl
;
1170 std::cerr
<< "DXGI error: in GetBuffer(n), n must be 0 for DXGI_SWAP_EFFECT_DISCARD\n" << std::endl
;
1175 HRESULT hr
= create_buffer0();
1179 return buffer0
->QueryInterface(riid
, ppSurface
);
1182 /* TODO: implement somehow */
1183 virtual HRESULT STDMETHODCALLTYPE
SetFullscreenState(
1185 __in_opt IDXGIOutput
*pTarget
)
1187 fullscreen
= Fullscreen
;
1192 virtual HRESULT STDMETHODCALLTYPE
GetFullscreenState(
1193 __out BOOL
*pFullscreen
,
1194 __out IDXGIOutput
**ppTarget
)
1197 *pFullscreen
= fullscreen
;
1199 *ppTarget
= target
.ref();
1203 virtual HRESULT STDMETHODCALLTYPE
GetDesc(
1204 __out DXGI_SWAP_CHAIN_DESC
*pDesc
)
1210 virtual HRESULT STDMETHODCALLTYPE
ResizeBuffers(
1214 DXGI_FORMAT NewFormat
,
1215 UINT SwapChainFlags
)
1219 buffer0
.p
->AddRef();
1220 ULONG v
= buffer0
.p
->Release();
1221 // we must fail if there are any references to buffer0 other than ours
1224 pipe_sampler_view_reference(&gallium_buffer0_view
, 0);
1225 buffer0
= (IUnknown
*)NULL
;
1226 gallium_buffer0
= 0;
1229 if(desc
.SwapEffect
!= DXGI_SWAP_EFFECT_SEQUENTIAL
)
1230 desc
.BufferCount
= BufferCount
;
1231 desc
.BufferDesc
.Format
= NewFormat
;
1232 desc
.BufferDesc
.Width
= Width
;
1233 desc
.BufferDesc
.Height
= Height
;
1234 desc
.Flags
= SwapChainFlags
;
1238 virtual HRESULT STDMETHODCALLTYPE
ResizeTarget(
1239 const DXGI_MODE_DESC
*pNewTargetParameters
)
1241 /* TODO: implement */
1245 virtual HRESULT STDMETHODCALLTYPE
GetContainingOutput(
1246 __out IDXGIOutput
**ppOutput
)
1248 *ppOutput
= adapter
->outputs
[0].ref();
1252 virtual HRESULT STDMETHODCALLTYPE
GetFrameStatistics(
1253 __out DXGI_FRAME_STATISTICS
*pStats
)
1255 memset(pStats
, 0, sizeof(*pStats
));
1257 QueryPerformanceCounter(&pStats
->SyncQPCTime
);
1259 pStats
->PresentCount
= present_count
;
1260 pStats
->PresentRefreshCount
= present_count
;
1261 pStats
->SyncRefreshCount
= present_count
;
1265 virtual HRESULT STDMETHODCALLTYPE
GetLastPresentCount(
1266 __out UINT
*pLastPresentCount
)
1268 *pLastPresentCount
= present_count
;
1273 static void GalliumDXGISwapChainRevalidate(IDXGISwapChain
* swap_chain
)
1275 ((GalliumDXGISwapChain
*)swap_chain
)->needs_validation
= true;
1278 static HRESULT
GalliumDXGIAdapterCreate(GalliumDXGIFactory
* factory
, const struct native_platform
* platform
, void* dpy
, IDXGIAdapter1
** pAdapter
)
1282 *pAdapter
= new GalliumDXGIAdapter(factory
, platform
, dpy
);
1291 static HRESULT
GalliumDXGIOutputCreate(GalliumDXGIAdapter
* adapter
, const std::string
& name
, const struct native_connector
* connector
, IDXGIOutput
** pOutput
)
1295 *pOutput
= new GalliumDXGIOutput(adapter
, name
, connector
);
1304 static HRESULT
GalliumDXGISwapChainCreate(GalliumDXGIFactory
* factory
, IUnknown
* device
, const DXGI_SWAP_CHAIN_DESC
& desc
, IDXGISwapChain
** pSwapChain
)
1308 *pSwapChain
= new GalliumDXGISwapChain(factory
, device
, desc
);
1319 const struct native_platform
* platform
;
1321 IGalliumDXGIBackend
* backend
;
1324 static dxgi_binding dxgi_default_binding
;
1325 static __thread dxgi_binding dxgi_thread_binding
;
1327 void STDMETHODCALLTYPE
GalliumDXGIUseNothing()
1329 dxgi_thread_binding
.platform
= 0;
1330 dxgi_thread_binding
.display
= 0;
1331 if(dxgi_thread_binding
.backend
)
1332 dxgi_thread_binding
.backend
->Release();
1333 dxgi_thread_binding
.backend
= 0;
1336 #ifdef GALLIUM_DXGI_USE_X11
1337 void STDMETHODCALLTYPE
GalliumDXGIUseX11Display(Display
* dpy
, IGalliumDXGIBackend
* backend
)
1339 GalliumDXGIUseNothing();
1340 dxgi_thread_binding
.platform
= native_get_x11_platform();
1341 dxgi_thread_binding
.display
= dpy
;
1345 dxgi_thread_binding
.backend
= backend
;
1352 #ifdef GALLIUM_DXGI_USE_DRM
1353 void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd)
1355 GalliumDXGIUseNothing();
1356 dxgi_thread_binding.platform = native_get_drm_platform();
1357 dxgi_thread_binding.display = (void*)fd;
1358 dxgi_thread_binding.backend = 0;
1362 #ifdef GALLIUM_DXGI_USE_FBDEV
1363 void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd)
1365 GalliumDXGIUseNothing();
1366 dxgi_thread_binding.platform = native_get_fbdev_platform();
1367 dxgi_thread_binding.display = (void*)fd;
1368 dxgi_thread_binding.backend = 0;
1372 #ifdef GALLIUM_DXGI_USE_GDI
1373 void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie)
1375 GalliumDXGIUseNothing();
1376 dxgi_thread_binding.platform = native_get_gdi_platform();
1377 dxgi_thread_binding.display = (void*)hdc;
1378 dxgi_thread_binding.backend = 0;
1382 void STDMETHODCALLTYPE
GalliumDXGIMakeDefault()
1384 if(dxgi_default_binding
.backend
)
1385 dxgi_default_binding
.backend
->Release();
1386 dxgi_default_binding
= dxgi_thread_binding
;
1387 if(dxgi_default_binding
.backend
)
1388 dxgi_default_binding
.backend
->AddRef();
1391 /* TODO: why did Microsoft add this? should we do something different for DXGI 1.0 and 1.1?
1392 * Or perhaps what they actually mean is "only create a single factory in your application"?
1393 * TODO: should we use a singleton here, so we never have multiple DXGI objects for the same thing? */
1394 HRESULT STDMETHODCALLTYPE
CreateDXGIFactory1(
1396 __out
void **ppFactory
1399 GalliumDXGIFactory
* factory
;
1401 if(dxgi_thread_binding
.platform
)
1402 factory
= new GalliumDXGIFactory(dxgi_thread_binding
.platform
, dxgi_thread_binding
.display
, dxgi_thread_binding
.backend
);
1403 else if(dxgi_default_binding
.platform
)
1404 factory
= new GalliumDXGIFactory(dxgi_default_binding
.platform
, dxgi_default_binding
.display
, dxgi_default_binding
.backend
);
1406 factory
= new GalliumDXGIFactory(native_get_x11_platform(), NULL
, NULL
);
1407 HRESULT hres
= factory
->QueryInterface(riid
, ppFactory
);
1412 HRESULT STDMETHODCALLTYPE
CreateDXGIFactory(
1414 __out
void **ppFactory
1417 return CreateDXGIFactory1(riid
, ppFactory
);