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 static void* STDMETHODCALLTYPE
identity_resolver(void* cookie
, HWND hwnd
)
71 struct GalliumDXGIFactory
: public GalliumDXGIObject
<IDXGIFactory1
, IUnknown
>
73 HWND associated_window
;
74 const struct native_platform
* platform
;
76 PFNHWNDRESOLVER resolver
;
77 void* resolver_cookie
;
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
)
83 virtual HRESULT STDMETHODCALLTYPE
EnumAdapters(
85 __out IDXGIAdapter
**ppAdapter
)
87 return EnumAdapters1(Adapter
, (IDXGIAdapter1
**)ppAdapter
);
90 virtual HRESULT STDMETHODCALLTYPE
EnumAdapters1(
92 __out IDXGIAdapter1
**ppAdapter
)
97 return GalliumDXGIAdapterCreate(this, platform
, display
, ppAdapter
);
101 if(platform
== native_get_x11_platform())
103 unsigned nscreens
= ScreenCount((Display
*)display
);
104 if(Adapter
< nscreens
)
106 unsigned def_screen
= DefaultScreen(display
);
107 if(Adapter
<= def_screen
)
109 *ppAdapter
= GalliumDXGIAdapterCreate(this, platform
, display
, Adapter
);
114 return DXGI_ERROR_NOT_FOUND
;
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?
124 virtual HRESULT STDMETHODCALLTYPE
MakeWindowAssociation(
128 /* TODO: actually implement, for Wine, X11 and KMS*/
129 associated_window
= WindowHandle
;
133 virtual HRESULT STDMETHODCALLTYPE
GetWindowAssociation(
134 __out HWND
*pWindowHandle
)
136 *pWindowHandle
= associated_window
;
140 virtual HRESULT STDMETHODCALLTYPE
CreateSwapChain(
141 __in IUnknown
*pDevice
,
142 __in DXGI_SWAP_CHAIN_DESC
*pDesc
,
143 __out IDXGISwapChain
**ppSwapChain
)
145 return GalliumDXGISwapChainCreate(this, pDevice
, *pDesc
, ppSwapChain
);
148 virtual HRESULT STDMETHODCALLTYPE
CreateSoftwareAdapter(
150 __out IDXGIAdapter
**ppAdapter
)
152 /* TODO: ignore the module, and just create a Gallium software screen */
157 /* TODO: support hotplug */
158 virtual BOOL STDMETHODCALLTYPE
IsCurrent( void)
164 struct GalliumDXGIAdapter
165 : public GalliumMultiComObject
<
166 GalliumDXGIObject
<IDXGIAdapter1
, GalliumDXGIFactory
>,
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
;
178 struct native_event_handler handler
;
180 GalliumDXGIAdapter(GalliumDXGIFactory
* factory
, const struct native_platform
* platform
, void* dpy
)
182 this->parent
= factory
;
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);
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
);
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
];
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;
202 // TODO: we should actually use an unique ID instead
203 *(void**)&desc
.AdapterLuid
= dpy
;
205 configs
= display
->get_configs(display
, (int*)&num_configs
);
206 for(unsigned i
= 0; i
< num_configs
; ++i
)
208 if(configs
[i
]->window_bit
)
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
;
222 connectors
= display
->modeset
->get_connectors(display
, &num_outputs
, &num_crtcs
);
225 else if(!num_outputs
)
235 static void handle_invalid_surface(struct native_display
*ndpy
, struct native_surface
*nsurf
, unsigned int seq_num
)
237 GalliumDXGISwapChainRevalidate((IDXGISwapChain
*)nsurf
->user_data
);
240 ~GalliumDXGIAdapter()
246 virtual HRESULT STDMETHODCALLTYPE
EnumOutputs(
248 __out IDXGIOutput
**ppOutput
)
250 if(Output
>= (unsigned)num_outputs
)
251 return DXGI_ERROR_NOT_FOUND
;
255 std::ostringstream ss
;
256 ss
<< "Output #" << Output
;
257 return GalliumDXGIOutputCreate(this, ss
.str(), connectors
[Output
], ppOutput
);
260 return GalliumDXGIOutputCreate(this, "Unique output", NULL
, ppOutput
);
263 virtual HRESULT STDMETHODCALLTYPE
GetDesc(
264 __out DXGI_ADAPTER_DESC
*pDesc
)
266 memcpy(pDesc
, &desc
, sizeof(*pDesc
));
270 virtual HRESULT STDMETHODCALLTYPE
GetDesc1(
271 __out DXGI_ADAPTER_DESC1
*pDesc
)
273 memcpy(pDesc
, &desc
, sizeof(*pDesc
));
277 virtual HRESULT STDMETHODCALLTYPE
CheckInterfaceSupport(
278 __in REFGUID InterfaceName
,
279 __out LARGE_INTEGER
*pUMDVersion
)
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
)
284 pUMDVersion
->QuadPart
= 0x00080011000a0411ULL
;
287 return DXGI_ERROR_UNSUPPORTED
;
290 pipe_screen
* STDMETHODCALLTYPE
GetGalliumScreen()
292 return display
->screen
;
295 pipe_screen
* STDMETHODCALLTYPE
GetGalliumReferenceSoftwareScreen()
297 // TODO: give a softpipe screen
298 return display
->screen
;
301 pipe_screen
* STDMETHODCALLTYPE
GetGalliumFastSoftwareScreen()
303 // TODO: give an llvmpipe screen
304 return display
->screen
;
309 struct GalliumDXGIOutput
: public GalliumDXGIObject
<IDXGIOutput
, GalliumDXGIAdapter
>
311 DXGI_OUTPUT_DESC desc
;
312 const struct native_mode
** modes
;
313 DXGI_MODE_DESC
* dxgi_modes
;
315 const struct native_connector
* connector
;
316 DXGI_GAMMA_CONTROL
* gamma
;
318 GalliumDXGIOutput(GalliumDXGIAdapter
* adapter
, std::string name
, const struct native_connector
* connector
= 0)
319 : GalliumDXGIObject(adapter
), connector(connector
)
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 */
332 modes
= parent
->display
->modeset
->get_modes(parent
->display
, connector
, (int*)&num_modes
);
333 if(modes
&& num_modes
)
335 dxgi_modes
= new DXGI_MODE_DESC
[num_modes
];
336 for(unsigned i
= 0; i
< num_modes
; ++i
)
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
;
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
;
371 delete [] dxgi_modes
;
377 virtual HRESULT STDMETHODCALLTYPE
GetDesc(
378 __out DXGI_OUTPUT_DESC
*pDesc
)
384 virtual HRESULT STDMETHODCALLTYPE
GetDisplayModeList(
385 DXGI_FORMAT EnumFormat
,
387 __inout UINT
*pNumModes
,
388 __out_ecount_part_opt(*pNumModes
,*pNumModes
) DXGI_MODE_DESC
*pDesc
)
390 /* TODO: should we return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE when we don't
391 * support modesetting instead of fake modes?
393 pipe_format format
= dxgi_to_pipe_format
[EnumFormat
];
394 if(parent
->configs_by_pipe_format
.count(format
))
398 *pNumModes
= num_modes
;
402 unsigned copy_modes
= std::min(num_modes
, *pNumModes
);
403 for(unsigned i
= 0; i
< copy_modes
; ++i
)
405 pDesc
[i
] = dxgi_modes
[i
];
406 pDesc
[i
].Format
= EnumFormat
;
408 *pNumModes
= num_modes
;
410 if(copy_modes
< num_modes
)
411 return DXGI_ERROR_MORE_DATA
;
422 virtual HRESULT STDMETHODCALLTYPE
FindClosestMatchingMode(
423 __in
const DXGI_MODE_DESC
*pModeToMatch
,
424 __out DXGI_MODE_DESC
*pClosestMatch
,
425 __in_opt IUnknown
*pConcernedDevice
)
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
))
433 if(!pConcernedDevice
)
437 format
= parent
->configs
[0]->color_format
;
438 dxgi_format
= pipe_to_dxgi_format
[format
];
442 *pClosestMatch
= dxgi_modes
[0];
443 pClosestMatch
->Format
= dxgi_format
;
447 virtual HRESULT STDMETHODCALLTYPE
WaitForVBlank( void)
452 virtual HRESULT STDMETHODCALLTYPE
TakeOwnership(
453 __in IUnknown
*pDevice
,
459 virtual void STDMETHODCALLTYPE
ReleaseOwnership( void)
463 virtual HRESULT STDMETHODCALLTYPE
GetGammaControlCapabilities(
464 __out DXGI_GAMMA_CONTROL_CAPABILITIES
*pGammaCaps
)
466 memset(pGammaCaps
, 0, sizeof(*pGammaCaps
));
470 virtual HRESULT STDMETHODCALLTYPE
SetGammaControl(
471 __in
const DXGI_GAMMA_CONTROL
*pArray
)
474 gamma
= new DXGI_GAMMA_CONTROL
;
479 virtual HRESULT STDMETHODCALLTYPE
GetGammaControl(
480 __out DXGI_GAMMA_CONTROL
*pArray
)
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;
498 virtual HRESULT STDMETHODCALLTYPE
SetDisplaySurface(
499 __in IDXGISurface
*pScanoutSurface
)
504 virtual HRESULT STDMETHODCALLTYPE
GetDisplaySurfaceData(
505 __in IDXGISurface
*pDestination
)
510 virtual HRESULT STDMETHODCALLTYPE
GetFrameStatistics(
511 __out DXGI_FRAME_STATISTICS
*pStats
)
513 memset(pStats
, 0, sizeof(*pStats
));
515 QueryPerformanceCounter(&pStats
->SyncQPCTime
);
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
526 * There are two modes (called "swap effects") that a swap chain can operate in:
527 * discard and sequential.
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.
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
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().
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.
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.
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
576 * How does Microsoft implement the rotation behavior?
577 * It turns out that it does it by calling RotateResourceIdentitiesDXGI in the user-mode
579 * This will rotate the kernel buffer handle, or possibly rotate the GPU virtual memory
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.
587 * OK, so how do we implement this in Gallium?
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.
600 * (2) is not acceptable since it prevents an optimal implementation.
601 * (3) is the ideal solution, but it is complicated.
603 * Hence, we implement (1) for now, and will switch to (3) later.
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..
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.
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.
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
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
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.
637 * "DXGI Overview" in MSDN
638 * IDXGISwapChain documentation on MSDN
639 * "RotateResourceIdentitiesDXGI" on MSDN
640 * http://forums.xna.com/forums/p/42362/266016.aspx
643 static float quad_data
[] = {
661 struct pipe_clip_state clip
;
662 struct pipe_vertex_buffer vbuf
;
663 struct pipe_draw_info draw
;
665 dxgi_blitter(pipe_context
* pipe
)
668 //normalized = !!pipe->screen->get_param(pipe, PIPE_CAP_NPOT_TEXTURES);
669 // TODO: need to update buffer in unnormalized case
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
);
679 struct pipe_blend_state blendd
;
680 blendd
.rt
[0].colormask
= PIPE_MASK_RGBA
;
681 blend
= pipe
->create_blend_state(pipe
, &blendd
);
683 struct pipe_depth_stencil_alpha_state zsad
;
684 memset(&zsad
, 0, sizeof(zsad
));
685 zsa
= pipe
->create_depth_stencil_alpha_state(pipe
, &zsad
);
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]);
695 for(unsigned stretch
= 0; stretch
< 2; ++stretch
)
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
;
706 sampler
[stretch
] = pipe
->create_sampler_state(pipe
, &sampler_state
);
709 fs
= util_make_fragment_tex_shader(pipe
, normalized
? TGSI_TEXTURE_2D
: TGSI_TEXTURE_RECT
, TGSI_INTERPOLATE_LINEAR
);
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
);
715 vbuf
.buffer
= pipe_buffer_create(pipe
->screen
, PIPE_BIND_VERTEX_BUFFER
, sizeof(quad_data
));
716 vbuf
.buffer_offset
= 0;
718 vbuf
.stride
= 4 * sizeof(float);
719 pipe_buffer_write(pipe
, vbuf
.buffer
, 0, sizeof(quad_data
), quad_data
);
721 memset(&clip
, 0, sizeof(clip
));
723 memset(&draw
, 0, sizeof(draw
));
724 draw
.mode
= PIPE_PRIM_QUADS
;
726 draw
.instance_count
= 1;
730 void blit(struct pipe_surface
* surf
, struct pipe_sampler_view
* view
, unsigned x
, unsigned y
, unsigned w
, unsigned h
)
732 struct pipe_framebuffer_state fb
;
733 memset(&fb
, 0, sizeof(fb
));
736 fb
.width
= surf
->width
;
737 fb
.height
= surf
->height
;
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
;
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
);
771 pipe
->draw_vbo(pipe
, &draw
);
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
);
788 struct GalliumDXGISwapChain
: public GalliumDXGIObject
<IDXGISwapChain
, GalliumDXGIFactory
>
790 ComPtr
<IDXGIDevice
>dxgi_device
;
791 ComPtr
<IGalliumDevice
>gallium_device
;
792 ComPtr
<GalliumDXGIAdapter
> adapter
;
793 ComPtr
<IDXGIOutput
> target
;
795 struct native_surface
* surface
;
796 const struct native_config
* config
;
798 struct pipe_resource
* resources
[NUM_NATIVE_ATTACHMENTS
];
803 bool needs_validation
;
804 unsigned present_count
;
806 ComPtr
<IDXGISurface
> buffer0
;
807 struct pipe_resource
* gallium_buffer0
;
808 struct pipe_sampler_view
* gallium_buffer0_view
;
810 DXGI_SWAP_CHAIN_DESC desc
;
812 struct pipe_context
* pipe
;
817 std::auto_ptr
<dxgi_blitter
> blitter
;
818 bool formats_compatible
;
820 GalliumDXGISwapChain(GalliumDXGIFactory
* factory
, IUnknown
* p_device
, const DXGI_SWAP_CHAIN_DESC
& p_desc
)
821 : GalliumDXGIObject(factory
), desc(p_desc
)
825 hr
= p_device
->QueryInterface(IID_IGalliumDevice
, (void**)&gallium_device
);
829 hr
= p_device
->QueryInterface(IID_IDXGIDevice
, (void**)&dxgi_device
);
833 hr
= dxgi_device
->GetAdapter((IDXGIAdapter
**)&adapter
);
837 void* win
= factory
->resolver(factory
->resolver_cookie
, desc
.OutputWindow
);
840 if(!strcmp(factory
->platform
->name
, "X11"))
842 XWindowAttributes xwa
;
843 XGetWindowAttributes((Display
*)factory
->display
, (Window
)win
, &xwa
);
844 config_num
= adapter
->configs_by_native_visual_id
[xwa
.visual
->visualid
];
848 enum pipe_format format
= dxgi_to_pipe_format
[desc
.BufferDesc
.Format
];
849 if(!adapter
->configs_by_pipe_format
.count(format
))
851 if(adapter
->configs_by_pipe_format
.empty())
853 // TODO: choose the best match
854 format
= (pipe_format
)adapter
->configs_by_pipe_format
.begin()->first
;
856 // TODO: choose the best config
857 config_num
= adapter
->configs_by_pipe_format
.find(format
)->second
;
860 config
= adapter
->configs
[config_num
];
861 surface
= adapter
->display
->create_window_surface(adapter
->display
, (EGLNativeWindowType
)win
, config
);
862 surface
->user_data
= this;
868 needs_validation
= true;
869 ever_validated
= false;
871 if(desc
.SwapEffect
== DXGI_SWAP_EFFECT_SEQUENTIAL
&& desc
.BufferCount
!= 1)
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;
878 pipe
= gallium_device
->GetGalliumContext();
882 pipe
= adapter
->display
->screen
->context_create(adapter
->display
->screen
, 0);
886 blitter
.reset(new dxgi_blitter(pipe
));
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
));
893 ~GalliumDXGISwapChain()
899 virtual HRESULT STDMETHODCALLTYPE
GetDevice(
901 __out
void **ppDevice
)
903 return dxgi_device
->QueryInterface(riid
, ppDevice
);
906 HRESULT
create_buffer0()
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
;
914 usage
|= DXGI_USAGE_SHADER_INPUT
;
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
);
925 ComPtr
<IGalliumResource
> gallium_resource
;
926 hr
= new_buffer0
->QueryInterface(IID_IGalliumResource
, (void**)&gallium_resource
);
930 struct pipe_resource
* new_gallium_buffer0
= gallium_resource
->GetGalliumResource();
931 if(!new_gallium_buffer0
)
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
);
950 unsigned new_seq_num
;
951 needs_validation
= false;
953 if(!surface
->validate(surface
, 1 << NATIVE_ATTACHMENT_BACK_LEFT
, &new_seq_num
, resources
, &width
, &height
))
956 if(!ever_validated
|| seq_num
!= new_seq_num
)
958 seq_num
= new_seq_num
;
959 ever_validated
= true;
964 virtual HRESULT STDMETHODCALLTYPE
Present(
968 if(Flags
& DXGI_PRESENT_TEST
)
973 HRESULT hr
= create_buffer0();
981 return DXGI_ERROR_DEVICE_REMOVED
;
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;
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
992 * We could alternatively force using another context, but that might cause inefficiency issues
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
998 unsigned blit_x
, blit_y
, blit_w
, blit_h
;
999 float black
[4] = {0, 0, 0, 0};
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
);
1004 int delta
= src
->width0
* dst
->height0
- dst
->width0
* src
->height0
;
1007 blit_w
= dst
->width0
;
1008 blit_h
= dst
->width0
* src
->height0
/ src
->width0
;
1012 blit_w
= dst
->height0
* src
->width0
/ src
->height0
;
1013 blit_h
= dst
->height0
;
1017 blit_w
= dst
->width0
;
1018 blit_h
= dst
->height0
;
1021 blit_x
= (dst
->width0
- blit_w
) >> 1;
1022 blit_y
= (dst
->height0
- blit_h
) >> 1;
1025 pipe
->clear_render_target(pipe
, dst_surface
, black
, 0, 0, blit_x
, dst
->height0
);
1027 pipe
->clear_render_target(pipe
, dst_surface
, black
, 0, 0, dst
->width0
, blit_y
);
1029 if(formats_compatible
&& blit_w
== src
->width0
&& blit_h
== src
->height0
)
1031 pipe_subresource sr
;
1034 pipe
->resource_copy_region(pipe
, dst
, sr
, 0, 0, 0, src
, sr
, 0, 0, 0, blit_w
, blit_h
);
1038 blitter
->blit(dst_surface
, gallium_buffer0_view
, blit_x
, blit_y
, blit_w
, blit_h
);
1040 gallium_device
->RestoreGalliumState();
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
);
1049 pipe
->screen
->tex_surface_destroy(dst_surface
);
1053 if(!surface
->swap_buffers(surface
))
1054 return DXGI_ERROR_DEVICE_REMOVED
;
1058 if(!surface
->flush_frontbuffer(surface
))
1059 return DXGI_ERROR_DEVICE_REMOVED
;
1066 virtual HRESULT STDMETHODCALLTYPE
GetBuffer(
1069 __out
void **ppSurface
)
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
;
1076 std::cerr
<< "DXGI error: in GetBuffer(n), n must be 0 for DXGI_SWAP_EFFECT_DISCARD\n" << std::endl
;
1081 HRESULT hr
= create_buffer0();
1085 return buffer0
->QueryInterface(riid
, ppSurface
);
1088 /* TODO: implement somehow */
1089 virtual HRESULT STDMETHODCALLTYPE
SetFullscreenState(
1091 __in_opt IDXGIOutput
*pTarget
)
1093 fullscreen
= Fullscreen
;
1098 virtual HRESULT STDMETHODCALLTYPE
GetFullscreenState(
1099 __out BOOL
*pFullscreen
,
1100 __out IDXGIOutput
**ppTarget
)
1103 *pFullscreen
= fullscreen
;
1105 *ppTarget
= target
.ref();
1109 virtual HRESULT STDMETHODCALLTYPE
GetDesc(
1110 __out DXGI_SWAP_CHAIN_DESC
*pDesc
)
1116 virtual HRESULT STDMETHODCALLTYPE
ResizeBuffers(
1120 DXGI_FORMAT NewFormat
,
1121 UINT SwapChainFlags
)
1125 buffer0
.p
->AddRef();
1126 ULONG v
= buffer0
.p
->Release();
1127 // we must fail if there are any references to buffer0 other than ours
1130 pipe_sampler_view_reference(&gallium_buffer0_view
, 0);
1131 buffer0
= (IUnknown
*)NULL
;
1132 gallium_buffer0
= 0;
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
;
1144 virtual HRESULT STDMETHODCALLTYPE
ResizeTarget(
1145 const DXGI_MODE_DESC
*pNewTargetParameters
)
1147 /* TODO: implement */
1151 virtual HRESULT STDMETHODCALLTYPE
GetContainingOutput(
1152 __out IDXGIOutput
**ppOutput
)
1154 *ppOutput
= adapter
->outputs
[0].ref();
1158 virtual HRESULT STDMETHODCALLTYPE
GetFrameStatistics(
1159 __out DXGI_FRAME_STATISTICS
*pStats
)
1161 memset(pStats
, 0, sizeof(*pStats
));
1163 QueryPerformanceCounter(&pStats
->SyncQPCTime
);
1165 pStats
->PresentCount
= present_count
;
1166 pStats
->PresentRefreshCount
= present_count
;
1167 pStats
->SyncRefreshCount
= present_count
;
1171 virtual HRESULT STDMETHODCALLTYPE
GetLastPresentCount(
1172 __out UINT
*pLastPresentCount
)
1174 *pLastPresentCount
= present_count
;
1179 static void GalliumDXGISwapChainRevalidate(IDXGISwapChain
* swap_chain
)
1181 ((GalliumDXGISwapChain
*)swap_chain
)->needs_validation
= true;
1184 static HRESULT
GalliumDXGIAdapterCreate(GalliumDXGIFactory
* factory
, const struct native_platform
* platform
, void* dpy
, IDXGIAdapter1
** pAdapter
)
1188 *pAdapter
= new GalliumDXGIAdapter(factory
, platform
, dpy
);
1197 static HRESULT
GalliumDXGIOutputCreate(GalliumDXGIAdapter
* adapter
, const std::string
& name
, const struct native_connector
* connector
, IDXGIOutput
** pOutput
)
1201 *pOutput
= new GalliumDXGIOutput(adapter
, name
, connector
);
1210 static HRESULT
GalliumDXGISwapChainCreate(GalliumDXGIFactory
* factory
, IUnknown
* device
, const DXGI_SWAP_CHAIN_DESC
& desc
, IDXGISwapChain
** pSwapChain
)
1214 *pSwapChain
= new GalliumDXGISwapChain(factory
, device
, desc
);
1225 const struct native_platform
* platform
;
1227 PFNHWNDRESOLVER resolver
;
1228 void* resolver_cookie
;
1231 static dxgi_binding dxgi_default_binding
;
1232 static __thread dxgi_binding dxgi_thread_binding
;
1234 void STDMETHODCALLTYPE
GalliumDXGIUseNothing()
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;
1242 #ifdef GALLIUM_DXGI_USE_X11
1243 void STDMETHODCALLTYPE
GalliumDXGIUseX11Display(Display
* dpy
, PFNHWNDRESOLVER resolver
, void* resolver_cookie
)
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
;
1252 #ifdef GALLIUM_DXGI_USE_DRM
1253 void STDMETHODCALLTYPE
GalliumDXGIUseDRMCard(int fd
)
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;
1262 #ifdef GALLIUM_DXGI_USE_FBDEV
1263 void STDMETHODCALLTYPE
GalliumDXGIUseFBDev(int fd
)
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;
1272 #ifdef GALLIUM_DXGI_USE_GDI
1273 void STDMETHODCALLTYPE
GalliumDXGIUseHDC(HDC hdc
, PFNHWNDRESOLVER resolver
, void* resolver_cookie
)
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
;
1282 void STDMETHODCALLTYPE
GalliumDXGIMakeDefault()
1284 dxgi_default_binding
= dxgi_thread_binding
;
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(
1292 __out
void **ppFactory
1295 GalliumDXGIFactory
* factory
;
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
);
1302 factory
= new GalliumDXGIFactory(native_get_x11_platform(), NULL
, NULL
, NULL
);
1303 HRESULT hres
= factory
->QueryInterface(riid
, ppFactory
);
1308 HRESULT STDMETHODCALLTYPE
CreateDXGIFactory(
1310 __out
void **ppFactory
1313 return CreateDXGIFactory1(riid
, ppFactory
);