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
// TODO: somehow check whether the window is fully obscured or not
69
struct GalliumDXGIIdentityBackend : public GalliumComObject<IGalliumDXGIBackend>
71
virtual HRESULT STDMETHODCALLTYPE BeginPresent(
73
void** present_cookie,
77
BOOL* preserve_aspect_ratio
80
*window = (void*)hwnd;
83
rect->right = INT_MAX;
84
rect->bottom = INT_MAX;
87
// yes, because we like things looking good
88
*preserve_aspect_ratio = TRUE;
93
virtual void STDMETHODCALLTYPE EndPresent(
99
virtual HRESULT STDMETHODCALLTYPE TestPresent(HWND hwnd)
104
virtual HRESULT STDMETHODCALLTYPE GetPresentSize(
116
// TODO: maybe install an X11 error hook, so we can return errors properly
117
struct GalliumDXGIX11IdentityBackend : public GalliumDXGIIdentityBackend
121
GalliumDXGIX11IdentityBackend(Display* dpy)
125
virtual HRESULT STDMETHODCALLTYPE GetPresentSize(
131
XWindowAttributes xwa;
132
XGetWindowAttributes(dpy, (Window)hwnd, &xwa);
134
*height = xwa.height;
139
struct GalliumDXGIFactory : public GalliumDXGIObject<IDXGIFactory1, IUnknown>
141
HWND associated_window;
142
const struct native_platform* platform;
144
ComPtr<IGalliumDXGIBackend> backend;
145
void* resolver_cookie;
147
GalliumDXGIFactory(const struct native_platform* platform, void* display, IGalliumDXGIBackend* p_backend)
148
: GalliumDXGIObject<IDXGIFactory1, IUnknown>((IUnknown*)NULL), platform(platform), display(display)
152
else if(!strcmp(platform->name, "X11"))
153
backend.reset(new GalliumDXGIX11IdentityBackend((Display*)display));
155
backend.reset(new GalliumDXGIIdentityBackend());
158
virtual HRESULT STDMETHODCALLTYPE EnumAdapters(
160
IDXGIAdapter **out_adapter)
162
return EnumAdapters1(adapter, (IDXGIAdapter1**)out_adapter);
165
virtual HRESULT STDMETHODCALLTYPE EnumAdapters1(
167
IDXGIAdapter1 **out_adapter)
172
return GalliumDXGIAdapterCreate(this, platform, display, out_adapter);
176
if(platform == native_get_x11_platform())
178
unsigned nscreens = ScreenCount((Display*)display);
179
if(adapter < nscreens)
181
unsigned def_screen = DefaultScreen(display);
182
if(adapter <= def_screen)
184
*out_adapter = GalliumDXGIAdapterCreate(this, platform, display, adapter);
189
return DXGI_ERROR_NOT_FOUND;
192
/* TODO: this is a mysterious underdocumented magic API
193
* Can we have multiple windows associated?
194
* Can we have multiple windows associated if we use multiple factories?
195
* If so, what should GetWindowAssociation return?
196
* If not, does a new swapchain steal the association?
197
* Does this act for existing swapchains? For new swapchains?
199
virtual HRESULT STDMETHODCALLTYPE MakeWindowAssociation(
203
/* TODO: actually implement, for Wine, X11 and KMS*/
204
associated_window = window_handle;
208
virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation(
209
HWND *pwindow_handle)
211
*pwindow_handle = associated_window;
215
virtual HRESULT STDMETHODCALLTYPE CreateSwapChain(
217
DXGI_SWAP_CHAIN_DESC *desc,
218
IDXGISwapChain **out_swap_chain)
220
return GalliumDXGISwapChainCreate(this, device, *desc, out_swap_chain);
223
virtual HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter(
225
IDXGIAdapter **out_adapter)
227
/* TODO: ignore the module, and just create a Gallium software screen */
232
/* TODO: support hotplug */
233
virtual BOOL STDMETHODCALLTYPE IsCurrent( void)
239
struct GalliumDXGIAdapter
240
: public GalliumMultiComObject<
241
GalliumDXGIObject<IDXGIAdapter1, GalliumDXGIFactory>,
244
struct native_display* display;
245
const struct native_config** configs;
246
std::unordered_multimap<unsigned, unsigned> configs_by_pipe_format;
247
std::unordered_map<unsigned, unsigned> configs_by_native_visual_id;
248
const struct native_connector** connectors;
249
unsigned num_configs;
250
DXGI_ADAPTER_DESC1 desc;
251
std::vector<ComPtr<IDXGIOutput> > outputs;
253
struct native_event_handler handler;
255
GalliumDXGIAdapter(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy)
257
this->parent = factory;
259
/* FIXME handler should be static */
260
handler.invalid_surface = handle_invalid_surface;
261
handler.new_drm_screen = dxgi_loader_create_drm_screen;
262
handler.new_sw_screen = dxgi_loader_create_sw_screen;
263
platform->set_event_handler(&handler);
265
display = platform->create_display(dpy, FALSE, this);
267
display = platform->create_display(dpy, TRUE, this);
270
memset(&desc, 0, sizeof(desc));
271
std::string s = std::string("GalliumD3D on ") + display->screen->get_name(display->screen) + " by " + display->screen->get_vendor(display->screen);
273
/* hopefully no one will decide to use UTF-8 in Gallium name/vendor strings */
274
for(int i = 0; i < std::min((int)s.size(), 127); ++i)
275
desc.Description[i] = (WCHAR)s[i];
277
// TODO: add an interface to get these; for now, return mid/low values
278
desc.DedicatedVideoMemory = 256 << 20;
279
desc.DedicatedSystemMemory = 256 << 20;
280
desc.SharedSystemMemory = 1024 << 20;
282
// TODO: we should actually use an unique ID instead
283
*(void**)&desc.AdapterLuid = dpy;
285
configs = display->get_configs(display, (int*)&num_configs);
286
for(unsigned i = 0; i < num_configs; ++i)
288
if(configs[i]->window_bit)
290
configs_by_pipe_format.insert(std::make_pair(configs[i]->color_format, i));
291
configs_by_native_visual_id[configs[i]->native_visual_id] = i;
302
connectors = display->modeset->get_connectors(display, &num_outputs, &num_crtcs);
305
else if(!num_outputs)
315
static void handle_invalid_surface(struct native_display *ndpy, struct native_surface *nsurf, unsigned int seq_num)
317
GalliumDXGISwapChainRevalidate((IDXGISwapChain*)nsurf->user_data);
320
~GalliumDXGIAdapter()
322
display->destroy(display);
327
virtual HRESULT STDMETHODCALLTYPE EnumOutputs(
329
IDXGIOutput **out_output)
331
if(output >= (unsigned)num_outputs)
332
return DXGI_ERROR_NOT_FOUND;
336
std::ostringstream ss;
337
ss << "output #" << output;
338
return GalliumDXGIOutputCreate(this, ss.str(), connectors[output], out_output);
341
return GalliumDXGIOutputCreate(this, "Unique output", NULL, out_output);
344
virtual HRESULT STDMETHODCALLTYPE GetDesc(
345
DXGI_ADAPTER_DESC *desc)
347
memcpy(desc, &desc, sizeof(*desc));
351
virtual HRESULT STDMETHODCALLTYPE GetDesc1(
352
DXGI_ADAPTER_DESC1 *desc)
354
memcpy(desc, &desc, sizeof(*desc));
358
virtual HRESULT STDMETHODCALLTYPE CheckInterfaceSupport(
359
REFGUID interface_name,
360
LARGE_INTEGER *u_m_d_version)
362
// these number was taken from Windows 7 with Catalyst 10.8: its meaning is unclear
363
if(interface_name == IID_ID3D11Device || interface_name == IID_ID3D10Device1 || interface_name == IID_ID3D10Device)
365
u_m_d_version->QuadPart = 0x00080011000a0411ULL;
368
return DXGI_ERROR_UNSUPPORTED;
371
pipe_screen* STDMETHODCALLTYPE GetGalliumScreen()
373
return display->screen;
376
pipe_screen* STDMETHODCALLTYPE GetGalliumReferenceSoftwareScreen()
378
// TODO: give a softpipe screen
379
return display->screen;
382
pipe_screen* STDMETHODCALLTYPE GetGalliumFastSoftwareScreen()
384
// TODO: give an llvmpipe screen
385
return display->screen;
390
struct GalliumDXGIOutput : public GalliumDXGIObject<IDXGIOutput, GalliumDXGIAdapter>
392
DXGI_OUTPUT_DESC desc;
393
const struct native_mode** modes;
394
DXGI_MODE_DESC* dxgi_modes;
396
const struct native_connector* connector;
397
DXGI_GAMMA_CONTROL* gamma;
399
GalliumDXGIOutput(GalliumDXGIAdapter* adapter, std::string name, const struct native_connector* connector = 0)
400
: GalliumDXGIObject<IDXGIOutput, GalliumDXGIAdapter>(adapter), connector(connector)
402
memset(&desc, 0, sizeof(desc));
403
for(unsigned i = 0; i < std::min(name.size(), sizeof(desc.DeviceName) - 1); ++i)
404
desc.DeviceName[i] = name[i];
405
desc.AttachedToDesktop = TRUE;
406
/* TODO: should put an HMONITOR in desc.Monitor */
413
modes = parent->display->modeset->get_modes(parent->display, connector, (int*)&num_modes);
414
if(modes && num_modes)
416
dxgi_modes = new DXGI_MODE_DESC[num_modes];
417
for(unsigned i = 0; i < num_modes; ++i)
419
dxgi_modes[i].Width = modes[i]->width;
420
dxgi_modes[i].Height = modes[i]->height;
421
dxgi_modes[i].RefreshRate.Numerator = modes[i]->refresh_rate;
422
dxgi_modes[i].RefreshRate.Denominator = 1;
423
dxgi_modes[i].Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
424
dxgi_modes[i].ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
440
dxgi_modes = new DXGI_MODE_DESC[1];
441
dxgi_modes[0].Width = 1920;
442
dxgi_modes[0].Height = 1200;
443
dxgi_modes[0].RefreshRate.Numerator = 60;
444
dxgi_modes[0].RefreshRate.Denominator = 1;
445
dxgi_modes[0].Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
446
dxgi_modes[0].ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
452
delete [] dxgi_modes;
458
virtual HRESULT STDMETHODCALLTYPE GetDesc(
459
DXGI_OUTPUT_DESC *out_desc)
465
virtual HRESULT STDMETHODCALLTYPE GetDisplayModeList(
466
DXGI_FORMAT enum_format,
469
DXGI_MODE_DESC *desc)
471
/* TODO: should we return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE when we don't
472
* support modesetting instead of fake modes?
474
pipe_format format = dxgi_to_pipe_format[enum_format];
475
if(parent->configs_by_pipe_format.count(format))
483
unsigned copy_modes = std::min(num_modes, *pcount);
484
for(unsigned i = 0; i < copy_modes; ++i)
486
desc[i] = dxgi_modes[i];
487
desc[i].Format = enum_format;
491
if(copy_modes < num_modes)
492
return DXGI_ERROR_MORE_DATA;
503
virtual HRESULT STDMETHODCALLTYPE FindClosestMatchingMode(
504
const DXGI_MODE_DESC *pModeToMatch,
505
DXGI_MODE_DESC *closest_match,
506
IUnknown *concerned_device)
508
/* TODO: actually implement this */
509
DXGI_FORMAT dxgi_format = pModeToMatch->Format;
510
enum pipe_format format = dxgi_to_pipe_format[dxgi_format];
511
init_pipe_to_dxgi_format();
512
if(!parent->configs_by_pipe_format.count(format))
514
if(!concerned_device)
518
format = parent->configs[0]->color_format;
519
dxgi_format = pipe_to_dxgi_format[format];
523
*closest_match = dxgi_modes[0];
524
closest_match->Format = dxgi_format;
528
virtual HRESULT STDMETHODCALLTYPE WaitForVBlank( void)
533
virtual HRESULT STDMETHODCALLTYPE TakeOwnership(
540
virtual void STDMETHODCALLTYPE ReleaseOwnership( void)
544
virtual HRESULT STDMETHODCALLTYPE GetGammaControlCapabilities(
545
DXGI_GAMMA_CONTROL_CAPABILITIES *gamma_caps)
547
memset(gamma_caps, 0, sizeof(*gamma_caps));
551
virtual HRESULT STDMETHODCALLTYPE SetGammaControl(
552
const DXGI_GAMMA_CONTROL *pArray)
555
gamma = new DXGI_GAMMA_CONTROL;
560
virtual HRESULT STDMETHODCALLTYPE GetGammaControl(
561
DXGI_GAMMA_CONTROL *pArray)
567
pArray->Scale.Red = 1;
568
pArray->Scale.Green = 1;
569
pArray->Scale.Blue = 1;
570
pArray->Offset.Red = 0;
571
pArray->Offset.Green = 0;
572
pArray->Offset.Blue = 0;
573
for(unsigned i = 0; i <= 1024; ++i)
574
pArray->GammaCurve[i].Red = pArray->GammaCurve[i].Green = pArray->GammaCurve[i].Blue = (float)i / 1024.0;
579
virtual HRESULT STDMETHODCALLTYPE SetDisplaySurface(
580
IDXGISurface *scanout_surface)
585
virtual HRESULT STDMETHODCALLTYPE GetDisplaySurfaceData(
586
IDXGISurface *destination)
591
virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics(
592
DXGI_FRAME_STATISTICS *stats)
594
memset(stats, 0, sizeof(*stats));
596
QueryPerformanceCounter(&stats->SyncQPCTime);
602
/* Swap chain are rather complex, and Microsoft's documentation is rather
603
* lacking. As far as I know, this is the most thorough publicly available
604
* description of how swap chains work, based on multiple sources and
607
* There are two modes (called "swap effects") that a swap chain can operate in:
608
* discard and sequential.
610
* In discard mode, things always look as if there is a single buffer, which
611
* you can get with GetBuffers(0).
612
* The 2D texture returned by GetBuffers(0) and can only be
613
* used as a render target view and for resource copies, since no CPU access
614
* flags are set and only the D3D11_BIND_RENDER_TARGET bind flag is set.
615
* On Present, it is copied to the actual display
616
* surface and the contents become undefined.
617
* D3D may internally use multiple buffers, but you can't observe this, except
618
* by looking at the buffer contents after Present (but those are undefined).
619
* If it uses multiple buffers internally, then it will normally use buffer_count buffers
620
* (this has latency implications).
621
* Discard mode seems to internally use a single buffer in windowed mode,
622
* even if DWM is enabled, and buffer_count buffers in fullscreen mode.
624
* In sequential mode, the runtime alllocates buffer_count buffers.
625
* You can get each with GetBuffers(n).
626
* GetBuffers(0) ALWAYS points to the backbuffer to be presented and has the
627
* same usage constraints as the discard mode.
628
* GetBuffer(n) with n > 0 points to resources that are identical to buffer 0, but
629
* are classified as "read-only resources" (due to DXGI_USAGE_READ_ONLY),
630
* meaning that you can't create render target views on them, or use them as
631
* a CopyResource/CopySubresourceRegion destination.
632
* It appears the only valid operation is to use them as a source for CopyResource
633
* and CopySubresourceRegion as well as just waiting for them to become
635
* Buffer n - 1 is always displayed on screen.
636
* When you call Present(), the contents of the buffers are rotated, so that buffer 0
637
* goes to buffer n - 1, and is thus displayed, and buffer 1 goes to buffer 0, becomes
638
* the accessible back buffer.
639
* The resources themselves are NOT rotated, so that you can still render on the
640
* same ID3D11Texture2D*, and views based on it, that you got before Present().
642
* Present seems to happen by either copying the relevant buffer into the window,
643
* or alternatively making it the current one, either by programming the CRTC or
644
* by sending the resource name to the DWM compositor.
646
* Hence, you can call GetBuffer(0) once and keep using the same ID3D11Texture2D*
647
* and ID3D11RenderTargetView* (and other views if needed) you got from it.
649
* If the window gets resized, DXGI will then "emulate" all successive presentations,
650
* by using a stretched blit automatically.
651
* Thus, you should handle WM_SIZE and call ResizeBuffers to update the DXGI
652
* swapchain buffers size to the new window size.
653
* Doing so requires you to release all GetBuffers() results and anything referencing
654
* them, including views and Direct3D11 deferred context command lists (this is
657
* How does Microsoft implement the rotation behavior?
658
* It turns out that it does it by calling RotateResourceIdentitiesDXGI in the user-mode
660
* This will rotate the kernel buffer handle, or possibly rotate the GPU virtual memory
663
* The reason this is done by driver instead of by the runtime appears to be that
664
* this is necessary to support driver-provided command list support, since otherwise
665
* the command list would not always target the current backbuffer, since it would
666
* be done at the driver level, while only the runtime knows about the rotation.
668
* OK, so how do we implement this in Gallium?
670
* There are three strategies:
671
* 1. Use a single buffer, and always copy it to a window system provided buffer, or
672
* just give the buffer to the window system if it supports that
673
* 2. Rotate the buffers in the D3D1x implementation, and recreate and rebind the views.
674
* Don't support driver-provided command lists
675
* 3. Add this rotation functionality to the Gallium driver, with the idea that it would rotate
676
* remap GPU virtual memory, so that virtual address are unchanged, but the physical
677
* ones are rotated (so that pushbuffers remain valid).
678
* If the driver does not support this, either fall back to (1), or have a layer doing this,
679
* putting a deferred context layer over this intermediate layer.
681
* (2) is not acceptable since it prevents an optimal implementation.
682
* (3) is the ideal solution, but it is complicated.
684
* Hence, we implement (1) for now, and will switch to (3) later.
686
* Note that (1) doesn't really work for DXGI_SWAP_EFFECT_SEQUENTIAL with more
687
* than one buffer, so we just pretend we got asked for a single buffer in that case
688
* Fortunately, no one seems to rely on that, so we'll just not implement it at first, and
689
* later perform the rotation with blits.
690
* Once we switch to (3), we'll just use real rotation to do it..
692
* DXGI_SWAP_EFFECT_SEQUENTIAL with more than one buffer is of dubious use
693
* anyway, since you can only render or write to buffer 0, and other buffers can apparently
694
* be used only as sources for copies.
695
* I was unable to find any code using it either in DirectX SDK examples, or on the web.
697
* It seems the only reason you would use it is to not have to redraw from scratch, while
698
* also possibly avoid a copy compared to buffer_count == 1, assuming that your
699
* application is OK with having to redraw starting not from the last frame, but from
700
* one/two/more frames behind it.
702
* A better design would forbid the user specifying buffer_count explicitly, and
703
* would instead let the application give an upper bound on how old the buffer can
704
* become after presentation, with "infinite" being equivalent to discard.
705
* The runtime would then tell the application with frame number the buffer switched to
707
* In addition, in a better design, the application would be allowed to specify the
708
* number of buffers available, having all them usable for rendering, so that things
709
* like video players could efficiently decode frames in parallel.
710
* Present would in such a better design gain a way to specify the number of buffers
713
* Other miscellaneous info:
714
* DXGI_PRESENT_DO_NOT_SEQUENCE causes DXGI to hold the frame for another
715
* vblank interval without rotating the resource data.
718
* "DXGI Overview" in MSDN
719
* IDXGISwapChain documentation on MSDN
720
* "RotateResourceIdentitiesDXGI" on MSDN
721
* http://forums.xna.com/forums/p/42362/266016.aspx
724
static float quad_data[] = {
742
struct pipe_clip_state clip;
743
struct pipe_vertex_buffer vbuf;
744
struct pipe_draw_info draw;
746
dxgi_blitter(pipe_context* pipe)
749
//normalized = !!pipe->screen->get_param(pipe, PIPE_CAP_NPOT_TEXTURES);
750
// TODO: need to update buffer in unnormalized case
753
struct pipe_rasterizer_state rs_state;
754
memset(&rs_state, 0, sizeof(rs_state));
755
rs_state.cull_face = PIPE_FACE_NONE;
756
rs_state.gl_rasterization_rules = 1;
757
rs_state.flatshade = 1;
758
rasterizer = pipe->create_rasterizer_state(pipe, &rs_state);
760
struct pipe_blend_state blendd;
761
memset(&blendd, 0, sizeof(blendd));
762
blendd.rt[0].colormask = PIPE_MASK_RGBA;
763
blend = pipe->create_blend_state(pipe, &blendd);
765
struct pipe_depth_stencil_alpha_state zsad;
766
memset(&zsad, 0, sizeof(zsad));
767
zsa = pipe->create_depth_stencil_alpha_state(pipe, &zsad);
769
struct pipe_vertex_element velem[2];
770
memset(&velem[0], 0, sizeof(velem[0]) * 2);
771
velem[0].src_offset = 0;
772
velem[0].src_format = PIPE_FORMAT_R32G32_FLOAT;
773
velem[1].src_offset = 8;
774
velem[1].src_format = PIPE_FORMAT_R32G32_FLOAT;
775
elements = pipe->create_vertex_elements_state(pipe, 2, &velem[0]);
777
for(unsigned stretch = 0; stretch < 2; ++stretch)
779
struct pipe_sampler_state sampler_state;
780
memset(&sampler_state, 0, sizeof(sampler_state));
781
sampler_state.min_img_filter = stretch ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
782
sampler_state.mag_img_filter = stretch ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST;
783
sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
784
sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
785
sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
786
sampler_state.normalized_coords = normalized;
788
sampler[stretch] = pipe->create_sampler_state(pipe, &sampler_state);
791
fs = util_make_fragment_tex_shader(pipe, normalized ? TGSI_TEXTURE_2D : TGSI_TEXTURE_RECT, TGSI_INTERPOLATE_LINEAR);
793
const unsigned semantic_names[] = { TGSI_SEMANTIC_POSITION, TGSI_SEMANTIC_GENERIC };
794
const unsigned semantic_indices[] = { 0, 0 };
795
vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names, semantic_indices);
797
vbuf.buffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER,
798
PIPE_USAGE_STREAM, sizeof(quad_data));
799
vbuf.buffer_offset = 0;
800
vbuf.stride = 4 * sizeof(float);
801
pipe_buffer_write(pipe, vbuf.buffer, 0, sizeof(quad_data), quad_data);
803
memset(&clip, 0, sizeof(clip));
805
memset(&draw, 0, sizeof(draw));
806
draw.mode = PIPE_PRIM_QUADS;
808
draw.instance_count = 1;
812
void blit(struct pipe_surface* surf, struct pipe_sampler_view* view, unsigned x, unsigned y, unsigned w, unsigned h)
814
struct pipe_framebuffer_state fb;
815
memset(&fb, 0, sizeof(fb));
818
fb.width = surf->width;
819
fb.height = surf->height;
821
struct pipe_viewport_state viewport;
822
float half_width = w * 0.5f;
823
float half_height = h * 0.5f;
824
viewport.scale[0] = half_width;
825
viewport.scale[1] = half_height;
826
viewport.scale[2] = 1.0f;
827
viewport.scale[3] = 1.0f;
828
viewport.translate[0] = x + half_width;
829
viewport.translate[1] = y + half_height;
830
viewport.translate[2] = 0.0f;
831
viewport.translate[3] = 1.0f;
833
bool stretch = view->texture->width0 != w || view->texture->height0 != h;
834
if(pipe->render_condition)
835
pipe->render_condition(pipe, 0, 0);
836
pipe->set_framebuffer_state(pipe, &fb);
837
pipe->bind_fragment_sampler_states(pipe, 1, &sampler[stretch]);
838
pipe->set_viewport_state(pipe, &viewport);
839
pipe->set_clip_state(pipe, &clip);
840
pipe->bind_rasterizer_state(pipe, rasterizer);
841
pipe->bind_depth_stencil_alpha_state(pipe, zsa);
842
pipe->bind_blend_state(pipe, blend);
843
pipe->bind_vertex_elements_state(pipe, elements);
844
pipe->set_vertex_buffers(pipe, 1, &vbuf);
845
pipe->bind_fs_state(pipe, fs);
846
pipe->bind_vs_state(pipe, vs);
847
if(pipe->bind_gs_state)
848
pipe->bind_gs_state(pipe, 0);
849
if(pipe->bind_stream_output_state)
850
pipe->bind_stream_output_state(pipe, 0);
851
pipe->set_fragment_sampler_views(pipe, 1, &view);
853
pipe->draw_vbo(pipe, &draw);
858
pipe->delete_blend_state(pipe, blend);
859
pipe->delete_rasterizer_state(pipe, rasterizer);
860
pipe->delete_depth_stencil_alpha_state(pipe, zsa);
861
pipe->delete_sampler_state(pipe, sampler[0]);
862
pipe->delete_sampler_state(pipe, sampler[1]);
863
pipe->delete_vertex_elements_state(pipe, elements);
864
pipe->delete_vs_state(pipe, vs);
865
pipe->delete_fs_state(pipe, fs);
866
pipe->screen->resource_destroy(pipe->screen, vbuf.buffer);
870
struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory>
872
ComPtr<IDXGIDevice>dxgi_device;
873
ComPtr<IGalliumDevice>gallium_device;
874
ComPtr<GalliumDXGIAdapter> adapter;
875
ComPtr<IDXGIOutput> target;
877
DXGI_SWAP_CHAIN_DESC desc;
879
struct native_surface* surface;
880
const struct native_config* config;
883
struct pipe_resource* resources[NUM_NATIVE_ATTACHMENTS];
888
bool needs_validation;
889
unsigned present_count;
891
ComPtr<IDXGISurface> buffer0;
892
struct pipe_resource* gallium_buffer0;
893
struct pipe_sampler_view* gallium_buffer0_view;
895
struct pipe_context* pipe;
900
std::auto_ptr<dxgi_blitter> blitter;
901
bool formats_compatible;
903
GalliumDXGISwapChain(GalliumDXGIFactory* factory, IUnknown* p_device, const DXGI_SWAP_CHAIN_DESC& p_desc)
904
: GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory>(factory), desc(p_desc), surface(0)
908
hr = p_device->QueryInterface(IID_IGalliumDevice, (void**)&gallium_device);
912
hr = p_device->QueryInterface(IID_IDXGIDevice, (void**)&dxgi_device);
916
hr = dxgi_device->GetAdapter((IDXGIAdapter**)&adapter);
920
memset(resources, 0, sizeof(resources));
922
if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL && desc.BufferCount != 1)
924
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;
925
// change the returned desc, so that the application might perhaps notice what we did and react well
926
desc.BufferCount = 1;
929
pipe = gallium_device->GetGalliumContext();
933
pipe = adapter->display->screen->context_create(adapter->display->screen, 0);
937
blitter.reset(new dxgi_blitter(pipe));
940
hr = resolve_zero_width_height(true);
945
void init_for_window()
949
surface->destroy(surface);
954
if(!strcmp(parent->platform->name, "X11"))
956
XWindowAttributes xwa;
957
XGetWindowAttributes((Display*)parent->display, (Window)window, &xwa);
958
assert(adapter->configs_by_native_visual_id.count(xwa.visual->visualid));
959
config_num = adapter->configs_by_native_visual_id[xwa.visual->visualid];
963
enum pipe_format format = dxgi_to_pipe_format[desc.BufferDesc.Format];
964
if(!adapter->configs_by_pipe_format.count(format))
966
if(adapter->configs_by_pipe_format.empty())
968
// TODO: choose the best match
969
format = (pipe_format)adapter->configs_by_pipe_format.begin()->first;
971
// TODO: choose the best config
972
config_num = adapter->configs_by_pipe_format.find(format)->second;
975
config = adapter->configs[config_num];
976
surface = adapter->display->create_window_surface(adapter->display, (EGLNativeWindowType)window, config);
977
surface->user_data = this;
983
needs_validation = true;
984
ever_validated = false;
986
formats_compatible = util_is_format_compatible(
987
util_format_description(dxgi_to_pipe_format[desc.BufferDesc.Format]),
988
util_format_description(config->color_format));
991
~GalliumDXGISwapChain()
997
virtual HRESULT STDMETHODCALLTYPE GetDevice(
1001
return dxgi_device->QueryInterface(riid, pdevice);
1004
HRESULT create_buffer0()
1007
ComPtr<IDXGISurface> new_buffer0;
1008
DXGI_USAGE usage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT;
1009
if(desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD)
1010
usage |= DXGI_USAGE_DISCARD_ON_PRESENT;
1012
usage |= DXGI_USAGE_SHADER_INPUT;
1014
DXGI_SURFACE_DESC surface_desc;
1015
surface_desc.Format = desc.BufferDesc.Format;
1016
surface_desc.Width = desc.BufferDesc.Width;
1017
surface_desc.Height = desc.BufferDesc.Height;
1018
surface_desc.SampleDesc = desc.SampleDesc;
1019
hr = dxgi_device->CreateSurface(&surface_desc, 1, usage, 0, &new_buffer0);
1023
ComPtr<IGalliumResource> gallium_resource;
1024
hr = new_buffer0->QueryInterface(IID_IGalliumResource, (void**)&gallium_resource);
1028
struct pipe_resource* new_gallium_buffer0 = gallium_resource->GetGalliumResource();
1029
if(!new_gallium_buffer0)
1032
buffer0.reset(new_buffer0.steal());
1033
gallium_buffer0 = new_gallium_buffer0;
1034
struct pipe_sampler_view templat;
1035
memset(&templat, 0, sizeof(templat));
1036
templat.texture = gallium_buffer0;
1037
templat.swizzle_r = 0;
1038
templat.swizzle_g = 1;
1039
templat.swizzle_b = 2;
1040
templat.swizzle_a = 3;
1041
templat.format = gallium_buffer0->format;
1042
gallium_buffer0_view = pipe->create_sampler_view(pipe, gallium_buffer0, &templat);
1048
unsigned new_seq_num;
1049
needs_validation = false;
1051
if(!surface->validate(surface, (1 << NATIVE_ATTACHMENT_BACK_LEFT) | (1 << NATIVE_ATTACHMENT_FRONT_LEFT), &new_seq_num, resources, &width, &height))
1054
if(!ever_validated || seq_num != new_seq_num)
1056
seq_num = new_seq_num;
1057
ever_validated = true;
1062
HRESULT resolve_zero_width_height(bool force = false)
1064
if(!force && desc.BufferDesc.Width && desc.BufferDesc.Height)
1067
unsigned width, height;
1068
HRESULT hr = parent->backend->GetPresentSize(desc.OutputWindow, &width, &height);
1072
// On Windows, 8 is used, and a debug message saying so gets printed
1078
if(!desc.BufferDesc.Width)
1079
desc.BufferDesc.Width = width;
1080
if(!desc.BufferDesc.Height)
1081
desc.BufferDesc.Height = height;
1085
virtual HRESULT STDMETHODCALLTYPE Present(
1090
if(flags & DXGI_PRESENT_TEST)
1091
return parent->backend->TestPresent(desc.OutputWindow);
1095
HRESULT hr = create_buffer0();
1100
void* cur_window = 0;
1103
BOOL preserve_aspect_ratio;
1104
unsigned dst_w, dst_h;
1106
struct pipe_resource* dst;
1107
struct pipe_resource* src;
1108
struct pipe_surface* dst_surface;
1109
enum native_attachment att;
1111
void* present_cookie;
1112
hr = parent->backend->BeginPresent(desc.OutputWindow, &present_cookie, &cur_window, &rect, &rgndata, &preserve_aspect_ratio);
1116
if(!cur_window || rect.left >= rect.right || rect.top >= rect.bottom)
1119
if(cur_window != window)
1121
window = cur_window;
1125
if(needs_validation)
1128
return DXGI_ERROR_DEVICE_REMOVED;
1131
db = !!(config->buffer_mask & (1 << NATIVE_ATTACHMENT_BACK_LEFT));
1132
dst = resources[db ? NATIVE_ATTACHMENT_BACK_LEFT : NATIVE_ATTACHMENT_FRONT_LEFT];
1133
src = gallium_buffer0;
1139
/* TODO: sharing the context for blitting won't work correctly if queries are active
1140
* Hopefully no one is crazy enough to keep queries active while presenting, expecting
1142
* We could alternatively force using another context, but that might cause inefficiency issues
1145
if((unsigned)rect.right > dst->width0)
1146
rect.right = dst->width0;
1147
if((unsigned)rect.bottom > dst->height0)
1148
rect.bottom = dst->height0;
1149
if(rect.left > rect.right)
1150
rect.left = rect.right;
1151
if(rect.top > rect.bottom)
1152
rect.top = rect.bottom;
1154
if(rect.left >= rect.right && rect.top >= rect.bottom)
1157
dst_w = rect.right - rect.left;
1158
dst_h = rect.bottom - rect.top;
1160
// TODO: add support for rgndata
1161
// if(preserve_aspect_ratio || !rgndata)
1164
unsigned blit_x, blit_y, blit_w, blit_h;
1165
float black[4] = {0, 0, 0, 0};
1167
if(!formats_compatible || src->width0 != dst_w || src->height0 != dst_h) {
1168
struct pipe_surface templat;
1169
templat.usage = PIPE_BIND_RENDER_TARGET;
1170
templat.format = dst->format;
1171
templat.u.tex.level = 0;
1172
templat.u.tex.first_layer = 0;
1173
templat.u.tex.last_layer = 0;
1174
dst_surface = pipe->create_surface(pipe, dst, &templat);
1177
if(preserve_aspect_ratio)
1179
int delta = src->width0 * dst_h - dst_w * src->height0;
1183
blit_h = dst_w * src->height0 / src->width0;
1187
blit_w = dst_h * src->width0 / src->height0;
1196
blit_x = (dst_w - blit_w) >> 1;
1197
blit_y = (dst_h - blit_h) >> 1;
1208
pipe->clear_render_target(pipe, dst_surface, black, rect.left, rect.top, blit_x, dst_h);
1210
pipe->clear_render_target(pipe, dst_surface, black, rect.left, rect.top, dst_w, blit_y);
1212
if(formats_compatible && blit_w == src->width0 && blit_h == src->height0)
1215
box.x = box.y = box.z;
1217
box.height = blit_h;
1219
pipe->resource_copy_region(pipe, dst, 0, rect.left, rect.top, 0, src, 0, &box);
1223
blitter->blit(dst_surface, gallium_buffer0_view, rect.left + blit_x, rect.top + blit_y, blit_w, blit_h);
1225
gallium_device->RestoreGalliumState();
1229
pipe->clear_render_target(pipe, dst_surface, black, rect.left + blit_x + blit_w, rect.top, dst_w - blit_x - blit_w, dst_h);
1231
pipe->clear_render_target(pipe, dst_surface, black, rect.left, rect.top + blit_y + blit_h, dst_w, dst_h - blit_y - blit_h);
1235
pipe->surface_destroy(pipe, dst_surface);
1237
pipe->flush(pipe, 0);
1239
att = (db) ? NATIVE_ATTACHMENT_BACK_LEFT : NATIVE_ATTACHMENT_FRONT_LEFT;
1240
if(!surface->present(surface, att, FALSE, 0))
1241
return DXGI_ERROR_DEVICE_REMOVED;
1244
parent->backend->EndPresent(desc.OutputWindow, present_cookie);
1250
virtual HRESULT STDMETHODCALLTYPE GetBuffer(
1257
if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL)
1258
std::cerr << "DXGI unimplemented: GetBuffer(n) with n > 0 not supported, returning buffer 0 instead!" << std::endl;
1260
std::cerr << "DXGI error: in GetBuffer(n), n must be 0 for DXGI_SWAP_EFFECT_DISCARD\n" << std::endl;
1265
HRESULT hr = create_buffer0();
1269
return buffer0->QueryInterface(riid, ppSurface);
1272
/* TODO: implement somehow */
1273
virtual HRESULT STDMETHODCALLTYPE SetFullscreenState(
1275
IDXGIOutput *target)
1277
fullscreen = fullscreen;
1282
virtual HRESULT STDMETHODCALLTYPE GetFullscreenState(
1283
BOOL *out_fullscreen,
1284
IDXGIOutput **out_target)
1287
*out_fullscreen = fullscreen;
1289
*out_target = target.ref();
1293
virtual HRESULT STDMETHODCALLTYPE GetDesc(
1294
DXGI_SWAP_CHAIN_DESC *out_desc)
1300
virtual HRESULT STDMETHODCALLTYPE ResizeBuffers(
1304
DXGI_FORMAT new_format,
1305
UINT swap_chain_flags)
1309
buffer0.p->AddRef();
1310
ULONG v = buffer0.p->Release();
1311
// we must fail if there are any references to buffer0 other than ours
1314
pipe_sampler_view_reference(&gallium_buffer0_view, 0);
1315
buffer0 = (IUnknown*)NULL;
1316
gallium_buffer0 = 0;
1319
if(desc.SwapEffect != DXGI_SWAP_EFFECT_SEQUENTIAL)
1320
desc.BufferCount = buffer_count;
1321
desc.BufferDesc.Format = new_format;
1322
desc.BufferDesc.Width = width;
1323
desc.BufferDesc.Height = height;
1324
desc.Flags = swap_chain_flags;
1325
return resolve_zero_width_height();
1328
virtual HRESULT STDMETHODCALLTYPE ResizeTarget(
1329
const DXGI_MODE_DESC *out_new_target_parameters)
1331
/* TODO: implement */
1335
virtual HRESULT STDMETHODCALLTYPE GetContainingOutput(
1336
IDXGIOutput **out_output)
1338
*out_output = adapter->outputs[0].ref();
1342
virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics(
1343
DXGI_FRAME_STATISTICS *out_stats)
1345
memset(out_stats, 0, sizeof(*out_stats));
1347
QueryPerformanceCounter(&out_stats->SyncQPCTime);
1349
out_stats->PresentCount = present_count;
1350
out_stats->PresentRefreshCount = present_count;
1351
out_stats->SyncRefreshCount = present_count;
1355
virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount(
1356
UINT *last_present_count)
1358
*last_present_count = present_count;
1363
static void GalliumDXGISwapChainRevalidate(IDXGISwapChain* swap_chain)
1365
((GalliumDXGISwapChain*)swap_chain)->needs_validation = true;
1368
static HRESULT GalliumDXGIAdapterCreate(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy, IDXGIAdapter1** out_adapter)
1372
*out_adapter = new GalliumDXGIAdapter(factory, platform, dpy);
1381
static HRESULT GalliumDXGIOutputCreate(GalliumDXGIAdapter* adapter, const std::string& name, const struct native_connector* connector, IDXGIOutput** out_output)
1385
*out_output = new GalliumDXGIOutput(adapter, name, connector);
1394
static HRESULT GalliumDXGISwapChainCreate(GalliumDXGIFactory* factory, IUnknown* device, const DXGI_SWAP_CHAIN_DESC& desc, IDXGISwapChain** out_swap_chain)
1398
*out_swap_chain = new GalliumDXGISwapChain(factory, device, desc);
1409
const struct native_platform* platform;
1411
IGalliumDXGIBackend* backend;
1414
static dxgi_binding dxgi_default_binding;
1415
static __thread dxgi_binding dxgi_thread_binding;
1417
void STDMETHODCALLTYPE GalliumDXGIUseNothing()
1419
dxgi_thread_binding.platform = 0;
1420
dxgi_thread_binding.display = 0;
1421
if(dxgi_thread_binding.backend)
1422
dxgi_thread_binding.backend->Release();
1423
dxgi_thread_binding.backend = 0;
1426
#ifdef GALLIUM_DXGI_USE_X11
1427
void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, IGalliumDXGIBackend* backend)
1429
GalliumDXGIUseNothing();
1430
dxgi_thread_binding.platform = native_get_x11_platform();
1431
dxgi_thread_binding.display = dpy;
1435
dxgi_thread_binding.backend = backend;
1442
#ifdef GALLIUM_DXGI_USE_DRM
1443
void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd)
1445
GalliumDXGIUseNothing();
1446
dxgi_thread_binding.platform = native_get_drm_platform();
1447
dxgi_thread_binding.display = (void*)fd;
1448
dxgi_thread_binding.backend = 0;
1452
#ifdef GALLIUM_DXGI_USE_FBDEV
1453
void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd)
1455
GalliumDXGIUseNothing();
1456
dxgi_thread_binding.platform = native_get_fbdev_platform();
1457
dxgi_thread_binding.display = (void*)fd;
1458
dxgi_thread_binding.backend = 0;
1462
#ifdef GALLIUM_DXGI_USE_GDI
1463
void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie)
1465
GalliumDXGIUseNothing();
1466
dxgi_thread_binding.platform = native_get_gdi_platform();
1467
dxgi_thread_binding.display = (void*)hdc;
1468
dxgi_thread_binding.backend = 0;
1472
void STDMETHODCALLTYPE GalliumDXGIMakeDefault()
1474
if(dxgi_default_binding.backend)
1475
dxgi_default_binding.backend->Release();
1476
dxgi_default_binding = dxgi_thread_binding;
1477
if(dxgi_default_binding.backend)
1478
dxgi_default_binding.backend->AddRef();
1481
/* TODO: why did Microsoft add this? should we do something different for DXGI 1.0 and 1.1?
1482
* Or perhaps what they actually mean is "only create a single factory in your application"?
1483
* TODO: should we use a singleton here, so we never have multiple DXGI objects for the same thing? */
1484
HRESULT STDMETHODCALLTYPE CreateDXGIFactory1(
1489
GalliumDXGIFactory* factory;
1491
if(dxgi_thread_binding.platform)
1492
factory = new GalliumDXGIFactory(dxgi_thread_binding.platform, dxgi_thread_binding.display, dxgi_thread_binding.backend);
1493
else if(dxgi_default_binding.platform)
1494
factory = new GalliumDXGIFactory(dxgi_default_binding.platform, dxgi_default_binding.display, dxgi_default_binding.backend);
1496
factory = new GalliumDXGIFactory(native_get_x11_platform(), NULL, NULL);
1497
HRESULT hres = factory->QueryInterface(riid, out_factory);
1502
HRESULT STDMETHODCALLTYPE CreateDXGIFactory(
1507
return CreateDXGIFactory1(riid, out_factor);