dxgi_native.cpp revision 6ce098631abf465e89b12d10c4e6713b9c843422
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 : (PFNHWNDRESOLVER)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 display->destroy(display); 243 free(configs); 244 free(connectors); 245 } 246 247 virtual HRESULT STDMETHODCALLTYPE EnumOutputs( 248 UINT Output, 249 __out IDXGIOutput **ppOutput) 250 { 251 if(Output >= (unsigned)num_outputs) 252 return DXGI_ERROR_NOT_FOUND; 253 254 if(connectors) 255 { 256 std::ostringstream ss; 257 ss << "Output #" << Output; 258 return GalliumDXGIOutputCreate(this, ss.str(), connectors[Output], ppOutput); 259 } 260 else 261 return GalliumDXGIOutputCreate(this, "Unique output", NULL, ppOutput); 262 } 263 264 virtual HRESULT STDMETHODCALLTYPE GetDesc( 265 __out DXGI_ADAPTER_DESC *pDesc) 266 { 267 memcpy(pDesc, &desc, sizeof(*pDesc)); 268 return S_OK; 269 } 270 271 virtual HRESULT STDMETHODCALLTYPE GetDesc1( 272 __out DXGI_ADAPTER_DESC1 *pDesc) 273 { 274 memcpy(pDesc, &desc, sizeof(*pDesc)); 275 return S_OK; 276 } 277 278 virtual HRESULT STDMETHODCALLTYPE CheckInterfaceSupport( 279 __in REFGUID InterfaceName, 280 __out LARGE_INTEGER *pUMDVersion) 281 { 282 // these number was taken from Windows 7 with Catalyst 10.8: its meaning is unclear 283 if(InterfaceName == IID_ID3D11Device || InterfaceName == IID_ID3D10Device1 || InterfaceName == IID_ID3D10Device) 284 { 285 pUMDVersion->QuadPart = 0x00080011000a0411ULL; 286 return S_OK; 287 } 288 return DXGI_ERROR_UNSUPPORTED; 289 } 290 291 pipe_screen* STDMETHODCALLTYPE GetGalliumScreen() 292 { 293 return display->screen; 294 } 295 296 pipe_screen* STDMETHODCALLTYPE GetGalliumReferenceSoftwareScreen() 297 { 298 // TODO: give a softpipe screen 299 return display->screen; 300 } 301 302 pipe_screen* STDMETHODCALLTYPE GetGalliumFastSoftwareScreen() 303 { 304 // TODO: give an llvmpipe screen 305 return display->screen; 306 } 307}; 308 309 310struct GalliumDXGIOutput : public GalliumDXGIObject<IDXGIOutput, GalliumDXGIAdapter> 311{ 312 DXGI_OUTPUT_DESC desc; 313 const struct native_mode** modes; 314 DXGI_MODE_DESC* dxgi_modes; 315 unsigned num_modes; 316 const struct native_connector* connector; 317 DXGI_GAMMA_CONTROL* gamma; 318 319 GalliumDXGIOutput(GalliumDXGIAdapter* adapter, std::string name, const struct native_connector* connector = 0) 320 : GalliumDXGIObject<IDXGIOutput, GalliumDXGIAdapter>(adapter), connector(connector) 321 { 322 memset(&desc, 0, sizeof(desc)); 323 for(unsigned i = 0; i < std::min(name.size(), sizeof(desc.DeviceName) - 1); ++i) 324 desc.DeviceName[i] = name[i]; 325 desc.AttachedToDesktop = TRUE; 326 /* TODO: should put an HMONITOR in desc.Monitor */ 327 328 gamma = 0; 329 num_modes = 0; 330 modes = 0; 331 if(connector) 332 { 333 modes = parent->display->modeset->get_modes(parent->display, connector, (int*)&num_modes); 334 if(modes && num_modes) 335 { 336 dxgi_modes = new DXGI_MODE_DESC[num_modes]; 337 for(unsigned i = 0; i < num_modes; ++i) 338 { 339 dxgi_modes[i].Width = modes[i]->width; 340 dxgi_modes[i].Height = modes[i]->height; 341 dxgi_modes[i].RefreshRate.Numerator = modes[i]->refresh_rate; 342 dxgi_modes[i].RefreshRate.Denominator = 1; 343 dxgi_modes[i].Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 344 dxgi_modes[i].ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 345 } 346 } 347 else 348 { 349 if(modes) 350 { 351 free(modes); 352 modes = 0; 353 } 354 goto use_fake_mode; 355 } 356 } 357 else 358 { 359use_fake_mode: 360 dxgi_modes = new DXGI_MODE_DESC[1]; 361 dxgi_modes[0].Width = 1920; 362 dxgi_modes[0].Height = 1200; 363 dxgi_modes[0].RefreshRate.Numerator = 60; 364 dxgi_modes[0].RefreshRate.Denominator = 1; 365 dxgi_modes[0].Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 366 dxgi_modes[0].ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 367 } 368 } 369 370 ~GalliumDXGIOutput() 371 { 372 delete [] dxgi_modes; 373 free(modes); 374 if(gamma) 375 delete gamma; 376 } 377 378 virtual HRESULT STDMETHODCALLTYPE GetDesc( 379 __out DXGI_OUTPUT_DESC *pDesc) 380 { 381 *pDesc = desc; 382 return S_OK; 383 } 384 385 virtual HRESULT STDMETHODCALLTYPE GetDisplayModeList( 386 DXGI_FORMAT EnumFormat, 387 UINT Flags, 388 __inout UINT *pNumModes, 389 __out_ecount_part_opt(*pNumModes,*pNumModes) DXGI_MODE_DESC *pDesc) 390 { 391 /* TODO: should we return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE when we don't 392 * support modesetting instead of fake modes? 393 */ 394 pipe_format format = dxgi_to_pipe_format[EnumFormat]; 395 if(parent->configs_by_pipe_format.count(format)) 396 { 397 if(!pDesc) 398 { 399 *pNumModes = num_modes; 400 return S_OK; 401 } 402 403 unsigned copy_modes = std::min(num_modes, *pNumModes); 404 for(unsigned i = 0; i < copy_modes; ++i) 405 { 406 pDesc[i] = dxgi_modes[i]; 407 pDesc[i].Format = EnumFormat; 408 } 409 *pNumModes = num_modes; 410 411 if(copy_modes < num_modes) 412 return DXGI_ERROR_MORE_DATA; 413 else 414 return S_OK; 415 } 416 else 417 { 418 *pNumModes = 0; 419 return S_OK; 420 } 421 } 422 423 virtual HRESULT STDMETHODCALLTYPE FindClosestMatchingMode( 424 __in const DXGI_MODE_DESC *pModeToMatch, 425 __out DXGI_MODE_DESC *pClosestMatch, 426 __in_opt IUnknown *pConcernedDevice) 427 { 428 /* TODO: actually implement this */ 429 DXGI_FORMAT dxgi_format = pModeToMatch->Format; 430 enum pipe_format format = dxgi_to_pipe_format[dxgi_format]; 431 init_pipe_to_dxgi_format(); 432 if(!parent->configs_by_pipe_format.count(format)) 433 { 434 if(!pConcernedDevice) 435 return E_FAIL; 436 else 437 { 438 format = parent->configs[0]->color_format; 439 dxgi_format = pipe_to_dxgi_format[format]; 440 } 441 } 442 443 *pClosestMatch = dxgi_modes[0]; 444 pClosestMatch->Format = dxgi_format; 445 return S_OK; 446 } 447 448 virtual HRESULT STDMETHODCALLTYPE WaitForVBlank( void) 449 { 450 return S_OK; 451 } 452 453 virtual HRESULT STDMETHODCALLTYPE TakeOwnership( 454 __in IUnknown *pDevice, 455 BOOL Exclusive) 456 { 457 return S_OK; 458 } 459 460 virtual void STDMETHODCALLTYPE ReleaseOwnership( void) 461 { 462 } 463 464 virtual HRESULT STDMETHODCALLTYPE GetGammaControlCapabilities( 465 __out DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps) 466 { 467 memset(pGammaCaps, 0, sizeof(*pGammaCaps)); 468 return S_OK; 469 } 470 471 virtual HRESULT STDMETHODCALLTYPE SetGammaControl( 472 __in const DXGI_GAMMA_CONTROL *pArray) 473 { 474 if(!gamma) 475 gamma = new DXGI_GAMMA_CONTROL; 476 *gamma = *pArray; 477 return S_OK; 478 } 479 480 virtual HRESULT STDMETHODCALLTYPE GetGammaControl( 481 __out DXGI_GAMMA_CONTROL *pArray) 482 { 483 if(gamma) 484 *pArray = *gamma; 485 else 486 { 487 pArray->Scale.Red = 1; 488 pArray->Scale.Green = 1; 489 pArray->Scale.Blue = 1; 490 pArray->Offset.Red = 0; 491 pArray->Offset.Green = 0; 492 pArray->Offset.Blue = 0; 493 for(unsigned i = 0; i <= 1024; ++i) 494 pArray->GammaCurve[i].Red = pArray->GammaCurve[i].Green = pArray->GammaCurve[i].Blue = (float)i / 1024.0; 495 } 496 return S_OK; 497 } 498 499 virtual HRESULT STDMETHODCALLTYPE SetDisplaySurface( 500 __in IDXGISurface *pScanoutSurface) 501 { 502 return E_NOTIMPL; 503 } 504 505 virtual HRESULT STDMETHODCALLTYPE GetDisplaySurfaceData( 506 __in IDXGISurface *pDestination) 507 { 508 return E_NOTIMPL; 509 } 510 511 virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics( 512 __out DXGI_FRAME_STATISTICS *pStats) 513 { 514 memset(pStats, 0, sizeof(*pStats)); 515#ifdef _WIN32 516 QueryPerformanceCounter(&pStats->SyncQPCTime); 517#endif 518 return E_NOTIMPL; 519 } 520}; 521 522/* Swap chain are rather complex, and Microsoft's documentation is rather 523 * lacking. As far as I know, this is the most thorough publicly available 524 * description of how swap chains work, based on multiple sources and 525 * experimentation. 526 * 527 * There are two modes (called "swap effects") that a swap chain can operate in: 528 * discard and sequential. 529 * 530 * In discard mode, things always look as if there is a single buffer, which 531 * you can get with GetBuffers(0). 532 * The 2D texture returned by GetBuffers(0) and can only be 533 * used as a render target view and for resource copies, since no CPU access 534 * flags are set and only the D3D11_BIND_RENDER_TARGET bind flag is set. 535 * On Present, it is copied to the actual display 536 * surface and the contents become undefined. 537 * D3D may internally use multiple buffers, but you can't observe this, except 538 * by looking at the buffer contents after Present (but those are undefined). 539 * If it uses multiple buffers internally, then it will normally use BufferCount buffers 540 * (this has latency implications). 541 * Discard mode seems to internally use a single buffer in windowed mode, 542 * even if DWM is enabled, and BufferCount buffers in fullscreen mode. 543 * 544 * In sequential mode, the runtime alllocates BufferCount buffers. 545 * You can get each with GetBuffers(n). 546 * GetBuffers(0) ALWAYS points to the backbuffer to be presented and has the 547 * same usage constraints as the discard mode. 548 * GetBuffer(n) with n > 0 points to resources that are identical to buffer 0, but 549 * are classified as "read-only resources" (due to DXGI_USAGE_READ_ONLY), 550 * meaning that you can't create render target views on them, or use them as 551 * a CopyResource/CopySubresourceRegion destination. 552 * It appears the only valid operation is to use them as a source for CopyResource 553 * and CopySubresourceRegion as well as just waiting for them to become 554 * buffer 0 again. 555 * Buffer n - 1 is always displayed on screen. 556 * When you call Present(), the contents of the buffers are rotated, so that buffer 0 557 * goes to buffer n - 1, and is thus displayed, and buffer 1 goes to buffer 0, becomes 558 * the accessible back buffer. 559 * The resources themselves are NOT rotated, so that you can still render on the 560 * same ID3D11Texture2D*, and views based on it, that you got before Present(). 561 * 562 * Present seems to happen by either copying the relevant buffer into the window, 563 * or alternatively making it the current one, either by programming the CRTC or 564 * by sending the resource name to the DWM compositor. 565 * 566 * Hence, you can call GetBuffer(0) once and keep using the same ID3D11Texture2D* 567 * and ID3D11RenderTargetView* (and other views if needed) you got from it. 568 * 569 * If the window gets resized, DXGI will then "emulate" all successive presentations, 570 * by using a stretched blit automatically. 571 * Thus, you should handle WM_SIZE and call ResizeBuffers to update the DXGI 572 * swapchain buffers size to the new window size. 573 * Doing so requires you to release all GetBuffers() results and anything referencing 574 * them, including views and Direct3D11 deferred context command lists (this is 575 * documented). 576 * 577 * How does Microsoft implement the rotation behavior? 578 * It turns out that it does it by calling RotateResourceIdentitiesDXGI in the user-mode 579 * DDI driver. 580 * This will rotate the kernel buffer handle, or possibly rotate the GPU virtual memory 581 * mappings. 582 * 583 * The reason this is done by driver instead of by the runtime appears to be that 584 * this is necessary to support driver-provided command list support, since otherwise 585 * the command list would not always target the current backbuffer, since it would 586 * be done at the driver level, while only the runtime knows about the rotation. 587 * 588 * OK, so how do we implement this in Gallium? 589 * 590 * There are three strategies: 591 * 1. Use a single buffer, and always copy it to a window system provided buffer, or 592 * just give the buffer to the window system if it supports that 593 * 2. Rotate the buffers in the D3D1x implementation, and recreate and rebind the views. 594 * Don't support driver-provided command lists 595 * 3. Add this rotation functionality to the Gallium driver, with the idea that it would rotate 596 * remap GPU virtual memory, so that virtual address are unchanged, but the physical 597 * ones are rotated (so that pushbuffers remain valid). 598 * If the driver does not support this, either fall back to (1), or have a layer doing this, 599 * putting a deferred context layer over this intermediate layer. 600 * 601 * (2) is not acceptable since it prevents an optimal implementation. 602 * (3) is the ideal solution, but it is complicated. 603 * 604 * Hence, we implement (1) for now, and will switch to (3) later. 605 * 606 * Note that (1) doesn't really work for DXGI_SWAP_EFFECT_SEQUENTIAL with more 607 * than one buffer, so we just pretend we got asked for a single buffer in that case 608 * Fortunately, no one seems to rely on that, so we'll just not implement it at first, and 609 * later perform the rotation with blits. 610 * Once we switch to (3), we'll just use real rotation to do it.. 611 * 612 * DXGI_SWAP_EFFECT_SEQUENTIAL with more than one buffer is of dubious use 613 * anyway, since you can only render or write to buffer 0, and other buffers can apparently 614 * be used only as sources for copies. 615 * I was unable to find any code using it either in DirectX SDK examples, or on the web. 616 * 617 * It seems the only reason you would use it is to not have to redraw from scratch, while 618 * also possibly avoid a copy compared to BufferCount == 1, assuming that your 619 * application is OK with having to redraw starting not from the last frame, but from 620 * one/two/more frames behind it. 621 * 622 * A better design would forbid the user specifying BufferCount explicitly, and 623 * would instead let the application give an upper bound on how old the buffer can 624 * become after presentation, with "infinite" being equivalent to discard. 625 * The runtime would then tell the application with frame number the buffer switched to 626 * after present. 627 * In addition, in a better design, the application would be allowed to specify the 628 * number of buffers available, having all them usable for rendering, so that things 629 * like video players could efficiently decode frames in parallel. 630 * Present would in such a better design gain a way to specify the number of buffers 631 * to present. 632 * 633 * Other miscellaneous info: 634 * DXGI_PRESENT_DO_NOT_SEQUENCE causes DXGI to hold the frame for another 635 * vblank interval without rotating the resource data. 636 * 637 * References: 638 * "DXGI Overview" in MSDN 639 * IDXGISwapChain documentation on MSDN 640 * "RotateResourceIdentitiesDXGI" on MSDN 641 * http://forums.xna.com/forums/p/42362/266016.aspx 642 */ 643 644static float quad_data[] = { 645 -1, -1, 0, 0, 646 -1, 1, 0, 1, 647 1, 1, 1, 1, 648 1, -1, 1, 0, 649}; 650 651struct dxgi_blitter 652{ 653 pipe_context* pipe; 654 bool normalized; 655 void* fs; 656 void* vs; 657 void* sampler[2]; 658 void* elements; 659 void* blend; 660 void* rasterizer; 661 void* zsa; 662 struct pipe_clip_state clip; 663 struct pipe_vertex_buffer vbuf; 664 struct pipe_draw_info draw; 665 666 dxgi_blitter(pipe_context* pipe) 667 : pipe(pipe) 668 { 669 //normalized = !!pipe->screen->get_param(pipe, PIPE_CAP_NPOT_TEXTURES); 670 // TODO: need to update buffer in unnormalized case 671 normalized = true; 672 673 struct pipe_rasterizer_state rs_state; 674 memset(&rs_state, 0, sizeof(rs_state)); 675 rs_state.cull_face = PIPE_FACE_NONE; 676 rs_state.gl_rasterization_rules = 1; 677 rs_state.flatshade = 1; 678 rasterizer = pipe->create_rasterizer_state(pipe, &rs_state); 679 680 struct pipe_blend_state blendd; 681 blendd.rt[0].colormask = PIPE_MASK_RGBA; 682 blend = pipe->create_blend_state(pipe, &blendd); 683 684 struct pipe_depth_stencil_alpha_state zsad; 685 memset(&zsad, 0, sizeof(zsad)); 686 zsa = pipe->create_depth_stencil_alpha_state(pipe, &zsad); 687 688 struct pipe_vertex_element velem[2]; 689 memset(&velem[0], 0, sizeof(velem[0]) * 2); 690 velem[0].src_offset = 0; 691 velem[0].src_format = PIPE_FORMAT_R32G32_FLOAT; 692 velem[1].src_offset = 8; 693 velem[1].src_format = PIPE_FORMAT_R32G32_FLOAT; 694 elements = pipe->create_vertex_elements_state(pipe, 2, &velem[0]); 695 696 for(unsigned stretch = 0; stretch < 2; ++stretch) 697 { 698 struct pipe_sampler_state sampler_state; 699 memset(&sampler_state, 0, sizeof(sampler_state)); 700 sampler_state.min_img_filter = stretch ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST; 701 sampler_state.mag_img_filter = stretch ? PIPE_TEX_FILTER_LINEAR : PIPE_TEX_FILTER_NEAREST; 702 sampler_state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 703 sampler_state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 704 sampler_state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; 705 sampler_state.normalized_coords = normalized; 706 707 sampler[stretch] = pipe->create_sampler_state(pipe, &sampler_state); 708 } 709 710 fs = util_make_fragment_tex_shader(pipe, normalized ? TGSI_TEXTURE_2D : TGSI_TEXTURE_RECT, TGSI_INTERPOLATE_LINEAR); 711 712 const unsigned semantic_names[] = { TGSI_SEMANTIC_POSITION, TGSI_SEMANTIC_GENERIC }; 713 const unsigned semantic_indices[] = { 0, 0 }; 714 vs = util_make_vertex_passthrough_shader(pipe, 2, semantic_names, semantic_indices); 715 716 vbuf.buffer = pipe_buffer_create(pipe->screen, PIPE_BIND_VERTEX_BUFFER, sizeof(quad_data)); 717 vbuf.buffer_offset = 0; 718 vbuf.max_index = ~0; 719 vbuf.stride = 4 * sizeof(float); 720 pipe_buffer_write(pipe, vbuf.buffer, 0, sizeof(quad_data), quad_data); 721 722 memset(&clip, 0, sizeof(clip)); 723 724 memset(&draw, 0, sizeof(draw)); 725 draw.mode = PIPE_PRIM_QUADS; 726 draw.count = 4; 727 draw.instance_count = 1; 728 draw.max_index = ~0; 729 } 730 731 void blit(struct pipe_surface* surf, struct pipe_sampler_view* view, unsigned x, unsigned y, unsigned w, unsigned h) 732 { 733 struct pipe_framebuffer_state fb; 734 memset(&fb, 0, sizeof(fb)); 735 fb.nr_cbufs = 1; 736 fb.cbufs[0] = surf; 737 fb.width = surf->width; 738 fb.height = surf->height; 739 740 struct pipe_viewport_state viewport; 741 float half_width = w * 0.5f; 742 float half_height = h * 0.5f; 743 viewport.scale[0] = half_width; 744 viewport.scale[1] = half_height; 745 viewport.scale[2] = 1.0f; 746 viewport.scale[3] = 1.0f; 747 viewport.translate[0] = x + half_width; 748 viewport.translate[1] = y + half_height; 749 viewport.translate[2] = 0.0f; 750 viewport.translate[3] = 1.0f; 751 752 bool stretch = view->texture->width0 != w || view->texture->height0 != h; 753 if(pipe->render_condition) 754 pipe->render_condition(pipe, 0, 0); 755 pipe->set_framebuffer_state(pipe, &fb); 756 pipe->bind_fragment_sampler_states(pipe, 1, &sampler[stretch]); 757 pipe->set_viewport_state(pipe, &viewport); 758 pipe->set_clip_state(pipe, &clip); 759 pipe->bind_rasterizer_state(pipe, rasterizer); 760 pipe->bind_depth_stencil_alpha_state(pipe, zsa); 761 pipe->bind_blend_state(pipe, blend); 762 pipe->bind_vertex_elements_state(pipe, elements); 763 pipe->set_vertex_buffers(pipe, 1, &vbuf); 764 pipe->bind_fs_state(pipe, fs); 765 pipe->bind_vs_state(pipe, vs); 766 if(pipe->bind_gs_state) 767 pipe->bind_gs_state(pipe, 0); 768 if(pipe->bind_stream_output_state) 769 pipe->bind_stream_output_state(pipe, 0); 770 pipe->set_fragment_sampler_views(pipe, 1, &view); 771 772 pipe->draw_vbo(pipe, &draw); 773 } 774 775 ~dxgi_blitter() 776 { 777 pipe->delete_blend_state(pipe, blend); 778 pipe->delete_rasterizer_state(pipe, rasterizer); 779 pipe->delete_depth_stencil_alpha_state(pipe, zsa); 780 pipe->delete_sampler_state(pipe, sampler[0]); 781 pipe->delete_sampler_state(pipe, sampler[1]); 782 pipe->delete_vertex_elements_state(pipe, elements); 783 pipe->delete_vs_state(pipe, vs); 784 pipe->delete_fs_state(pipe, fs); 785 pipe->screen->resource_destroy(pipe->screen, vbuf.buffer); 786 } 787}; 788 789struct GalliumDXGISwapChain : public GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory> 790{ 791 ComPtr<IDXGIDevice>dxgi_device; 792 ComPtr<IGalliumDevice>gallium_device; 793 ComPtr<GalliumDXGIAdapter> adapter; 794 ComPtr<IDXGIOutput> target; 795 796 struct native_surface* surface; 797 const struct native_config* config; 798 799 struct pipe_resource* resources[NUM_NATIVE_ATTACHMENTS]; 800 int width; 801 int height; 802 unsigned seq_num; 803 bool ever_validated; 804 bool needs_validation; 805 unsigned present_count; 806 807 ComPtr<IDXGISurface> buffer0; 808 struct pipe_resource* gallium_buffer0; 809 struct pipe_sampler_view* gallium_buffer0_view; 810 811 DXGI_SWAP_CHAIN_DESC desc; 812 813 struct pipe_context* pipe; 814 bool owns_pipe; 815 816 BOOL fullscreen; 817 818 std::auto_ptr<dxgi_blitter> blitter; 819 bool formats_compatible; 820 821 GalliumDXGISwapChain(GalliumDXGIFactory* factory, IUnknown* p_device, const DXGI_SWAP_CHAIN_DESC& p_desc) 822 : GalliumDXGIObject<IDXGISwapChain, GalliumDXGIFactory>(factory), desc(p_desc) 823 { 824 HRESULT hr; 825 826 hr = p_device->QueryInterface(IID_IGalliumDevice, (void**)&gallium_device); 827 if(!SUCCEEDED(hr)) 828 throw hr; 829 830 hr = p_device->QueryInterface(IID_IDXGIDevice, (void**)&dxgi_device); 831 if(!SUCCEEDED(hr)) 832 throw hr; 833 834 hr = dxgi_device->GetAdapter((IDXGIAdapter**)&adapter); 835 if(!SUCCEEDED(hr)) 836 throw hr; 837 838 void* win = factory->resolver(factory->resolver_cookie, desc.OutputWindow); 839 840 unsigned config_num; 841 if(!strcmp(factory->platform->name, "X11")) 842 { 843 XWindowAttributes xwa; 844 XGetWindowAttributes((Display*)factory->display, (Window)win, &xwa); 845 config_num = adapter->configs_by_native_visual_id[xwa.visual->visualid]; 846 } 847 else 848 { 849 enum pipe_format format = dxgi_to_pipe_format[desc.BufferDesc.Format]; 850 if(!adapter->configs_by_pipe_format.count(format)) 851 { 852 if(adapter->configs_by_pipe_format.empty()) 853 throw E_FAIL; 854 // TODO: choose the best match 855 format = (pipe_format)adapter->configs_by_pipe_format.begin()->first; 856 } 857 // TODO: choose the best config 858 config_num = adapter->configs_by_pipe_format.find(format)->second; 859 } 860 861 config = adapter->configs[config_num]; 862 surface = adapter->display->create_window_surface(adapter->display, (EGLNativeWindowType)win, config); 863 surface->user_data = this; 864 865 width = 0; 866 height = 0; 867 seq_num = 0; 868 present_count = 0; 869 needs_validation = true; 870 ever_validated = false; 871 872 if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL && desc.BufferCount != 1) 873 { 874 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; 875 // change the returned desc, so that the application might perhaps notice what we did and react well 876 desc.BufferCount = 1; 877 } 878 879 pipe = gallium_device->GetGalliumContext(); 880 owns_pipe = false; 881 if(!pipe) 882 { 883 pipe = adapter->display->screen->context_create(adapter->display->screen, 0); 884 owns_pipe = true; 885 } 886 887 blitter.reset(new dxgi_blitter(pipe)); 888 889 formats_compatible = util_is_format_compatible( 890 util_format_description(dxgi_to_pipe_format[desc.BufferDesc.Format]), 891 util_format_description(config->color_format)); 892 } 893 894 ~GalliumDXGISwapChain() 895 { 896 if(owns_pipe) 897 pipe->destroy(pipe); 898 } 899 900 virtual HRESULT STDMETHODCALLTYPE GetDevice( 901 __in REFIID riid, 902 __out void **ppDevice) 903 { 904 return dxgi_device->QueryInterface(riid, ppDevice); 905 } 906 907 HRESULT create_buffer0() 908 { 909 HRESULT hr; 910 ComPtr<IDXGISurface> new_buffer0; 911 DXGI_USAGE usage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT; 912 if(desc.SwapEffect == DXGI_SWAP_EFFECT_DISCARD) 913 usage |= DXGI_USAGE_DISCARD_ON_PRESENT; 914 // for our blitter 915 usage |= DXGI_USAGE_SHADER_INPUT; 916 917 DXGI_SURFACE_DESC surface_desc; 918 surface_desc.Format = desc.BufferDesc.Format; 919 surface_desc.Width = desc.BufferDesc.Width; 920 surface_desc.Height = desc.BufferDesc.Height; 921 surface_desc.SampleDesc = desc.SampleDesc; 922 hr = dxgi_device->CreateSurface(&surface_desc, 1, usage, 0, &new_buffer0); 923 if(!SUCCEEDED(hr)) 924 return hr; 925 926 ComPtr<IGalliumResource> gallium_resource; 927 hr = new_buffer0->QueryInterface(IID_IGalliumResource, (void**)&gallium_resource); 928 if(!SUCCEEDED(hr)) 929 return hr; 930 931 struct pipe_resource* new_gallium_buffer0 = gallium_resource->GetGalliumResource(); 932 if(!new_gallium_buffer0) 933 return E_FAIL; 934 935 buffer0.reset(new_buffer0.steal()); 936 gallium_buffer0 = new_gallium_buffer0; 937 struct pipe_sampler_view templat; 938 memset(&templat, 0, sizeof(templat)); 939 templat.texture = gallium_buffer0; 940 templat.swizzle_r = 0; 941 templat.swizzle_g = 1; 942 templat.swizzle_b = 2; 943 templat.swizzle_a = 3; 944 templat.format = gallium_buffer0->format; 945 gallium_buffer0_view = pipe->create_sampler_view(pipe, gallium_buffer0, &templat); 946 return S_OK; 947 } 948 949 bool validate() 950 { 951 unsigned new_seq_num; 952 needs_validation = false; 953 954 if(!surface->validate(surface, 1 << NATIVE_ATTACHMENT_BACK_LEFT, &new_seq_num, resources, &width, &height)) 955 return false; 956 957 if(!ever_validated || seq_num != new_seq_num) 958 { 959 seq_num = new_seq_num; 960 ever_validated = true; 961 } 962 return true; 963 } 964 965 virtual HRESULT STDMETHODCALLTYPE Present( 966 UINT SyncInterval, 967 UINT Flags) 968 { 969 if(Flags & DXGI_PRESENT_TEST) 970 return S_OK; 971 972 if(!buffer0) 973 { 974 HRESULT hr = create_buffer0(); 975 if(!SUCCEEDED(hr)) 976 return hr; 977 } 978 979 if(needs_validation) 980 { 981 if(!validate()) 982 return DXGI_ERROR_DEVICE_REMOVED; 983 } 984 985 bool db = !!(config->buffer_mask & NATIVE_ATTACHMENT_BACK_LEFT); 986 struct pipe_resource* dst = resources[db ? NATIVE_ATTACHMENT_BACK_LEFT : NATIVE_ATTACHMENT_FRONT_LEFT]; 987 struct pipe_resource* src = gallium_buffer0; 988 struct pipe_surface* dst_surface = 0; 989 990 /* TODO: sharing the context for blitting won't work correctly if queries are active 991 * Hopefully no one is crazy enough to keep queries active while presenting, expecting 992 * sensible results. 993 * We could alternatively force using another context, but that might cause inefficiency issues 994 */ 995 996 /* Windows DXGI does not scale in an aspect-preserving way, but we do this 997 * by default, since we can and it's usually what you want 998 */ 999 unsigned blit_x, blit_y, blit_w, blit_h; 1000 float black[4] = {0, 0, 0, 0}; 1001 1002 if(!formats_compatible || src->width0 != dst->width0 || dst->width0 != src->width0) 1003 dst_surface = pipe->screen->get_tex_surface(pipe->screen, dst, 0, 0, 0, PIPE_BIND_RENDER_TARGET); 1004 1005 int delta = src->width0 * dst->height0 - dst->width0 * src->height0; 1006 if(delta > 0) 1007 { 1008 blit_w = dst->width0; 1009 blit_h = dst->width0 * src->height0 / src->width0; 1010 } 1011 else if(delta < 0) 1012 { 1013 blit_w = dst->height0 * src->width0 / src->height0; 1014 blit_h = dst->height0; 1015 } 1016 else 1017 { 1018 blit_w = dst->width0; 1019 blit_h = dst->height0; 1020 } 1021 1022 blit_x = (dst->width0 - blit_w) >> 1; 1023 blit_y = (dst->height0 - blit_h) >> 1; 1024 1025 if(blit_x) 1026 pipe->clear_render_target(pipe, dst_surface, black, 0, 0, blit_x, dst->height0); 1027 if(blit_y) 1028 pipe->clear_render_target(pipe, dst_surface, black, 0, 0, dst->width0, blit_y); 1029 1030 if(formats_compatible && blit_w == src->width0 && blit_h == src->height0) 1031 { 1032 pipe_subresource sr; 1033 sr.face = 0; 1034 sr.level = 0; 1035 pipe->resource_copy_region(pipe, dst, sr, 0, 0, 0, src, sr, 0, 0, 0, blit_w, blit_h); 1036 } 1037 else 1038 { 1039 blitter->blit(dst_surface, gallium_buffer0_view, blit_x, blit_y, blit_w, blit_h); 1040 if(!owns_pipe) 1041 gallium_device->RestoreGalliumState(); 1042 } 1043 1044 if(blit_w != dst->width0) 1045 pipe->clear_render_target(pipe, dst_surface, black, blit_x + blit_w, 0, dst->width0 - blit_x - blit_w, dst->height0); 1046 if(blit_h != dst->height0) 1047 pipe->clear_render_target(pipe, dst_surface, black, 0, blit_y + blit_h, dst->width0, dst->height0 - blit_y - blit_h); 1048 1049 if(dst_surface) 1050 pipe->screen->tex_surface_destroy(dst_surface); 1051 1052 if(db) 1053 { 1054 if(!surface->swap_buffers(surface)) 1055 return DXGI_ERROR_DEVICE_REMOVED; 1056 } 1057 else 1058 { 1059 if(!surface->flush_frontbuffer(surface)) 1060 return DXGI_ERROR_DEVICE_REMOVED; 1061 } 1062 1063 ++present_count; 1064 return S_OK; 1065 } 1066 1067 virtual HRESULT STDMETHODCALLTYPE GetBuffer( 1068 UINT Buffer, 1069 __in REFIID riid, 1070 __out void **ppSurface) 1071 { 1072 if(Buffer > 0) 1073 { 1074 if(desc.SwapEffect == DXGI_SWAP_EFFECT_SEQUENTIAL) 1075 std::cerr << "DXGI unimplemented: GetBuffer(n) with n > 0 not supported, returning buffer 0 instead!" << std::endl; 1076 else 1077 std::cerr << "DXGI error: in GetBuffer(n), n must be 0 for DXGI_SWAP_EFFECT_DISCARD\n" << std::endl; 1078 } 1079 1080 if(!buffer0) 1081 { 1082 HRESULT hr = create_buffer0(); 1083 if(!SUCCEEDED(hr)) 1084 return hr; 1085 } 1086 return buffer0->QueryInterface(riid, ppSurface); 1087 } 1088 1089 /* TODO: implement somehow */ 1090 virtual HRESULT STDMETHODCALLTYPE SetFullscreenState( 1091 BOOL Fullscreen, 1092 __in_opt IDXGIOutput *pTarget) 1093 { 1094 fullscreen = Fullscreen; 1095 target = pTarget; 1096 return S_OK; 1097 } 1098 1099 virtual HRESULT STDMETHODCALLTYPE GetFullscreenState( 1100 __out BOOL *pFullscreen, 1101 __out IDXGIOutput **ppTarget) 1102 { 1103 if(pFullscreen) 1104 *pFullscreen = fullscreen; 1105 if(ppTarget) 1106 *ppTarget = target.ref(); 1107 return S_OK; 1108 } 1109 1110 virtual HRESULT STDMETHODCALLTYPE GetDesc( 1111 __out DXGI_SWAP_CHAIN_DESC *pDesc) 1112 { 1113 *pDesc = desc; 1114 return S_OK; 1115 } 1116 1117 virtual HRESULT STDMETHODCALLTYPE ResizeBuffers( 1118 UINT BufferCount, 1119 UINT Width, 1120 UINT Height, 1121 DXGI_FORMAT NewFormat, 1122 UINT SwapChainFlags) 1123 { 1124 if(buffer0) 1125 { 1126 buffer0.p->AddRef(); 1127 ULONG v = buffer0.p->Release(); 1128 // we must fail if there are any references to buffer0 other than ours 1129 if(v > 1) 1130 return E_FAIL; 1131 pipe_sampler_view_reference(&gallium_buffer0_view, 0); 1132 buffer0 = (IUnknown*)NULL; 1133 gallium_buffer0 = 0; 1134 } 1135 1136 if(desc.SwapEffect != DXGI_SWAP_EFFECT_SEQUENTIAL) 1137 desc.BufferCount = BufferCount; 1138 desc.BufferDesc.Format = NewFormat; 1139 desc.BufferDesc.Width = Width; 1140 desc.BufferDesc.Height = Height; 1141 desc.Flags = SwapChainFlags; 1142 return S_OK; 1143 } 1144 1145 virtual HRESULT STDMETHODCALLTYPE ResizeTarget( 1146 const DXGI_MODE_DESC *pNewTargetParameters) 1147 { 1148 /* TODO: implement */ 1149 return S_OK; 1150 } 1151 1152 virtual HRESULT STDMETHODCALLTYPE GetContainingOutput( 1153 __out IDXGIOutput **ppOutput) 1154 { 1155 *ppOutput = adapter->outputs[0].ref(); 1156 return S_OK; 1157 } 1158 1159 virtual HRESULT STDMETHODCALLTYPE GetFrameStatistics( 1160 __out DXGI_FRAME_STATISTICS *pStats) 1161 { 1162 memset(pStats, 0, sizeof(*pStats)); 1163#ifdef _WIN32 1164 QueryPerformanceCounter(&pStats->SyncQPCTime); 1165#endif 1166 pStats->PresentCount = present_count; 1167 pStats->PresentRefreshCount = present_count; 1168 pStats->SyncRefreshCount = present_count; 1169 return S_OK; 1170 } 1171 1172 virtual HRESULT STDMETHODCALLTYPE GetLastPresentCount( 1173 __out UINT *pLastPresentCount) 1174 { 1175 *pLastPresentCount = present_count; 1176 return S_OK; 1177 } 1178}; 1179 1180static void GalliumDXGISwapChainRevalidate(IDXGISwapChain* swap_chain) 1181{ 1182 ((GalliumDXGISwapChain*)swap_chain)->needs_validation = true; 1183} 1184 1185static HRESULT GalliumDXGIAdapterCreate(GalliumDXGIFactory* factory, const struct native_platform* platform, void* dpy, IDXGIAdapter1** pAdapter) 1186{ 1187 try 1188 { 1189 *pAdapter = new GalliumDXGIAdapter(factory, platform, dpy); 1190 return S_OK; 1191 } 1192 catch(HRESULT hr) 1193 { 1194 return hr; 1195 } 1196} 1197 1198static HRESULT GalliumDXGIOutputCreate(GalliumDXGIAdapter* adapter, const std::string& name, const struct native_connector* connector, IDXGIOutput** pOutput) 1199{ 1200 try 1201 { 1202 *pOutput = new GalliumDXGIOutput(adapter, name, connector); 1203 return S_OK; 1204 } 1205 catch(HRESULT hr) 1206 { 1207 return hr; 1208 } 1209} 1210 1211static HRESULT GalliumDXGISwapChainCreate(GalliumDXGIFactory* factory, IUnknown* device, const DXGI_SWAP_CHAIN_DESC& desc, IDXGISwapChain** pSwapChain) 1212{ 1213 try 1214 { 1215 *pSwapChain = new GalliumDXGISwapChain(factory, device, desc); 1216 return S_OK; 1217 } 1218 catch(HRESULT hr) 1219 { 1220 return hr; 1221 } 1222} 1223 1224struct dxgi_binding 1225{ 1226 const struct native_platform* platform; 1227 void* display; 1228 PFNHWNDRESOLVER resolver; 1229 void* resolver_cookie; 1230}; 1231 1232static dxgi_binding dxgi_default_binding; 1233static __thread dxgi_binding dxgi_thread_binding; 1234 1235void STDMETHODCALLTYPE GalliumDXGIUseNothing() 1236{ 1237 dxgi_thread_binding.platform = 0; 1238 dxgi_thread_binding.display = 0; 1239 dxgi_thread_binding.resolver = 0; 1240 dxgi_thread_binding.resolver_cookie = 0; 1241} 1242 1243#ifdef GALLIUM_DXGI_USE_X11 1244void STDMETHODCALLTYPE GalliumDXGIUseX11Display(Display* dpy, PFNHWNDRESOLVER resolver, void* resolver_cookie) 1245{ 1246 dxgi_thread_binding.platform = native_get_x11_platform(); 1247 dxgi_thread_binding.display = dpy; 1248 dxgi_thread_binding.resolver = resolver; 1249 dxgi_thread_binding.resolver_cookie = resolver_cookie; 1250} 1251#endif 1252 1253#ifdef GALLIUM_DXGI_USE_DRM 1254void STDMETHODCALLTYPE GalliumDXGIUseDRMCard(int fd) 1255{ 1256 dxgi_thread_binding.platform = native_get_drm_platform(); 1257 dxgi_thread_binding.display = (void*)fd; 1258 dxgi_thread_binding.resolver = 0; 1259 dxgi_thread_binding.resolver_cookie = 0; 1260} 1261#endif 1262 1263#ifdef GALLIUM_DXGI_USE_FBDEV 1264void STDMETHODCALLTYPE GalliumDXGIUseFBDev(int fd) 1265{ 1266 dxgi_thread_binding.platform = native_get_fbdev_platform(); 1267 dxgi_thread_binding.display = (void*)fd; 1268 dxgi_thread_binding.resolver = 0; 1269 dxgi_thread_binding.resolver_cookie = 0; 1270} 1271#endif 1272 1273#ifdef GALLIUM_DXGI_USE_GDI 1274void STDMETHODCALLTYPE GalliumDXGIUseHDC(HDC hdc, PFNHWNDRESOLVER resolver, void* resolver_cookie) 1275{ 1276 dxgi_thread_binding.platform = native_get_gdi_platform(); 1277 dxgi_thread_binding.display = (void*)hdc; 1278 dxgi_thread_binding.resolver = resolver; 1279 dxgi_thread_binding.resolver_cookie = resolver_cookie; 1280} 1281#endif 1282 1283void STDMETHODCALLTYPE GalliumDXGIMakeDefault() 1284{ 1285 dxgi_default_binding = dxgi_thread_binding; 1286} 1287 1288 /* TODO: why did Microsoft add this? should we do something different for DXGI 1.0 and 1.1? 1289 * Or perhaps what they actually mean is "only create a single factory in your application"? 1290 * TODO: should we use a singleton here, so we never have multiple DXGI objects for the same thing? */ 1291 HRESULT STDMETHODCALLTYPE CreateDXGIFactory1( 1292 __in REFIID riid, 1293 __out void **ppFactory 1294) 1295 { 1296 GalliumDXGIFactory* factory; 1297 *ppFactory = 0; 1298 if(dxgi_thread_binding.platform) 1299 factory = new GalliumDXGIFactory(dxgi_thread_binding.platform, dxgi_thread_binding.display, dxgi_thread_binding.resolver, dxgi_thread_binding.resolver_cookie); 1300 else if(dxgi_default_binding.platform) 1301 factory = new GalliumDXGIFactory(dxgi_default_binding.platform, dxgi_default_binding.display, dxgi_default_binding.resolver, dxgi_default_binding.resolver_cookie); 1302 else 1303 factory = new GalliumDXGIFactory(native_get_x11_platform(), NULL, NULL, NULL); 1304 HRESULT hres = factory->QueryInterface(riid, ppFactory); 1305 factory->Release(); 1306 return hres; 1307 } 1308 1309 HRESULT STDMETHODCALLTYPE CreateDXGIFactory( 1310 __in REFIID riid, 1311 __out void **ppFactory 1312) 1313 { 1314 return CreateDXGIFactory1(riid, ppFactory); 1315 } 1316