dxgi_native.cpp revision b4b2091655676ec3b898d3ae7298192aa7f9147f
1/************************************************************************** 2 * 3 * Copyright 2010 Luca Barbieri 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 **************************************************************************/ 26 27#include "dxgi_private.h" 28extern "C" { 29#include "native.h" 30#include <util/u_format.h> 31#include <util/u_inlines.h> 32#include <util/u_simple_shaders.h> 33#include <pipe/p_shader_tokens.h> 34} 35#include <iostream> 36#include <memory> 37 38struct GalliumDXGIOutput; 39struct GalliumDXGIAdapter; 40struct GalliumDXGISwapChain; 41struct GalliumDXGIFactory; 42 43static HRESULT GalliumDXGISwapChainCreate(GalliumDXGIFactory* factory, IUnknown* device, const DXGI_SWAP_CHAIN_DESC& desc, IDXGISwapChain** ppSwapChain); 44static HRESULT GalliumDXGIAdapterCreate(GalliumDXGIFactory* adapter, const struct native_platform* platform, void* dpy, IDXGIAdapter1** ppAdapter); 45static HRESULT GalliumDXGIOutputCreate(GalliumDXGIAdapter* adapter, const std::string& name, const struct native_connector* connector, IDXGIOutput** ppOutput); 46static void GalliumDXGISwapChainRevalidate(IDXGISwapChain* swap_chain); 47 48template<typename Base = IDXGIObject, typename Parent = IDXGIObject> 49struct GalliumDXGIObject : public GalliumPrivateDataComObject<Base> 50{ 51 ComPtr<Parent> parent; 52 53 GalliumDXGIObject(Parent* p_parent = 0) 54 { 55 this->parent = p_parent; 56 } 57 58 virtual HRESULT STDMETHODCALLTYPE GetParent( 59 __in REFIID riid, 60 __out void **ppParent) 61 { 62 return parent->QueryInterface(riid, ppParent); 63 } 64}; 65 66static void* STDMETHODCALLTYPE identity_resolver(void* cookie, HWND hwnd) 67{ 68 return (void*)hwnd; 69} 70 71struct GalliumDXGIFactory : public GalliumDXGIObject<IDXGIFactory1, IUnknown> 72{ 73 HWND associated_window; 74 const struct native_platform* platform; 75 void* display; 76 PFNHWNDRESOLVER resolver; 77 void* resolver_cookie; 78 79 GalliumDXGIFactory(const struct native_platform* platform, void* display, PFNHWNDRESOLVER resolver, void* resolver_cookie) 80 : GalliumDXGIObject<IDXGIFactory1, IUnknown>((IUnknown*)NULL), platform(platform), display(display), resolver(resolver ? resolver : identity_resolver), resolver_cookie(resolver_cookie) 81 {} 82 83 virtual HRESULT STDMETHODCALLTYPE EnumAdapters( 84 UINT Adapter, 85 __out IDXGIAdapter **ppAdapter) 86 { 87 return EnumAdapters1(Adapter, (IDXGIAdapter1**)ppAdapter); 88 } 89 90 virtual HRESULT STDMETHODCALLTYPE EnumAdapters1( 91 UINT Adapter, 92 __out IDXGIAdapter1 **ppAdapter) 93 { 94 *ppAdapter = 0; 95 if(Adapter == 0) 96 { 97 return GalliumDXGIAdapterCreate(this, platform, display, ppAdapter); 98 } 99#if 0 100 // TODO: enable this 101 if(platform == native_get_x11_platform()) 102 { 103 unsigned nscreens = ScreenCount((Display*)display); 104 if(Adapter < nscreens) 105 { 106 unsigned def_screen = DefaultScreen(display); 107 if(Adapter <= def_screen) 108 --Adapter; 109 *ppAdapter = GalliumDXGIAdapterCreate(this, platform, display, Adapter); 110 return S_OK; 111 } 112 } 113#endif 114 return DXGI_ERROR_NOT_FOUND; 115 } 116 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? 123 */ 124 virtual HRESULT STDMETHODCALLTYPE MakeWindowAssociation( 125 HWND WindowHandle, 126 UINT Flags) 127 { 128 /* TODO: actually implement, for Wine, X11 and KMS*/ 129 associated_window = WindowHandle; 130 return S_OK; 131 } 132 133 virtual HRESULT STDMETHODCALLTYPE GetWindowAssociation( 134 __out HWND *pWindowHandle) 135 { 136 *pWindowHandle = associated_window; 137 return S_OK; 138 } 139 140 virtual HRESULT STDMETHODCALLTYPE CreateSwapChain( 141 __in IUnknown *pDevice, 142 __in DXGI_SWAP_CHAIN_DESC *pDesc, 143 __out IDXGISwapChain **ppSwapChain) 144 { 145 return GalliumDXGISwapChainCreate(this, pDevice, *pDesc, ppSwapChain); 146 } 147 148 virtual HRESULT STDMETHODCALLTYPE CreateSoftwareAdapter( 149 HMODULE Module, 150 __out IDXGIAdapter **ppAdapter) 151 { 152 /* TODO: ignore the module, and just create a Gallium software screen */ 153 *ppAdapter = 0; 154 return E_NOTIMPL; 155 } 156 157 /* TODO: support hotplug */ 158 virtual BOOL STDMETHODCALLTYPE IsCurrent( void) 159 { 160 return TRUE; 161 } 162}; 163 164struct GalliumDXGIAdapter 165 : public GalliumMultiComObject< 166 GalliumDXGIObject<IDXGIAdapter1, GalliumDXGIFactory>, 167 IGalliumAdapter> 168{ 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; 177 int num_outputs; 178 struct native_event_handler handler; 179 180 GalliumDXGIAdapter(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy) 181 { 182 this->parent = factory; 183 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); 188 if(!display) 189 throw E_FAIL; 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); 192 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]; 196 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; 201 202 // TODO: we should actually use an unique ID instead 203 *(void**)&desc.AdapterLuid = dpy; 204 205 configs = display->get_configs(display, (int*)&num_configs); 206 for(unsigned i = 0; i < num_configs; ++i) 207 { 208 if(configs[i]->window_bit) 209 { 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; 212 } 213 } 214 215 connectors = 0; 216 num_outputs = 0; 217 218 if(display->modeset) 219 { 220 int num_crtcs; 221 222 connectors = display->modeset->get_connectors(display, &num_outputs, &num_crtcs); 223 if(!connectors) 224 num_outputs = 0; 225 else if(!num_outputs) 226 { 227 free(connectors); 228 connectors = 0; 229 } 230 } 231 if(!num_outputs) 232 num_outputs = 1; 233 } 234 235 static void handle_invalid_surface(struct native_display *ndpy, struct native_surface *nsurf, unsigned int seq_num) 236 { 237 GalliumDXGISwapChainRevalidate((IDXGISwapChain*)nsurf->user_data); 238 } 239 240 ~GalliumDXGIAdapter() 241 { 242 free(configs); 243 free(connectors); 244 } 245 246 virtual HRESULT STDMETHODCALLTYPE EnumOutputs( 247 UINT Output, 248 __out IDXGIOutput **ppOutput) 249 { 250 if(Output >= (unsigned)num_outputs) 251 return DXGI_ERROR_NOT_FOUND; 252 253 if(connectors) 254 { 255 std::ostringstream ss; 256 ss << "Output #" << Output; 257 return GalliumDXGIOutputCreate(this, ss.str(), connectors[Output], ppOutput); 258 } 259 else 260 return GalliumDXGIOutputCreate(this, "Unique output", NULL, ppOutput); 261 } 262 263 virtual HRESULT STDMETHODCALLTYPE GetDesc( 264 __out DXGI_ADAPTER_DESC *pDesc) 265 { 266 memcpy(pDesc, &desc, sizeof(*pDesc)); 267 return S_OK; 268 } 269 270 virtual HRESULT STDMETHODCALLTYPE GetDesc1( 271 __out DXGI_ADAPTER_DESC1 *pDesc) 272 { 273 memcpy(pDesc, &desc, sizeof(*pDesc)); 274 return S_OK; 275 } 276 277 virtual HRESULT STDMETHODCALLTYPE CheckInterfaceSupport( 278 __in REFGUID InterfaceName, 279 __out LARGE_INTEGER *pUMDVersion) 280 { 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) 283 { 284 pUMDVersion->QuadPart = 0x00080011000a0411ULL; 285 return S_OK; 286 } 287 return DXGI_ERROR_UNSUPPORTED; 288 } 289 290 pipe_screen* STDMETHODCALLTYPE GetGalliumScreen() 291 { 292 return display->screen; 293 } 294 295 pipe_screen* STDMETHODCALLTYPE GetGalliumReferenceSoftwareScreen() 296 { 297 // TODO: give a softpipe screen 298 return display->screen; 299 } 300 301 pipe_screen* STDMETHODCALLTYPE GetGalliumFastSoftwareScreen() 302 { 303 // TODO: give an llvmpipe screen 304 return display->screen; 305 } 306}; 307 308 309struct GalliumDXGIOutput : public GalliumDXGIObject<IDXGIOutput, GalliumDXGIAdapter> 310{ 311 DXGI_OUTPUT_DESC desc; 312 const struct native_mode** modes; 313 DXGI_MODE_DESC* dxgi_modes; 314 unsigned num_modes; 315 const struct native_connector* connector; 316 DXGI_GAMMA_CONTROL* gamma; 317 318 GalliumDXGIOutput(GalliumDXGIAdapter* adapter, std::string name, const struct native_connector* connector = 0) 319 : GalliumDXGIObject<IDXGIOutput, GalliumDXGIAdapter>(adapter), connector(connector) 320 { 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 */ 326 327 gamma = 0; 328 num_modes = 0; 329 modes = 0; 330 if(connector) 331 { 332 modes = parent->display->modeset->get_modes(parent->display, connector, (int*)&num_modes); 333 if(modes && num_modes) 334 { 335 dxgi_modes = new DXGI_MODE_DESC[num_modes]; 336 for(unsigned i = 0; i < num_modes; ++i) 337 { 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; 344 } 345 } 346 else 347 { 348 if(modes) 349 { 350 free(modes); 351 modes = 0; 352 } 353 goto use_fake_mode; 354 } 355 } 356 else 357 { 358use_fake_mode: 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; 366 } 367 } 368 369 ~GalliumDXGIOutput() 370 { 371 delete [] dxgi_modes; 372 free(modes); 373 if(gamma) 374 delete gamma; 375 } 376 377 virtual HRESULT STDMETHODCALLTYPE GetDesc( 378 __out DXGI_OUTPUT_DESC *pDesc) 379 { 380 *pDesc = desc; 381 return S_OK; 382 } 383 384 virtual HRESULT STDMETHODCALLTYPE GetDisplayModeList( 385 DXGI_FORMAT EnumFormat, 386 UINT Flags, 387 __inout UINT *pNumModes, 388 __out_ecount_part_opt(*pNumModes,*pNumModes) DXGI_MODE_DESC *pDesc) 389 { 390 /* TODO: should we return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE when we don't 391 * support modesetting instead of fake modes? 392 */ 393 pipe_format format = dxgi_to_pipe_format[EnumFormat]; 394 if(parent->configs_by_pipe_format.count(format)) 395 { 396 if(!pDesc) 397 { 398 *pNumModes = num_modes; 399 return S_OK; 400 } 401 402 unsigned copy_modes = std::min(num_modes, *pNumModes); 403 for(unsigned i = 0; i < copy_modes; ++i) 404 { 405 pDesc[i] = dxgi_modes[i]; 406 pDesc[i].Format = EnumFormat; 407 } 408 *pNumModes = num_modes; 409 410 if(copy_modes < num_modes) 411 return DXGI_ERROR_MORE_DATA; 412 else 413 return S_OK; 414 } 415 else 416 { 417 *pNumModes = 0; 418 return S_OK; 419 } 420 } 421 422 virtual HRESULT STDMETHODCALLTYPE FindClosestMatchingMode( 423 __in const DXGI_MODE_DESC *pModeToMatch, 424 __out DXGI_MODE_DESC *pClosestMatch, 425 __in_opt IUnknown *pConcernedDevice) 426 { 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)) 432 { 433 if(!pConcernedDevice) 434 return E_FAIL; 435 else 436 { 437 format = parent->configs[0]->color_format; 438 dxgi_format = pipe_to_dxgi_format[format]; 439 } 440 } 441 442 *pClosestMatch = dxgi_modes[0]; 443 pClosestMatch->Format = dxgi_format; 444 return S_OK; 445 } 446 447 virtual HRESULT STDMETHODCALLTYPE WaitForVBlank( void) 448 { 449 return S_OK; 450 } 451 452 virtual HRESULT STDMETHODCALLTYPE TakeOwnership( 453 __in IUnknown *pDevice, 454 BOOL Exclusive) 455 { 456 return S_OK; 457 } 458 459 virtual void STDMETHODCALLTYPE ReleaseOwnership( void) 460 { 461 } 462 463 virtual HRESULT STDMETHODCALLTYPE GetGammaControlCapabilities( 464 __out DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps) 465 { 466 memset(pGammaCaps, 0, sizeof(*pGammaCaps)); 467 return S_OK; 468 } 469 470 virtual HRESULT STDMETHODCALLTYPE SetGammaControl( 471 __in const DXGI_GAMMA_CONTROL *pArray) 472 { 473 if(!gamma) 474 gamma = new DXGI_GAMMA_CONTROL; 475 *gamma = *pArray; 476 return S_OK; 477 } 478 479 virtual HRESULT STDMETHODCALLTYPE GetGammaControl( 480 __out DXGI_GAMMA_CONTROL *pArray) 481 { 482 if(gamma) 483 *pArray = *gamma; 484 else 485 { 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; 494 } 495 return S_OK; 496 } 497 498 virtual HRESULT STDMETHODCALLTYPE SetDisplaySurface( 499 __in IDXGISurface *pScanoutSurface) 500 { 501 return E_NOTIMPL; 502 } 503 504 virtual HRESULT STDMETHODCALLTYPE GetDisplaySurfaceData( 505 __in IDXGISurface *pDestination) 506 { 507 return E_NOTIMPL; 508 } 509 510 virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics( 511 __out DXGI_FRAME_STATISTICS *pStats) 512 { 513 memset(pStats, 0, sizeof(*pStats)); 514#ifdef _WIN32 515 QueryPerformanceCounter(&pStats->SyncQPCTime); 516#endif 517 return E_NOTIMPL; 518 } 519}; 520 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 524 * experimentation. 525 * 526 * There are two modes (called "swap effects") that a swap chain can operate in: 527 * discard and sequential. 528 * 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. 542 * 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 553 * buffer 0 again. 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(). 560 * 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. 564 * 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. 567 * 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 574 * documented). 575 * 576 * How does Microsoft implement the rotation behavior? 577 * It turns out that it does it by calling RotateResourceIdentitiesDXGI in the user-mode 578 * DDI driver. 579 * This will rotate the kernel buffer handle, or possibly rotate the GPU virtual memory 580 * mappings. 581 * 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. 586 * 587 * OK, so how do we implement this in Gallium? 588 * 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. 599 * 600 * (2) is not acceptable since it prevents an optimal implementation. 601 * (3) is the ideal solution, but it is complicated. 602 * 603 * Hence, we implement (1) for now, and will switch to (3) later. 604 * 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.. 610 * 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. 615 * 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. 620 * 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 625 * after present. 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 630 * to present. 631 * 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. 635 * 636 * References: 637 * "DXGI Overview" in MSDN 638 * IDXGISwapChain documentation on MSDN 639 * "RotateResourceIdentitiesDXGI" on MSDN 640 * http://forums.xna.com/forums/p/42362/266016.aspx 641 */ 642 643static float quad_data[] = { 644 -1, -1, 0, 0, 645 -1, 1, 0, 1, 646 1, 1, 1, 1, 647 1, -1, 1, 0, 648}; 649 650struct dxgi_blitter 651{ 652 pipe_context* pipe; 653 bool normalized; 654 void* fs; 655 void* vs; 656 void* sampler[2]; 657 void* elements; 658 void* blend; 659 void* rasterizer; 660 void* zsa; 661 struct pipe_clip_state clip; 662 struct pipe_vertex_buffer vbuf; 663 struct pipe_draw_info draw; 664 665 dxgi_blitter(pipe_context* pipe) 666 : pipe(pipe) 667 { 668 //normalized = !!pipe->screen->get_param(pipe, PIPE_CAP_NPOT_TEXTURES); 669 // TODO: need to update buffer in unnormalized case 670 normalized = true; 671 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); 678 679 struct pipe_blend_state blendd; 680 blendd.rt[0].colormask = PIPE_MASK_RGBA; 681 blend = pipe->create_blend_state(pipe, &blendd); 682 683 struct pipe_depth_stencil_alpha_state zsad; 684 memset(&zsad, 0, sizeof(zsad)); 685 zsa = pipe->create_depth_stencil_alpha_state(pipe, &zsad); 686 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]); 694 695 for(unsigned stretch = 0; stretch < 2; ++stretch) 696 { 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; 705 706 sampler[stretch] = pipe->create_sampler_state(pipe, &sampler_state); 707 } 708 709 fs = util_make_fragment_tex_shader(pipe, normalized ? TGSI_TEXTURE_2D : TGSI_TEXTURE_RECT, TGSI_INTERPOLATE_LINEAR); 710 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); 714 715 vbuf.buffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER, sizeof(quad_data)); 716 vbuf.buffer_offset = 0; 717 vbuf.max_index = ~0; 718 vbuf.stride = 4 * sizeof(float); 719 pipe_buffer_write(pipe, vbuf.buffer, 0, sizeof(quad_data), quad_data); 720 721 memset(&clip, 0, sizeof(clip)); 722 723 memset(&draw, 0, sizeof(draw)); 724 draw.mode = PIPE_PRIM_QUADS; 725 draw.count = 4; 726 draw.instance_count = 1; 727 draw.max_index = ~0; 728 } 729 730 void blit(struct pipe_surface* surf, struct pipe_sampler_view* view, unsigned x, unsigned y, unsigned w, unsigned h) 731 { 732 struct pipe_framebuffer_state fb; 733 memset(&fb, 0, sizeof(fb)); 734 fb.nr_cbufs = 1; 735 fb.cbufs[0] = surf; 736 fb.width = surf->width; 737 fb.height = surf->height; 738 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; 750 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); 770 771 pipe->draw_vbo(pipe, &draw); 772 } 773 774 ~dxgi_blitter() 775 { 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); 785 } 786}; 787 788struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory> 789{ 790 ComPtr<IDXGIDevice>dxgi_device; 791 ComPtr<IGalliumDevice>gallium_device; 792 ComPtr<GalliumDXGIAdapter> adapter; 793 ComPtr<IDXGIOutput> target; 794 795 struct native_surface* surface; 796 const struct native_config* config; 797 798 struct pipe_resource* resources[NUM_NATIVE_ATTACHMENTS]; 799 int width; 800 int height; 801 unsigned seq_num; 802 bool ever_validated; 803 bool needs_validation; 804 unsigned present_count; 805 806 ComPtr<IDXGISurface> buffer0; 807 struct pipe_resource* gallium_buffer0; 808 struct pipe_sampler_view* gallium_buffer0_view; 809 810 DXGI_SWAP_CHAIN_DESC desc; 811 812 struct pipe_context* pipe; 813 bool owns_pipe; 814 815 BOOL fullscreen; 816 817 std::auto_ptr<dxgi_blitter> blitter; 818 bool formats_compatible; 819 820 GalliumDXGISwapChain(GalliumDXGIFactory* factory, IUnknown* p_device, const DXGI_SWAP_CHAIN_DESC& p_desc) 821 : GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory>(factory), desc(p_desc) 822 { 823 HRESULT hr; 824 825 hr = p_device->QueryInterface(IID_IGalliumDevice, (void**)&gallium_device); 826 if(!SUCCEEDED(hr)) 827 throw hr; 828 829 hr = p_device->QueryInterface(IID_IDXGIDevice, (void**)&dxgi_device); 830 if(!SUCCEEDED(hr)) 831 throw hr; 832 833 hr = dxgi_device->GetAdapter((IDXGIAdapter**)&adapter); 834 if(!SUCCEEDED(hr)) 835 throw hr; 836 837 void* win = factory->resolver(factory->resolver_cookie, desc.OutputWindow); 838 839 unsigned config_num; 840 if(!strcmp(factory->platform->name, "X11")) 841 { 842 XWindowAttributes xwa; 843 XGetWindowAttributes((Display*)factory->display, (Window)win, &xwa); 844 config_num = adapter->configs_by_native_visual_id[xwa.visual->visualid]; 845 } 846 else 847 { 848 enum pipe_format format = dxgi_to_pipe_format[desc.BufferDesc.Format]; 849 if(!adapter->configs_by_pipe_format.count(format)) 850 { 851 if(adapter->configs_by_pipe_format.empty()) 852 throw E_FAIL; 853 // TODO: choose the best match 854 format = (pipe_format)adapter->configs_by_pipe_format.begin()->first; 855 } 856 // TODO: choose the best config 857 config_num = adapter->configs_by_pipe_format.find(format)->second; 858 } 859 860 config = adapter->configs[config_num]; 861 surface = adapter->display->create_window_surface(adapter->display, (EGLNativeWindowType)win, config); 862 surface->user_data = this; 863 864 width = 0; 865 height = 0; 866 seq_num = 0; 867 present_count = 0; 868 needs_validation = true; 869 ever_validated = false; 870 871 if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL && desc.BufferCount != 1) 872 { 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; 876 } 877 878 pipe = gallium_device->GetGalliumContext(); 879 owns_pipe = false; 880 if(!pipe) 881 { 882 pipe = adapter->display->screen->context_create(adapter->display->screen, 0); 883 owns_pipe = true; 884 } 885 886 blitter.reset(new dxgi_blitter(pipe)); 887 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)); 891 } 892 893 ~GalliumDXGISwapChain() 894 { 895 if(owns_pipe) 896 pipe->destroy(pipe); 897 } 898 899 virtual HRESULT STDMETHODCALLTYPE GetDevice( 900 __in REFIID riid, 901 __out void **ppDevice) 902 { 903 return dxgi_device->QueryInterface(riid, ppDevice); 904 } 905 906 HRESULT create_buffer0() 907 { 908 HRESULT hr; 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; 913 // for our blitter 914 usage |= DXGI_USAGE_SHADER_INPUT; 915 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); 922 if(!SUCCEEDED(hr)) 923 return hr; 924 925 ComPtr<IGalliumResource> gallium_resource; 926 hr = new_buffer0->QueryInterface(IID_IGalliumResource, (void**)&gallium_resource); 927 if(!SUCCEEDED(hr)) 928 return hr; 929 930 struct pipe_resource* new_gallium_buffer0 = gallium_resource->GetGalliumResource(); 931 if(!new_gallium_buffer0) 932 return E_FAIL; 933 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); 945 return S_OK; 946 } 947 948 bool validate() 949 { 950 unsigned new_seq_num; 951 needs_validation = false; 952 953 if(!surface->validate(surface, 1 << NATIVE_ATTACHMENT_BACK_LEFT, &new_seq_num, resources, &width, &height)) 954 return false; 955 956 if(!ever_validated || seq_num != new_seq_num) 957 { 958 seq_num = new_seq_num; 959 ever_validated = true; 960 } 961 return true; 962 } 963 964 virtual HRESULT STDMETHODCALLTYPE Present( 965 UINT SyncInterval, 966 UINT Flags) 967 { 968 if(Flags & DXGI_PRESENT_TEST) 969 return S_OK; 970 971 if(!buffer0) 972 { 973 HRESULT hr = create_buffer0(); 974 if(!SUCCEEDED(hr)) 975 return hr; 976 } 977 978 if(needs_validation) 979 { 980 if(!validate()) 981 return DXGI_ERROR_DEVICE_REMOVED; 982 } 983 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; 988 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 991 * sensible results. 992 * We could alternatively force using another context, but that might cause inefficiency issues 993 */ 994 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 997 */ 998 unsigned blit_x, blit_y, blit_w, blit_h; 999 float black[4] = {0, 0, 0, 0}; 1000 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); 1003 1004 int delta = src->width0 * dst->height0 - dst->width0 * src->height0; 1005 if(delta > 0) 1006 { 1007 blit_w = dst->width0; 1008 blit_h = dst->width0 * src->height0 / src->width0; 1009 } 1010 else if(delta < 0) 1011 { 1012 blit_w = dst->height0 * src->width0 / src->height0; 1013 blit_h = dst->height0; 1014 } 1015 else 1016 { 1017 blit_w = dst->width0; 1018 blit_h = dst->height0; 1019 } 1020 1021 blit_x = (dst->width0 - blit_w) >> 1; 1022 blit_y = (dst->height0 - blit_h) >> 1; 1023 1024 if(blit_x) 1025 pipe->clear_render_target(pipe, dst_surface, black, 0, 0, blit_x, dst->height0); 1026 if(blit_y) 1027 pipe->clear_render_target(pipe, dst_surface, black, 0, 0, dst->width0, blit_y); 1028 1029 if(formats_compatible && blit_w == src->width0 && blit_h == src->height0) 1030 { 1031 pipe_subresource sr; 1032 sr.face = 0; 1033 sr.level = 0; 1034 pipe->resource_copy_region(pipe, dst, sr, 0, 0, 0, src, sr, 0, 0, 0, blit_w, blit_h); 1035 } 1036 else 1037 { 1038 blitter->blit(dst_surface, gallium_buffer0_view, blit_x, blit_y, blit_w, blit_h); 1039 if(!owns_pipe) 1040 gallium_device->RestoreGalliumState(); 1041 } 1042 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); 1047 1048 if(dst_surface) 1049 pipe->screen->tex_surface_destroy(dst_surface); 1050 1051 if(db) 1052 { 1053 if(!surface->swap_buffers(surface)) 1054 return DXGI_ERROR_DEVICE_REMOVED; 1055 } 1056 else 1057 { 1058 if(!surface->flush_frontbuffer(surface)) 1059 return DXGI_ERROR_DEVICE_REMOVED; 1060 } 1061 1062 ++present_count; 1063 return S_OK; 1064 } 1065 1066 virtual HRESULT STDMETHODCALLTYPE GetBuffer( 1067 UINT Buffer, 1068 __in REFIID riid, 1069 __out void **ppSurface) 1070 { 1071 if(Buffer > 0) 1072 { 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; 1075 else 1076 std::cerr << "DXGI error: in GetBuffer(n), n must be 0 for DXGI_SWAP_EFFECT_DISCARD\n" << std::endl; 1077 } 1078 1079 if(!buffer0) 1080 { 1081 HRESULT hr = create_buffer0(); 1082 if(!SUCCEEDED(hr)) 1083 return hr; 1084 } 1085 return buffer0->QueryInterface(riid, ppSurface); 1086 } 1087 1088 /* TODO: implement somehow */ 1089 virtual HRESULT STDMETHODCALLTYPE SetFullscreenState( 1090 BOOL Fullscreen, 1091 __in_opt IDXGIOutput *pTarget) 1092 { 1093 fullscreen = Fullscreen; 1094 target = pTarget; 1095 return S_OK; 1096 } 1097 1098 virtual HRESULT STDMETHODCALLTYPE GetFullscreenState( 1099 __out BOOL *pFullscreen, 1100 __out IDXGIOutput **ppTarget) 1101 { 1102 if(pFullscreen) 1103 *pFullscreen = fullscreen; 1104 if(ppTarget) 1105 *ppTarget = target.ref(); 1106 return S_OK; 1107 } 1108 1109 virtual HRESULT STDMETHODCALLTYPE GetDesc( 1110 __out DXGI_SWAP_CHAIN_DESC *pDesc) 1111 { 1112 *pDesc = desc; 1113 return S_OK; 1114 } 1115 1116 virtual HRESULT STDMETHODCALLTYPE ResizeBuffers( 1117 UINT BufferCount, 1118 UINT Width, 1119 UINT Height, 1120 DXGI_FORMAT NewFormat, 1121 UINT SwapChainFlags) 1122 { 1123 if(buffer0) 1124 { 1125 buffer0.p->AddRef(); 1126 ULONG v = buffer0.p->Release(); 1127 // we must fail if there are any references to buffer0 other than ours 1128 if(v > 1) 1129 return E_FAIL; 1130 pipe_sampler_view_reference(&gallium_buffer0_view, 0); 1131 buffer0 = (IUnknown*)NULL; 1132 gallium_buffer0 = 0; 1133 } 1134 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; 1141 return S_OK; 1142 } 1143 1144 virtual HRESULT STDMETHODCALLTYPE ResizeTarget( 1145 const DXGI_MODE_DESC *pNewTargetParameters) 1146 { 1147 /* TODO: implement */ 1148 return S_OK; 1149 } 1150 1151 virtual HRESULT STDMETHODCALLTYPE GetContainingOutput( 1152 __out IDXGIOutput **ppOutput) 1153 { 1154 *ppOutput = adapter->outputs[0].ref(); 1155 return S_OK; 1156 } 1157 1158 virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics( 1159 __out DXGI_FRAME_STATISTICS *pStats) 1160 { 1161 memset(pStats, 0, sizeof(*pStats)); 1162#ifdef _WIN32 1163 QueryPerformanceCounter(&pStats->SyncQPCTime); 1164#endif 1165 pStats->PresentCount = present_count; 1166 pStats->PresentRefreshCount = present_count; 1167 pStats->SyncRefreshCount = present_count; 1168 return S_OK; 1169 } 1170 1171 virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount( 1172 __out UINT *pLastPresentCount) 1173 { 1174 *pLastPresentCount = present_count; 1175 return S_OK; 1176 } 1177}; 1178 1179static void GalliumDXGISwapChainRevalidate(IDXGISwapChain* swap_chain) 1180{ 1181 ((GalliumDXGISwapChain*)swap_chain)->needs_validation = true; 1182} 1183 1184static HRESULT GalliumDXGIAdapterCreate(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy, IDXGIAdapter1** pAdapter) 1185{ 1186 try 1187 { 1188 *pAdapter = new GalliumDXGIAdapter(factory, platform, dpy); 1189 return S_OK; 1190 } 1191 catch(HRESULT hr) 1192 { 1193 return hr; 1194 } 1195} 1196 1197static HRESULT GalliumDXGIOutputCreate(GalliumDXGIAdapter* adapter, const std::string& name, const struct native_connector* connector, IDXGIOutput** pOutput) 1198{ 1199 try 1200 { 1201 *pOutput = new GalliumDXGIOutput(adapter, name, connector); 1202 return S_OK; 1203 } 1204 catch(HRESULT hr) 1205 { 1206 return hr; 1207 } 1208} 1209 1210static HRESULT GalliumDXGISwapChainCreate(GalliumDXGIFactory* factory, IUnknown* device, const DXGI_SWAP_CHAIN_DESC& desc, IDXGISwapChain** pSwapChain) 1211{ 1212 try 1213 { 1214 *pSwapChain = new GalliumDXGISwapChain(factory, device, desc); 1215 return S_OK; 1216 } 1217 catch(HRESULT hr) 1218 { 1219 return hr; 1220 } 1221} 1222 1223struct dxgi_binding 1224{ 1225 const struct native_platform* platform; 1226 void* display; 1227 PFNHWNDRESOLVER resolver; 1228 void* resolver_cookie; 1229}; 1230 1231static dxgi_binding dxgi_default_binding; 1232static __thread dxgi_binding dxgi_thread_binding; 1233 1234void STDMETHODCALLTYPE GalliumDXGIUseNothing() 1235{ 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; 1240} 1241 1242#ifdef GALLIUM_DXGI_USE_X11 1243void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, PFNHWNDRESOLVER resolver, void* resolver_cookie) 1244{ 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; 1249} 1250#endif 1251 1252#ifdef GALLIUM_DXGI_USE_DRM 1253void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd) 1254{ 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; 1259} 1260#endif 1261 1262#ifdef GALLIUM_DXGI_USE_FBDEV 1263void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd) 1264{ 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; 1269} 1270#endif 1271 1272#ifdef GALLIUM_DXGI_USE_GDI 1273void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie) 1274{ 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; 1279} 1280#endif 1281 1282void STDMETHODCALLTYPE GalliumDXGIMakeDefault() 1283{ 1284 dxgi_default_binding = dxgi_thread_binding; 1285} 1286 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( 1291 __in REFIID riid, 1292 __out void **ppFactory 1293) 1294 { 1295 GalliumDXGIFactory* factory; 1296 *ppFactory = 0; 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); 1301 else 1302 factory = new GalliumDXGIFactory(native_get_x11_platform(), NULL, NULL, NULL); 1303 HRESULT hres = factory->QueryInterface(riid, ppFactory); 1304 factory->Release(); 1305 return hres; 1306 } 1307 1308 HRESULT STDMETHODCALLTYPE CreateDXGIFactory( 1309 __in REFIID riid, 1310 __out void **ppFactory 1311) 1312 { 1313 return CreateDXGIFactory1(riid, ppFactory); 1314 } 1315