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
** 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
);
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(
62 return parent
->QueryInterface(riid
, out_parent
);
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 IDXGIAdapter
**out_adapter
)
118 return EnumAdapters1(adapter
, (IDXGIAdapter1
**)out_adapter
);
121 virtual HRESULT STDMETHODCALLTYPE
EnumAdapters1(
123 IDXGIAdapter1
**out_adapter
)
128 return GalliumDXGIAdapterCreate(this, platform
, display
, out_adapter
);
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 *out_adapter
= 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
= window_handle
;
164 virtual HRESULT STDMETHODCALLTYPE
GetWindowAssociation(
165 HWND
*pwindow_handle
)
167 *pwindow_handle
= associated_window
;
171 virtual HRESULT STDMETHODCALLTYPE
CreateSwapChain(
173 DXGI_SWAP_CHAIN_DESC
*desc
,
174 IDXGISwapChain
**out_swap_chain
)
176 return GalliumDXGISwapChainCreate(this, device
, *desc
, out_swap_chain
);
179 virtual HRESULT STDMETHODCALLTYPE
CreateSoftwareAdapter(
181 IDXGIAdapter
**out_adapter
)
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 IDXGIOutput
**out_output
)
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
], out_output
);
292 return GalliumDXGIOutputCreate(this, "Unique output", NULL
, out_output
);
295 virtual HRESULT STDMETHODCALLTYPE
GetDesc(
296 DXGI_ADAPTER_DESC
*desc
)
298 memcpy(desc
, &desc
, sizeof(*desc
));
302 virtual HRESULT STDMETHODCALLTYPE
GetDesc1(
303 DXGI_ADAPTER_DESC1
*desc
)
305 memcpy(desc
, &desc
, sizeof(*desc
));
309 virtual HRESULT STDMETHODCALLTYPE
CheckInterfaceSupport(
310 REFGUID interface_name
,
311 LARGE_INTEGER
*u_m_d_version
)
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
)
316 u_m_d_version
->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 DXGI_OUTPUT_DESC
*out_desc
)
416 virtual HRESULT STDMETHODCALLTYPE
GetDisplayModeList(
417 DXGI_FORMAT enum_format
,
420 DXGI_MODE_DESC
*desc
)
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
[enum_format
];
426 if(parent
->configs_by_pipe_format
.count(format
))
434 unsigned copy_modes
= std::min(num_modes
, *pcount
);
435 for(unsigned i
= 0; i
< copy_modes
; ++i
)
437 desc
[i
] = dxgi_modes
[i
];
438 desc
[i
].Format
= enum_format
;
442 if(copy_modes
< num_modes
)
443 return DXGI_ERROR_MORE_DATA
;
454 virtual HRESULT STDMETHODCALLTYPE
FindClosestMatchingMode(
455 const DXGI_MODE_DESC
*pModeToMatch
,
456 DXGI_MODE_DESC
*closest_match
,
457 IUnknown
*concerned_device
)
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(!concerned_device
)
469 format
= parent
->configs
[0]->color_format
;
470 dxgi_format
= pipe_to_dxgi_format
[format
];
474 *closest_match
= dxgi_modes
[0];
475 closest_match
->Format
= dxgi_format
;
479 virtual HRESULT STDMETHODCALLTYPE
WaitForVBlank( void)
484 virtual HRESULT STDMETHODCALLTYPE
TakeOwnership(
491 virtual void STDMETHODCALLTYPE
ReleaseOwnership( void)
495 virtual HRESULT STDMETHODCALLTYPE
GetGammaControlCapabilities(
496 DXGI_GAMMA_CONTROL_CAPABILITIES
*gamma_caps
)
498 memset(gamma_caps
, 0, sizeof(*gamma_caps
));
502 virtual HRESULT STDMETHODCALLTYPE
SetGammaControl(
503 const DXGI_GAMMA_CONTROL
*pArray
)
506 gamma
= new DXGI_GAMMA_CONTROL
;
511 virtual HRESULT STDMETHODCALLTYPE
GetGammaControl(
512 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 IDXGISurface
*scanout_surface
)
536 virtual HRESULT STDMETHODCALLTYPE
GetDisplaySurfaceData(
537 IDXGISurface
*destination
)
542 virtual HRESULT STDMETHODCALLTYPE
GetFrameStatistics(
543 DXGI_FRAME_STATISTICS
*stats
)
545 memset(stats
, 0, sizeof(*stats
));
547 QueryPerformanceCounter(&stats
->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 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.
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
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 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.
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
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 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;
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(
947 return dxgi_device
->QueryInterface(riid
, pdevice
);
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
& (1 << 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
);
1142 pipe
->flush(pipe
, PIPE_FLUSH_RENDER_CACHE
| PIPE_FLUSH_FRAME
, 0);
1146 if(!surface
->swap_buffers(surface
))
1147 return DXGI_ERROR_DEVICE_REMOVED
;
1151 if(!surface
->flush_frontbuffer(surface
))
1152 return DXGI_ERROR_DEVICE_REMOVED
;
1156 parent
->backend
->EndPresent(desc
.OutputWindow
, present_cookie
);
1162 virtual HRESULT STDMETHODCALLTYPE
GetBuffer(
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
;
1172 std::cerr
<< "DXGI error: in GetBuffer(n), n must be 0 for DXGI_SWAP_EFFECT_DISCARD\n" << std::endl
;
1177 HRESULT hr
= create_buffer0();
1181 return buffer0
->QueryInterface(riid
, ppSurface
);
1184 /* TODO: implement somehow */
1185 virtual HRESULT STDMETHODCALLTYPE
SetFullscreenState(
1187 IDXGIOutput
*target
)
1189 fullscreen
= fullscreen
;
1194 virtual HRESULT STDMETHODCALLTYPE
GetFullscreenState(
1195 BOOL
*out_fullscreen
,
1196 IDXGIOutput
**out_target
)
1199 *out_fullscreen
= fullscreen
;
1201 *out_target
= target
.ref();
1205 virtual HRESULT STDMETHODCALLTYPE
GetDesc(
1206 DXGI_SWAP_CHAIN_DESC
*out_desc
)
1212 virtual HRESULT STDMETHODCALLTYPE
ResizeBuffers(
1216 DXGI_FORMAT new_format
,
1217 UINT swap_chain_flags
)
1221 buffer0
.p
->AddRef();
1222 ULONG v
= buffer0
.p
->Release();
1223 // we must fail if there are any references to buffer0 other than ours
1226 pipe_sampler_view_reference(&gallium_buffer0_view
, 0);
1227 buffer0
= (IUnknown
*)NULL
;
1228 gallium_buffer0
= 0;
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
;
1240 virtual HRESULT STDMETHODCALLTYPE
ResizeTarget(
1241 const DXGI_MODE_DESC
*out_new_target_parameters
)
1243 /* TODO: implement */
1247 virtual HRESULT STDMETHODCALLTYPE
GetContainingOutput(
1248 IDXGIOutput
**out_output
)
1250 *out_output
= adapter
->outputs
[0].ref();
1254 virtual HRESULT STDMETHODCALLTYPE
GetFrameStatistics(
1255 DXGI_FRAME_STATISTICS
*out_stats
)
1257 memset(out_stats
, 0, sizeof(*out_stats
));
1259 QueryPerformanceCounter(&out_stats
->SyncQPCTime
);
1261 out_stats
->PresentCount
= present_count
;
1262 out_stats
->PresentRefreshCount
= present_count
;
1263 out_stats
->SyncRefreshCount
= present_count
;
1267 virtual HRESULT STDMETHODCALLTYPE
GetLastPresentCount(
1268 UINT
*last_present_count
)
1270 *last_present_count
= present_count
;
1275 static void GalliumDXGISwapChainRevalidate(IDXGISwapChain
* swap_chain
)
1277 ((GalliumDXGISwapChain
*)swap_chain
)->needs_validation
= true;
1280 static HRESULT
GalliumDXGIAdapterCreate(GalliumDXGIFactory
* factory
, const struct native_platform
* platform
, void* dpy
, IDXGIAdapter1
** out_adapter
)
1284 *out_adapter
= new GalliumDXGIAdapter(factory
, platform
, dpy
);
1293 static HRESULT
GalliumDXGIOutputCreate(GalliumDXGIAdapter
* adapter
, const std::string
& name
, const struct native_connector
* connector
, IDXGIOutput
** out_output
)
1297 *out_output
= new GalliumDXGIOutput(adapter
, name
, connector
);
1306 static HRESULT
GalliumDXGISwapChainCreate(GalliumDXGIFactory
* factory
, IUnknown
* device
, const DXGI_SWAP_CHAIN_DESC
& desc
, IDXGISwapChain
** out_swap_chain
)
1310 *out_swap_chain
= new GalliumDXGISwapChain(factory
, device
, desc
);
1321 const struct native_platform
* platform
;
1323 IGalliumDXGIBackend
* backend
;
1326 static dxgi_binding dxgi_default_binding
;
1327 static __thread dxgi_binding dxgi_thread_binding
;
1329 void STDMETHODCALLTYPE
GalliumDXGIUseNothing()
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;
1338 #ifdef GALLIUM_DXGI_USE_X11
1339 void STDMETHODCALLTYPE
GalliumDXGIUseX11Display(Display
* dpy
, IGalliumDXGIBackend
* backend
)
1341 GalliumDXGIUseNothing();
1342 dxgi_thread_binding
.platform
= native_get_x11_platform();
1343 dxgi_thread_binding
.display
= dpy
;
1347 dxgi_thread_binding
.backend
= backend
;
1354 #ifdef GALLIUM_DXGI_USE_DRM
1355 void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd)
1357 GalliumDXGIUseNothing();
1358 dxgi_thread_binding.platform = native_get_drm_platform();
1359 dxgi_thread_binding.display = (void*)fd;
1360 dxgi_thread_binding.backend = 0;
1364 #ifdef GALLIUM_DXGI_USE_FBDEV
1365 void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd)
1367 GalliumDXGIUseNothing();
1368 dxgi_thread_binding.platform = native_get_fbdev_platform();
1369 dxgi_thread_binding.display = (void*)fd;
1370 dxgi_thread_binding.backend = 0;
1374 #ifdef GALLIUM_DXGI_USE_GDI
1375 void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie)
1377 GalliumDXGIUseNothing();
1378 dxgi_thread_binding.platform = native_get_gdi_platform();
1379 dxgi_thread_binding.display = (void*)hdc;
1380 dxgi_thread_binding.backend = 0;
1384 void STDMETHODCALLTYPE
GalliumDXGIMakeDefault()
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();
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(
1401 GalliumDXGIFactory
* factory
;
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
);
1408 factory
= new GalliumDXGIFactory(native_get_x11_platform(), NULL
, NULL
);
1409 HRESULT hres
= factory
->QueryInterface(riid
, out_factory
);
1414 HRESULT STDMETHODCALLTYPE
CreateDXGIFactory(
1419 return CreateDXGIFactory1(riid
, out_factor
);