2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
24 #include <DirectXPackedVector.h>
25 #include "Application.h"
26 #include "RenderSystemDX.h"
27 #include "cores/VideoRenderers/RenderManager.h"
28 #include "guilib/D3DResource.h"
29 #include "guilib/GUIShaderDX.h"
30 #include "guilib/GUITextureD3D.h"
31 #include "guilib/GUIWindowManager.h"
32 #include "settings/AdvancedSettings.h"
33 #include "threads/SingleLock.h"
34 #include "utils/MathUtils.h"
35 #include "utils/TimeUtils.h"
36 #include "utils/log.h"
37 #include "win32/WIN32Util.h"
38 #include "win32/dxerr.h"
40 #pragma comment(lib, "d3d11.lib")
41 #pragma comment(lib, "dxgi.lib")
42 #pragma comment(lib, "dxguid.lib")
44 #define RATIONAL_TO_FLOAT(rational) ((rational.Denominator != 0) ? (float)rational.Numerator / (float)rational.Denominator : 0.0)
46 using namespace DirectX::PackedVector;
48 CRenderSystemDX::CRenderSystemDX() : CRenderSystemBase()
50 m_enumRenderingSystem = RENDERING_SYSTEM_DIRECTX;
54 m_nBackBufferWidth = 0;
55 m_nBackBufferHeight = 0;
56 m_bFullScreenDevice = false;
58 m_nDeviceStatus = S_OK;
60 m_needNewDevice = false;
61 m_resizeInProgress = false;
63 m_systemFreq = CurrentHostFrequency();
65 m_defaultD3DUsage = D3D11_USAGE_DEFAULT;
67 m_featureLevel = D3D_FEATURE_LEVEL_11_1;
68 m_driverType = D3D_DRIVER_TYPE_HARDWARE;
79 m_pRenderTargetView = NULL;
80 m_depthStencilState = NULL;
81 m_depthStencilView = NULL;
82 m_BlendEnableState = NULL;
83 m_BlendDisableState = NULL;
84 m_BlendEnabled = false;
85 m_RSScissorDisable = NULL;
86 m_RSScissorEnable = NULL;
87 m_ScissorsEnabled = false;
89 m_pTextureRight = NULL;
90 m_pRenderTargetViewRight = NULL;
91 m_pShaderResourceViewRight = NULL;
93 m_bResizeRequred = false;
94 m_bHWStereoEnabled = false;
95 ZeroMemory(&m_cachedMode, sizeof(m_cachedMode));
96 ZeroMemory(&m_viewPort, sizeof(m_viewPort));
97 ZeroMemory(&m_scissor, sizeof(CRect));
100 CRenderSystemDX::~CRenderSystemDX()
104 bool CRenderSystemDX::InitRenderSystem()
108 CLog::Log(LOGDEBUG, __FUNCTION__" - Initializing D3D11 Factory...");
110 HRESULT hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&m_dxgiFactory));
113 CLog::Log(LOGERROR, __FUNCTION__" - D3D11 initialization failed.");
118 return CreateDevice();
121 void CRenderSystemDX::SetRenderParams(unsigned int width, unsigned int height, bool fullScreen, float refreshRate)
123 m_nBackBufferWidth = width;
124 m_nBackBufferHeight = height;
125 m_bFullScreenDevice = fullScreen;
126 m_refreshRate = refreshRate;
129 void CRenderSystemDX::SetMonitor(HMONITOR monitor)
134 DXGI_OUTPUT_DESC outputDesc;
135 if (m_pOutput && SUCCEEDED(m_pOutput->GetDesc(&outputDesc)) && outputDesc.Monitor == monitor)
138 // find the appropriate screen
139 IDXGIAdapter1* pAdapter;
140 for (unsigned i = 0; m_dxgiFactory->EnumAdapters1(i, &pAdapter) != DXGI_ERROR_NOT_FOUND; ++i)
142 IDXGIOutput* pOutput;
143 for (unsigned j = 0; pAdapter->EnumOutputs(j, &pOutput) != DXGI_ERROR_NOT_FOUND; ++j)
145 if (FAILED(pOutput->GetDesc(&outputDesc)))
148 if (outputDesc.Monitor == monitor)
150 // update monitor info
151 SAFE_RELEASE(m_pOutput);
154 CLog::Log(LOGDEBUG, __FUNCTION__" - Selected %S output. ", outputDesc.DeviceName);
156 // check if adapter is changed
157 if (m_adapterIndex != i)
159 pAdapter->GetDesc(&m_adapterDesc);
161 CLog::Log(LOGDEBUG, __FUNCTION__" - Selected %S adapter. ", m_adapterDesc.Description);
163 SAFE_RELEASE(m_adapter);
164 m_adapter = pAdapter;
166 m_needNewDevice = true;
180 bool CRenderSystemDX::ResetRenderSystem(int width, int height, bool fullScreen, float refreshRate)
185 if (m_hDeviceWnd != NULL)
187 HMONITOR hMonitor = MonitorFromWindow(m_hDeviceWnd, MONITOR_DEFAULTTONULL);
189 SetMonitor(hMonitor);
192 SetRenderParams(width, height, fullScreen, refreshRate);
194 CRect rc(0, 0, float(width), float(height));
197 if (!m_needNewDevice)
199 CreateWindowSizeDependentResources();
200 SetFullScreenInternal();
201 if (m_bResizeRequred)
202 CreateWindowSizeDependentResources();
213 void CRenderSystemDX::OnMove()
215 if (!m_bRenderCreated)
218 DXGI_OUTPUT_DESC outputDesc;
219 m_pOutput->GetDesc(&outputDesc);
220 HMONITOR newMonitor = MonitorFromWindow(m_hDeviceWnd, MONITOR_DEFAULTTONULL);
222 if (newMonitor != NULL && outputDesc.Monitor != newMonitor)
224 SetMonitor(newMonitor);
227 CLog::Log(LOGDEBUG, "%s - Adapter changed, reseting render system.", __FUNCTION__);
228 ResetRenderSystem(m_nBackBufferWidth, m_nBackBufferHeight, m_bFullScreenDevice, m_refreshRate);
233 void CRenderSystemDX::OnResize(unsigned int width, unsigned int height)
235 if (!m_bRenderCreated)
238 m_nBackBufferWidth = width;
239 m_nBackBufferHeight = height;
240 CreateWindowSizeDependentResources();
243 void CRenderSystemDX::GetClosestDisplayModeToCurrent(IDXGIOutput* output, DXGI_MODE_DESC* outCurrentDisplayMode, bool useCached /*= false*/)
245 DXGI_OUTPUT_DESC outputDesc;
246 output->GetDesc(&outputDesc);
247 HMONITOR hMonitor = outputDesc.Monitor;
248 MONITORINFOEX monitorInfo;
249 monitorInfo.cbSize = sizeof(MONITORINFOEX);
250 GetMonitorInfo(hMonitor, &monitorInfo);
252 devMode.dmSize = sizeof(DEVMODE);
253 devMode.dmDriverExtra = 0;
254 EnumDisplaySettings(monitorInfo.szDevice, ENUM_CURRENT_SETTINGS, &devMode);
256 bool useDefaultRefreshRate = 1 == devMode.dmDisplayFrequency || 0 == devMode.dmDisplayFrequency;
257 float refreshRate = RATIONAL_TO_FLOAT(m_cachedMode.RefreshRate);
259 // this needed to improve performance for VideoSync bacause FindClosestMatchingMode is very slow
261 || m_cachedMode.Width != devMode.dmPelsWidth
262 || m_cachedMode.Height != devMode.dmPelsHeight
263 || long(refreshRate) != devMode.dmDisplayFrequency)
265 DXGI_MODE_DESC current;
266 current.Width = devMode.dmPelsWidth;
267 current.Height = devMode.dmPelsHeight;
268 current.RefreshRate.Numerator = useDefaultRefreshRate ? 0 : devMode.dmDisplayFrequency;
269 current.RefreshRate.Denominator = useDefaultRefreshRate ? 0 : 1;
270 current.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
271 current.ScanlineOrdering = m_interlaced ? DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST : DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
272 current.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
274 output->FindClosestMatchingMode(¤t, &m_cachedMode, m_pD3DDev);
277 ZeroMemory(outCurrentDisplayMode, sizeof(DXGI_MODE_DESC));
278 outCurrentDisplayMode->Width = m_cachedMode.Width;
279 outCurrentDisplayMode->Height = m_cachedMode.Height;
280 outCurrentDisplayMode->RefreshRate.Numerator = m_cachedMode.RefreshRate.Numerator;
281 outCurrentDisplayMode->RefreshRate.Denominator = m_cachedMode.RefreshRate.Denominator;
282 outCurrentDisplayMode->Format = m_cachedMode.Format;
283 outCurrentDisplayMode->ScanlineOrdering = m_cachedMode.ScanlineOrdering;
284 outCurrentDisplayMode->Scaling = m_cachedMode.Scaling;
287 void CRenderSystemDX::GetDisplayMode(DXGI_MODE_DESC *mode, bool useCached /*= false*/)
289 GetClosestDisplayModeToCurrent(m_pOutput, mode, useCached);
292 inline void DXWait(ID3D11Device* pDevice, ID3D11DeviceContext* pContext)
294 ID3D11Query* wait = NULL;
295 CD3D11_QUERY_DESC qd(D3D11_QUERY_EVENT);
296 if (SUCCEEDED(pDevice->CreateQuery(&qd, &wait)))
299 while (S_FALSE == pContext->GetData(wait, NULL, 0, 0))
305 void CRenderSystemDX::SetFullScreenInternal()
307 if (!m_bRenderCreated)
312 m_pSwapChain->GetFullscreenState(&bFullScreen, NULL);
314 // full-screen to windowed translation. Only change FS state and return
315 if (!!bFullScreen && m_useWindowedDX)
317 CLog::Log(LOGDEBUG, "%s - Switching swap chain to windowed mode.", __FUNCTION__);
318 hr = m_pSwapChain->SetFullscreenState(false, NULL);
319 m_bResizeRequred = S_OK == hr;
322 CLog::Log(LOGERROR, "%s - Failed switch full screen state: %s.", __FUNCTION__, GetErrorDescription(hr).c_str());
323 // wait until switching screen state is done
324 DXWait(m_pD3DDev, m_pImdContext);
329 if (m_bFullScreenDevice && !m_useWindowedDX)
331 IDXGIOutput* pOutput = NULL;
332 m_pSwapChain->GetContainingOutput(&pOutput);
334 DXGI_OUTPUT_DESC trgDesc, currDesc;
335 m_pOutput->GetDesc(&trgDesc);
336 pOutput->GetDesc(&currDesc);
338 if (trgDesc.Monitor != currDesc.Monitor || !bFullScreen)
340 // swap chain requires to change FS mode after resize or transition from windowed to full-screen.
341 CLog::Log(LOGDEBUG, "%s - Switching swap chain to fullscreen state.", __FUNCTION__);
342 hr = m_pSwapChain->SetFullscreenState(true, m_pOutput);
343 m_bResizeRequred = S_OK == hr;
346 CLog::Log(LOGERROR, "%s - Failed switch full screen state: %s.", __FUNCTION__, GetErrorDescription(hr).c_str());
348 SAFE_RELEASE(pOutput);
350 // do not change modes if hw stereo
351 if (g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_HARDWAREBASED)
354 DXGI_SWAP_CHAIN_DESC scDesc;
355 m_pSwapChain->GetDesc(&scDesc);
357 DXGI_MODE_DESC currentMode, // closest to current mode
358 toMatchMode, // required mode
359 matchedMode; // closest to required mode
361 // find current mode on target output
362 GetClosestDisplayModeToCurrent(m_pOutput, ¤tMode);
364 float currentRefreshRate = RATIONAL_TO_FLOAT(currentMode.RefreshRate);
365 CLog::Log(LOGDEBUG, "%s - Current display mode is: %dx%d@%0.3f", __FUNCTION__, currentMode.Width, currentMode.Height, currentRefreshRate);
367 // use backbuffer dimention to find required display mode
368 toMatchMode.Width = m_nBackBufferWidth;
369 toMatchMode.Height = m_nBackBufferHeight;
370 bool useDefaultRefreshRate = 0 == m_refreshRate;
371 toMatchMode.RefreshRate.Numerator = useDefaultRefreshRate ? 0 : m_refreshRate;
372 toMatchMode.RefreshRate.Denominator = useDefaultRefreshRate ? 0 : 1;
373 toMatchMode.Format = scDesc.BufferDesc.Format;
374 toMatchMode.Scaling = scDesc.BufferDesc.Scaling;
375 toMatchMode.ScanlineOrdering = scDesc.BufferDesc.ScanlineOrdering;
378 m_pOutput->FindClosestMatchingMode(&toMatchMode, &matchedMode, m_pD3DDev);
380 float matchedRefreshRate = RATIONAL_TO_FLOAT(matchedMode.RefreshRate);
381 CLog::Log(LOGDEBUG, "%s - Found matched mode: %dx%d@%0.3f", __FUNCTION__, matchedMode.Width, matchedMode.Height, matchedRefreshRate);
383 // change mode if required (current != required)
384 if ( currentMode.Width != matchedMode.Width
385 || currentMode.Height != matchedMode.Height
386 || currentRefreshRate != matchedRefreshRate)
388 CLog::Log(LOGDEBUG, "%s - Switching mode to %dx%d@%0.3f.", __FUNCTION__, matchedMode.Width, matchedMode.Height, matchedRefreshRate);
390 // resize window (in windowed mode) or monitor resolution (in fullscreen mode) to required mode
391 hr = m_pSwapChain->ResizeTarget(&matchedMode);
392 m_bResizeRequred = S_OK == hr;
395 CLog::Log(LOGERROR, "%s - Failed to switch output mode: %s", __FUNCTION__, GetErrorDescription(hr).c_str());
398 // wait until switching screen state is done
399 DXWait(m_pD3DDev, m_pImdContext);
403 bool CRenderSystemDX::IsFormatSupport(DXGI_FORMAT format, unsigned int usage)
406 m_pD3DDev->CheckFormatSupport(format, &supported);
407 return (supported & usage) != 0;
410 bool CRenderSystemDX::DestroyRenderSystem()
414 SAFE_RELEASE(m_pOutput);
415 SAFE_RELEASE(m_adapter);
416 SAFE_RELEASE(m_dxgiFactory);
420 void CRenderSystemDX::DeleteDevice()
422 CSingleLock lock(m_resourceSection);
427 // tell any shared resources
428 for (std::vector<ID3DResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i)
429 (*i)->OnDestroyDevice();
432 m_pSwapChain->SetFullscreenState(false, NULL);
434 SAFE_DELETE(m_pGUIShader);
435 SAFE_RELEASE(m_pTextureRight);
436 SAFE_RELEASE(m_pRenderTargetViewRight);
437 SAFE_RELEASE(m_pShaderResourceViewRight);
438 SAFE_RELEASE(m_BlendEnableState);
439 SAFE_RELEASE(m_BlendDisableState);
440 SAFE_RELEASE(m_RSScissorDisable);
441 SAFE_RELEASE(m_RSScissorEnable);
442 SAFE_RELEASE(m_depthStencilState);
443 SAFE_RELEASE(m_depthStencilView);
444 SAFE_RELEASE(m_pRenderTargetView);
445 if (m_pContext && m_pContext != m_pImdContext)
447 m_pContext->ClearState();
449 SAFE_RELEASE(m_pContext);
453 m_pImdContext->ClearState();
454 m_pImdContext->Flush();
455 SAFE_RELEASE(m_pImdContext);
457 SAFE_RELEASE(m_pSwapChain);
458 SAFE_RELEASE(m_pSwapChain1);
459 SAFE_RELEASE(m_pD3DDev);
463 m_d3dDebug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL);
464 SAFE_RELEASE(m_d3dDebug);
467 m_bResizeRequred = false;
468 m_bHWStereoEnabled = false;
469 m_bRenderCreated = false;
472 void CRenderSystemDX::OnDeviceLost()
474 CSingleLock lock(m_resourceSection);
475 g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_LOST);
481 // just resetting the device
482 for (std::vector<ID3DResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i)
483 (*i)->OnLostDevice();
487 void CRenderSystemDX::OnDeviceReset()
489 CSingleLock lock(m_resourceSection);
494 if (m_bRenderCreated)
497 for (std::vector<ID3DResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i)
498 (*i)->OnResetDevice();
500 g_renderManager.Flush();
501 g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_RESET);
505 bool CRenderSystemDX::CreateDevice()
507 CSingleLock lock(m_resourceSection);
511 SAFE_RELEASE(m_pD3DDev);
513 D3D_FEATURE_LEVEL featureLevels[] =
515 D3D_FEATURE_LEVEL_11_1,
516 D3D_FEATURE_LEVEL_11_0,
517 D3D_FEATURE_LEVEL_10_1,
518 D3D_FEATURE_LEVEL_10_0,
519 D3D_FEATURE_LEVEL_9_3,
520 D3D_FEATURE_LEVEL_9_2,
521 D3D_FEATURE_LEVEL_9_1,
524 // the VIDEO_SUPPORT flag force lowering feature level if current env not support video on 11_1
525 UINT createDeviceFlags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
527 createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
530 // we should specify D3D_DRIVER_TYPE_UNKNOWN if create device with specified adapter.
531 hr = D3D11CreateDevice(m_adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, createDeviceFlags, featureLevels, ARRAYSIZE(featureLevels),
532 D3D11_SDK_VERSION, &m_pD3DDev, &m_featureLevel, &m_pImdContext);
536 // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it
537 CLog::Log(LOGDEBUG, "%s - First try to create device failed with error: %s.", __FUNCTION__, GetErrorDescription(hr).c_str());
538 CLog::Log(LOGDEBUG, "%s - Trying to create device with lowest feature level: %#x.", __FUNCTION__, featureLevels[1]);
540 hr = D3D11CreateDevice(m_adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, createDeviceFlags, &featureLevels[1], ARRAYSIZE(featureLevels) - 1,
541 D3D11_SDK_VERSION, &m_pD3DDev, &m_featureLevel, &m_pImdContext);
544 // still failed. seems driver doesn't support video API acceleration, try without VIDEO_SUPPORT flag
545 CLog::Log(LOGDEBUG, "%s - Next try to create device failed with error: %s.", __FUNCTION__, GetErrorDescription(hr).c_str());
546 CLog::Log(LOGDEBUG, "%s - Trying to create device without video API support.", __FUNCTION__);
548 createDeviceFlags &= ~D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
549 hr = D3D11CreateDevice(m_adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, createDeviceFlags, &featureLevels[1], ARRAYSIZE(featureLevels) - 1,
550 D3D11_SDK_VERSION, &m_pD3DDev, &m_featureLevel, &m_pImdContext);
552 CLog::Log(LOGNOTICE, "%s - Your video driver doesn't support DirectX 11 Video Acceleration API. Application is not be able to use hardware video processing and decoding", __FUNCTION__);
558 CLog::Log(LOGERROR, "%s - D3D11 device creation failure with error %s.", __FUNCTION__, GetErrorDescription(hr).c_str());
562 if ( g_advancedSettings.m_bAllowDeferredRendering
563 && FAILED(m_pD3DDev->CreateDeferredContext(0, &m_pContext)))
565 CLog::Log(LOGERROR, "%s - Failed to create deferred context, deferred rendering is not possible, fallback to immediate rendering.", __FUNCTION__);
568 // make immediate context as default context if deferred context was not created
570 m_pContext = m_pImdContext;
572 if (m_featureLevel < D3D_FEATURE_LEVEL_9_3)
573 m_maxTextureSize = D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION;
574 else if (m_featureLevel < D3D_FEATURE_LEVEL_10_0)
575 m_maxTextureSize = D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION;
576 else if (m_featureLevel < D3D_FEATURE_LEVEL_11_0)
577 m_maxTextureSize = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
579 // 11_x and greater feature level. Limit this size to avoid memory overheads
580 m_maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION >> 1;
582 // use multi-thread protection on the device context to prevent deadlock issues that can sometimes happen
583 // when decoder call ID3D11VideoContext::GetDecoderBuffer or ID3D11VideoContext::ReleaseDecoderBuffer.
584 ID3D10Multithread *pMultiThreading = NULL;
585 if (SUCCEEDED(m_pD3DDev->QueryInterface(__uuidof(ID3D10Multithread), reinterpret_cast<void**>(&pMultiThreading))))
587 pMultiThreading->SetMultithreadProtected(true);
588 pMultiThreading->Release();
591 IDXGIDevice1* pDXGIDevice = NULL;
592 if (SUCCEEDED(m_pD3DDev->QueryInterface(__uuidof(IDXGIDevice1), reinterpret_cast<void**>(&pDXGIDevice))))
594 // Not sure the following actually does something but this exists in dx9 implementation
595 pDXGIDevice->SetGPUThreadPriority(7);
596 // Ensure that DXGI does not queue more than one frame at a time. This both reduces
597 // latency and ensures that the application will only render after each VSync
598 pDXGIDevice->SetMaximumFrameLatency(1);
599 SAFE_RELEASE(pDXGIDevice);
603 if (SUCCEEDED(m_pD3DDev->QueryInterface(__uuidof(ID3D11Debug), reinterpret_cast<void**>(&m_d3dDebug))))
605 ID3D11InfoQueue *d3dInfoQueue = nullptr;
606 if (SUCCEEDED(m_d3dDebug->QueryInterface(__uuidof(ID3D11InfoQueue), reinterpret_cast<void**>(&d3dInfoQueue))))
608 D3D11_MESSAGE_ID hide[] =
610 D3D11_MESSAGE_ID_GETVIDEOPROCESSORFILTERRANGE_UNSUPPORTED, // avoid GETVIDEOPROCESSORFILTERRANGE_UNSUPPORTED (dx bug)
611 D3D11_MESSAGE_ID_DEVICE_RSSETSCISSORRECTS_NEGATIVESCISSOR // avoid warning for some labels out of screen
612 // Add more message IDs here as needed
615 D3D11_INFO_QUEUE_FILTER filter;
616 ZeroMemory(&filter, sizeof(filter));
617 filter.DenyList.NumIDs = _countof(hide);
618 filter.DenyList.pIDList = hide;
619 d3dInfoQueue->AddStorageFilterEntries(&filter);
620 d3dInfoQueue->Release();
626 if (SUCCEEDED(m_adapter->GetDesc(&m_adapterDesc)))
628 CLog::Log(LOGDEBUG, "%s - on adapter %S (VendorId: %#x DeviceId: %#x) with feature level %#x.", __FUNCTION__,
629 m_adapterDesc.Description, m_adapterDesc.VendorId, m_adapterDesc.DeviceId, m_featureLevel);
631 m_RenderRenderer = StringUtils::Format("%S", m_adapterDesc.Description);
632 IDXGIFactory2* dxgiFactory2 = nullptr;
633 m_dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2));
634 m_RenderVersion = StringUtils::Format("DirectX %s (FL %d.%d)",
635 dxgiFactory2 != nullptr ? "11.1" : "11.0",
636 (m_featureLevel >> 12) & 0xF,
637 (m_featureLevel >> 8) & 0xF);
638 SAFE_RELEASE(dxgiFactory2);
642 unsigned int usage = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE;
643 if ( IsFormatSupport(DXGI_FORMAT_BC1_UNORM, usage)
644 && IsFormatSupport(DXGI_FORMAT_BC2_UNORM, usage)
645 && IsFormatSupport(DXGI_FORMAT_BC3_UNORM, usage))
646 m_renderCaps |= RENDER_CAPS_DXT;
648 // MSDN: At feature levels 9_1, 9_2 and 9_3, the display device supports the use of 2D textures with dimensions that are not powers of two under two conditions.
649 // First, only one MIP-map level for each texture can be created - we are using only 1 mip level)
650 // Second, no wrap sampler modes for textures are allowed - we are using clamp everywhere
651 // At feature levels 10_0, 10_1 and 11_0, the display device unconditionally supports the use of 2D textures with dimensions that are not powers of two.
652 // so, setup caps NPOT
653 m_renderCaps |= RENDER_CAPS_NPOT;
654 if ((m_renderCaps & RENDER_CAPS_DXT) != 0)
655 m_renderCaps |= RENDER_CAPS_DXT_NPOT;
657 // Temporary - allow limiting the caps to debug a texture problem
658 if (g_advancedSettings.m_RestrictCapsMask != 0)
659 m_renderCaps &= ~g_advancedSettings.m_RestrictCapsMask;
661 if (m_renderCaps & RENDER_CAPS_DXT)
662 CLog::Log(LOGDEBUG, "%s - RENDER_CAPS_DXT", __FUNCTION__);
663 if (m_renderCaps & RENDER_CAPS_NPOT)
664 CLog::Log(LOGDEBUG, "%s - RENDER_CAPS_NPOT", __FUNCTION__);
665 if (m_renderCaps & RENDER_CAPS_DXT_NPOT)
666 CLog::Log(LOGDEBUG, "%s - RENDER_CAPS_DXT_NPOT", __FUNCTION__);
668 /* All the following quirks need to be tested
669 // nVidia quirk: some NPOT DXT textures of the GUI display with corruption
670 // when using D3DPOOL_DEFAULT + D3DUSAGE_DYNAMIC textures (no other choice with D3D9Ex for example)
671 // most likely xbmc bug, but no hw to repro & fix properly.
672 // affects lots of hw generations - 6xxx, 7xxx, GT220, ION1
674 if (m_adapterDesc.VendorId == PCIV_nVidia)
676 CLog::Log(LOGDEBUG, __FUNCTION__" - nVidia workaround - disabling RENDER_CAPS_DXT_NPOT");
677 m_renderCaps &= ~RENDER_CAPS_DXT_NPOT;
680 // Intel quirk: DXT texture pitch must be > 64
681 // when using D3DPOOL_DEFAULT + D3DUSAGE_DYNAMIC textures (no other choice with D3D9Ex)
682 // DXT1: 32 pixels wide is the largest non-working texture width
683 // DXT3/5: 16 pixels wide ----------------------------------------
684 // Both equal to a pitch of 64. So far no Intel has DXT NPOT (including i3/i5/i7, so just go with the next higher POT.
686 if (m_adapterDesc.VendorId == PCIV_Intel)
688 CLog::Log(LOGDEBUG, __FUNCTION__" - Intel workaround - specifying minimum pitch for compressed textures.");
692 if (!CreateStates() || !InitGUIShader() || !CreateWindowSizeDependentResources())
695 m_bRenderCreated = true;
696 m_needNewDevice = false;
698 // tell any shared objects about our resurrection
699 for (std::vector<ID3DResource *>::iterator i = m_resources.begin(); i != m_resources.end(); ++i)
700 (*i)->OnCreateDevice();
707 bool CRenderSystemDX::CreateWindowSizeDependentResources()
709 if (m_resizeInProgress)
713 DXGI_SWAP_CHAIN_DESC scDesc = { 0 };
715 bool bNeedRecreate = false;
716 bool bNeedResize = false;
717 bool bHWStereoEnabled = RENDER_STEREO_MODE_HARDWAREBASED == g_graphicsContext.GetStereoMode();
721 m_pSwapChain->GetDesc(&scDesc);
722 bNeedResize = m_bResizeRequred || m_nBackBufferWidth != scDesc.BufferDesc.Width || m_nBackBufferHeight != scDesc.BufferDesc.Height;
729 DXGI_SWAP_CHAIN_DESC1 scDesc;
730 m_pSwapChain1->GetDesc1(&scDesc);
731 bNeedRecreate = (scDesc.Stereo && !bHWStereoEnabled) || (!scDesc.Stereo && bHWStereoEnabled);
734 if (!bNeedRecreate && !bNeedResize)
736 CheckInterlasedStereoView();
740 m_resizeInProgress = true;
742 CLog::Log(LOGDEBUG, "%s - (Re)Create window size (%dx%d) dependent resources.", __FUNCTION__, m_nBackBufferWidth, m_nBackBufferHeight);
744 bool bRestoreRTView = false;
746 ID3D11RenderTargetView* pRTView; ID3D11DepthStencilView* pDSView;
747 m_pContext->OMGetRenderTargets(1, &pRTView, &pDSView);
749 bRestoreRTView = NULL != pRTView || NULL != pDSView;
751 SAFE_RELEASE(pRTView);
752 SAFE_RELEASE(pDSView);
755 m_pContext->OMSetRenderTargets(0, NULL, NULL);
756 FinishCommandList(false);
758 SAFE_RELEASE(m_pRenderTargetView);
759 SAFE_RELEASE(m_depthStencilView);
760 SAFE_RELEASE(m_pRenderTargetViewRight);
761 SAFE_RELEASE(m_pShaderResourceViewRight);
762 SAFE_RELEASE(m_pTextureRight);
767 m_pSwapChain1->GetFullscreenState(&fullScreen, NULL);
769 m_pSwapChain1->SetFullscreenState(false, NULL);
771 CLog::Log(LOGDEBUG, "%s - Destroying swapchain in order to switch %s stereoscopic 3D.", __FUNCTION__, bHWStereoEnabled ? "to" : "from");
773 SAFE_RELEASE(m_pSwapChain);
774 SAFE_RELEASE(m_pSwapChain1);
775 m_pImdContext->Flush();
777 // flush command is asynchronous, so wait until destruction is completed
778 // otherwise it can cause problems with flip presentation model swap chains.
779 DXWait(m_pD3DDev, m_pImdContext);
784 CLog::Log(LOGDEBUG, "%s - Creating swapchain in %s mode.", __FUNCTION__, bHWStereoEnabled ? "Stereoscopic 3D" : "Mono");
787 IDXGIFactory2* dxgiFactory2 = NULL;
788 hr = m_dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2));
789 if (SUCCEEDED(hr) && dxgiFactory2)
791 // DirectX 11.1 or later
792 DXGI_SWAP_CHAIN_DESC1 scDesc1 = { 0 };
793 scDesc1.Width = m_nBackBufferWidth;
794 scDesc1.Height = m_nBackBufferHeight;
795 scDesc1.BufferCount = 2; // Use double buffering to minimize latency.
796 scDesc1.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
797 scDesc1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
798 scDesc1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
799 scDesc1.Stereo = bHWStereoEnabled;
800 scDesc1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
801 scDesc1.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
803 scDesc1.SampleDesc.Count = 1;
804 scDesc1.SampleDesc.Quality = 0;
806 DXGI_SWAP_CHAIN_FULLSCREEN_DESC scFSDesc = { 0 };
807 scFSDesc.ScanlineOrdering = m_interlaced ? DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST : DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
808 scFSDesc.Windowed = m_useWindowedDX;
810 hr = dxgiFactory2->CreateSwapChainForHwnd(m_pD3DDev, m_hFocusWnd, &scDesc1, &scFSDesc, NULL, &m_pSwapChain1);
814 m_pSwapChain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast<void**>(&m_pSwapChain));
815 // this hackish way to disable stereo in windowed mode:
816 // - restart presenting, 0 in sync interval discards current frame also
817 // - wait until new frame will be drawn
818 // sleep value possible depends on hardware m.b. need a setting in as.xml
819 if (m_useWindowedDX && !bHWStereoEnabled && m_bHWStereoEnabled)
821 DXGI_PRESENT_PARAMETERS presentParams = {};
822 presentParams.DirtyRectsCount = 0;
823 presentParams.pDirtyRects = NULL;
824 presentParams.pScrollRect = NULL;
825 m_pSwapChain1->Present1(0, DXGI_PRESENT_RESTART, &presentParams);
829 m_bHWStereoEnabled = bHWStereoEnabled;
831 dxgiFactory2->Release();
835 // DirectX 11.0 systems
836 scDesc.BufferCount = 2; // Use double buffering to minimize latency.
837 scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
838 scDesc.OutputWindow = m_hFocusWnd;
839 scDesc.Windowed = m_useWindowedDX;
840 scDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
841 scDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
843 scDesc.BufferDesc.Width = m_nBackBufferWidth;
844 scDesc.BufferDesc.Height = m_nBackBufferHeight;
845 scDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
846 scDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
847 scDesc.BufferDesc.ScanlineOrdering = m_interlaced ? DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST : DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
848 scDesc.SampleDesc.Count = 1;
849 scDesc.SampleDesc.Quality = 0;
851 hr = m_dxgiFactory->CreateSwapChain(m_pD3DDev, &scDesc, &m_pSwapChain);
856 CLog::Log(LOGERROR, "%s - Creating swap chain failed with error: %s.", __FUNCTION__, GetErrorDescription(hr).c_str());
857 m_bRenderCreated = false;
861 // tell DXGI to not interfere with application's handling of window mode changes
862 m_dxgiFactory->MakeWindowAssociation(m_hFocusWnd, DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER);
866 // resize swap chain buffers with preserving the existing buffer count and format.
867 hr = m_pSwapChain->ResizeBuffers(scDesc.BufferCount, m_nBackBufferWidth, m_nBackBufferHeight, scDesc.BufferDesc.Format, scDesc.Flags);
870 CLog::Log(LOGERROR, "%s - Failed to resize buffers (%s).", __FUNCTION__, GetErrorDescription(hr).c_str());
871 if (DXGI_ERROR_DEVICE_REMOVED == hr)
878 // Create a render target view
879 ID3D11Texture2D* pBackBuffer = nullptr;
880 hr = m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackBuffer));
883 CLog::Log(LOGERROR, "%s - Failed to get back buffer (%s).", __FUNCTION__, GetErrorDescription(hr).c_str());
887 // Create a view interface on the rendertarget to use on bind for mono or left eye view.
888 CD3D11_RENDER_TARGET_VIEW_DESC rtDesc(D3D11_RTV_DIMENSION_TEXTURE2DARRAY, DXGI_FORMAT_UNKNOWN, 0, 0, 1);
889 hr = m_pD3DDev->CreateRenderTargetView(pBackBuffer, &rtDesc, &m_pRenderTargetView);
892 CLog::Log(LOGERROR, "%s - Failed to create render target view (%s).", __FUNCTION__, GetErrorDescription(hr).c_str());
893 pBackBuffer->Release();
897 if (m_bHWStereoEnabled)
899 // Stereo swapchains have an arrayed resource, so create a second Render Target for the right eye buffer.
900 CD3D11_RENDER_TARGET_VIEW_DESC rtDesc(D3D11_RTV_DIMENSION_TEXTURE2DARRAY, DXGI_FORMAT_UNKNOWN, 0, 1, 1);
901 hr = m_pD3DDev->CreateRenderTargetView(pBackBuffer, &rtDesc, &m_pRenderTargetViewRight);
904 CLog::Log(LOGERROR, "%s - Failed to create right eye buffer (%s).", __FUNCTION__, GetErrorDescription(hr).c_str());
905 pBackBuffer->Release();
906 g_graphicsContext.SetStereoMode(RENDER_STEREO_MODE_OFF); // try fallback to mono
909 pBackBuffer->Release();
911 DXGI_FORMAT zFormat = DXGI_FORMAT_D16_UNORM;
912 if (IsFormatSupport(DXGI_FORMAT_D32_FLOAT, D3D11_FORMAT_SUPPORT_DEPTH_STENCIL)) zFormat = DXGI_FORMAT_D32_FLOAT;
913 else if (IsFormatSupport(DXGI_FORMAT_D24_UNORM_S8_UINT, D3D11_FORMAT_SUPPORT_DEPTH_STENCIL)) zFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;
914 else if (IsFormatSupport(DXGI_FORMAT_D16_UNORM, D3D11_FORMAT_SUPPORT_DEPTH_STENCIL)) zFormat = DXGI_FORMAT_D16_UNORM;
916 ID3D11Texture2D* depthStencilBuffer = NULL;
917 // Initialize the description of the depth buffer.
918 CD3D11_TEXTURE2D_DESC depthBufferDesc(zFormat, m_nBackBufferWidth, m_nBackBufferHeight, 1, 1, D3D11_BIND_DEPTH_STENCIL);
919 // Create the texture for the depth buffer using the filled out description.
920 hr = m_pD3DDev->CreateTexture2D(&depthBufferDesc, NULL, &depthStencilBuffer);
923 CLog::Log(LOGERROR, "%s - Failed to create depth stencil buffer (%s).", __FUNCTION__, GetErrorDescription(hr).c_str());
927 // Create the depth stencil view.
928 CD3D11_DEPTH_STENCIL_VIEW_DESC viewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
929 hr = m_pD3DDev->CreateDepthStencilView(depthStencilBuffer, &viewDesc, &m_depthStencilView);
930 depthStencilBuffer->Release();
934 CLog::Log(LOGERROR, "%s - Failed to create depth stencil view (%s).", __FUNCTION__, GetErrorDescription(hr).c_str());
938 if (m_viewPort.Height == 0 || m_viewPort.Width == 0)
940 CRect rect(0, 0, m_nBackBufferWidth, m_nBackBufferHeight);
944 // set camera to center of screen
945 CPoint camPoint = { m_nBackBufferWidth * 0.5f, m_nBackBufferHeight * 0.5f };
946 SetCameraPosition(camPoint, m_nBackBufferWidth, m_nBackBufferHeight);
948 CheckInterlasedStereoView();
951 m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, m_depthStencilView);
953 m_resizeInProgress = false;
954 m_bResizeRequred = false;
959 void CRenderSystemDX::CheckInterlasedStereoView(void)
961 RENDER_STEREO_MODE stereoMode = g_graphicsContext.GetStereoMode();
963 if ( m_pRenderTargetViewRight
964 && RENDER_STEREO_MODE_INTERLACED != stereoMode
965 && RENDER_STEREO_MODE_CHECKERBOARD != stereoMode
966 && RENDER_STEREO_MODE_HARDWAREBASED != stereoMode)
969 SAFE_RELEASE(m_pRenderTargetViewRight);
970 SAFE_RELEASE(m_pShaderResourceViewRight);
971 SAFE_RELEASE(m_pTextureRight);
974 if ( !m_pRenderTargetViewRight
975 && ( RENDER_STEREO_MODE_INTERLACED == stereoMode
976 || RENDER_STEREO_MODE_CHECKERBOARD == stereoMode))
978 // Create a second Render Target for the right eye buffer
980 CD3D11_TEXTURE2D_DESC texDesc(DXGI_FORMAT_B8G8R8A8_UNORM, m_nBackBufferWidth, m_nBackBufferHeight, 1, 1,
981 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE);
982 hr = m_pD3DDev->CreateTexture2D(&texDesc, NULL, &m_pTextureRight);
985 CD3D11_RENDER_TARGET_VIEW_DESC rtDesc(D3D11_RTV_DIMENSION_TEXTURE2D);
986 hr = m_pD3DDev->CreateRenderTargetView(m_pTextureRight, &rtDesc, &m_pRenderTargetViewRight);
990 CD3D11_SHADER_RESOURCE_VIEW_DESC srDesc(D3D11_SRV_DIMENSION_TEXTURE2D);
991 hr = m_pD3DDev->CreateShaderResourceView(m_pTextureRight, &srDesc, &m_pShaderResourceViewRight);
994 CLog::Log(LOGERROR, "%s - Failed to create right view shader resource.", __FUNCTION__);
997 CLog::Log(LOGERROR, "%s - Failed to create right view render target.", __FUNCTION__);
1002 SAFE_RELEASE(m_pShaderResourceViewRight);
1003 SAFE_RELEASE(m_pRenderTargetViewRight);
1004 SAFE_RELEASE(m_pTextureRight);
1006 CLog::Log(LOGERROR, "%s - Failed to create right eye buffer.", __FUNCTION__);
1007 g_graphicsContext.SetStereoMode(RENDER_STEREO_MODE_OFF); // try fallback to mono
1012 bool CRenderSystemDX::CreateStates()
1017 SAFE_RELEASE(m_depthStencilState);
1018 SAFE_RELEASE(m_BlendEnableState);
1019 SAFE_RELEASE(m_BlendDisableState);
1021 // Initialize the description of the stencil state.
1022 D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
1023 ZeroMemory(&depthStencilDesc, sizeof(D3D11_DEPTH_STENCIL_DESC));
1025 // Set up the description of the stencil state.
1026 depthStencilDesc.DepthEnable = false;
1027 depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
1028 depthStencilDesc.DepthFunc = D3D11_COMPARISON_NEVER;
1029 depthStencilDesc.StencilEnable = false;
1030 depthStencilDesc.StencilReadMask = 0xFF;
1031 depthStencilDesc.StencilWriteMask = 0xFF;
1033 // Stencil operations if pixel is front-facing.
1034 depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
1035 depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
1036 depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
1037 depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
1039 // Stencil operations if pixel is back-facing.
1040 depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
1041 depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
1042 depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
1043 depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
1045 // Create the depth stencil state.
1046 HRESULT hr = m_pD3DDev->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilState);
1050 // Set the depth stencil state.
1051 m_pContext->OMSetDepthStencilState(m_depthStencilState, 0);
1053 D3D11_RASTERIZER_DESC rasterizerState;
1054 rasterizerState.CullMode = D3D11_CULL_NONE;
1055 rasterizerState.FillMode = D3D11_FILL_SOLID;// DEBUG - D3D11_FILL_WIREFRAME
1056 rasterizerState.FrontCounterClockwise = false;
1057 rasterizerState.DepthBias = 0;
1058 rasterizerState.DepthBiasClamp = 0.0f;
1059 rasterizerState.DepthClipEnable = true;
1060 rasterizerState.SlopeScaledDepthBias = 0.0f;
1061 rasterizerState.ScissorEnable = false;
1062 rasterizerState.MultisampleEnable = false;
1063 rasterizerState.AntialiasedLineEnable = false;
1065 if (FAILED(m_pD3DDev->CreateRasterizerState(&rasterizerState, &m_RSScissorDisable)))
1068 rasterizerState.ScissorEnable = true;
1069 if (FAILED(m_pD3DDev->CreateRasterizerState(&rasterizerState, &m_RSScissorEnable)))
1072 m_pContext->RSSetState(m_RSScissorDisable); // by default
1074 D3D11_BLEND_DESC blendState = { 0 };
1075 ZeroMemory(&blendState, sizeof(D3D11_BLEND_DESC));
1076 blendState.RenderTarget[0].BlendEnable = true;
1077 blendState.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; // D3D11_BLEND_SRC_ALPHA;
1078 blendState.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; // D3D11_BLEND_INV_SRC_ALPHA;
1079 blendState.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
1080 blendState.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
1081 blendState.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
1082 blendState.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
1083 blendState.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
1085 m_pD3DDev->CreateBlendState(&blendState, &m_BlendEnableState);
1087 blendState.RenderTarget[0].BlendEnable = false;
1088 m_pD3DDev->CreateBlendState(&blendState, &m_BlendDisableState);
1091 m_pContext->OMSetBlendState(m_BlendEnableState, nullptr, 0xFFFFFFFF);
1092 m_BlendEnabled = true;
1097 bool CRenderSystemDX::PresentRenderImpl(const CDirtyRegionList &dirty)
1101 if (!m_bRenderCreated)
1104 if (m_nDeviceStatus != S_OK)
1106 // if DXGI_STATUS_OCCLUDED occurred we just clear command queue and return
1107 if (m_nDeviceStatus == DXGI_STATUS_OCCLUDED)
1108 FinishCommandList(false);
1112 if ( m_stereoMode == RENDER_STEREO_MODE_INTERLACED
1113 || m_stereoMode == RENDER_STEREO_MODE_CHECKERBOARD)
1115 // all views prepared, let's merge them before present
1116 m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, m_depthStencilView);
1117 CRect destRect = { 0.0f, 0.0f, float(m_nBackBufferWidth), float(m_nBackBufferHeight) };
1118 SHADER_METHOD method = RENDER_STEREO_MODE_INTERLACED == m_stereoMode
1119 ? SHADER_METHOD_RENDER_STEREO_INTERLACED_RIGHT
1120 : SHADER_METHOD_RENDER_STEREO_CHECKERBOARD_RIGHT;
1121 SetAlphaBlendEnable(true);
1122 CD3DTexture::DrawQuad(destRect, 0, 1, &m_pShaderResourceViewRight, NULL, method);
1123 CD3DHelper::PSClearShaderResources(m_pContext);
1126 FinishCommandList();
1130 // will use optimized present with dirty regions.
1131 DXGI_PRESENT_PARAMETERS presentParams = {};
1132 presentParams.DirtyRectsCount = 0;
1133 presentParams.pDirtyRects = NULL;
1134 presentParams.pScrollRect = NULL;
1135 hr = m_pSwapChain1->Present1((m_bVSync ? 1 : 0), 0, &presentParams);
1138 hr = m_pSwapChain->Present((m_bVSync ? 1 : 0), 0);
1140 if (DXGI_ERROR_DEVICE_REMOVED == hr)
1142 CLog::Log(LOGDEBUG, "%s - device removed", __FUNCTION__);
1146 if (DXGI_ERROR_INVALID_CALL == hr)
1148 m_bResizeRequred = true;
1149 if (CreateWindowSizeDependentResources())
1155 CLog::Log(LOGDEBUG, "%s - Present failed. %s", __FUNCTION__, GetErrorDescription(hr).c_str());
1159 // after present swapchain unbinds RT view from immediate context, need to restore it because it can be used by something else
1160 if (m_pContext == m_pImdContext)
1161 m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, m_depthStencilView);
1166 bool CRenderSystemDX::BeginRender()
1168 if (!m_bRenderCreated)
1171 HRESULT oldStatus = m_nDeviceStatus;
1174 DXGI_PRESENT_PARAMETERS presentParams = {};
1175 presentParams.DirtyRectsCount = 0;
1176 presentParams.pDirtyRects = NULL;
1177 presentParams.pScrollRect = NULL;
1178 m_nDeviceStatus = m_pSwapChain1->Present1(0, DXGI_PRESENT_TEST, &presentParams);
1182 m_nDeviceStatus = m_pSwapChain->Present(0, DXGI_PRESENT_TEST);
1185 // handling of return values.
1186 switch (m_nDeviceStatus)
1188 case DXGI_ERROR_DEVICE_REMOVED: // GPU has been physically removed from the system, or a driver upgrade occurred.
1189 CLog::Log(LOGERROR, "DXGI_ERROR_DEVICE_REMOVED");
1190 m_needNewDevice = true;
1192 case DXGI_ERROR_DEVICE_RESET: // This is an run-time issue that should be investigated and fixed.
1193 CLog::Log(LOGERROR, "DXGI_ERROR_DEVICE_RESET");
1194 m_nDeviceStatus = DXGI_ERROR_DEVICE_REMOVED;
1195 m_needNewDevice = true;
1197 case DXGI_ERROR_INVALID_CALL: // application provided invalid parameter data. Try to return after resize buffers
1198 CLog::Log(LOGERROR, "DXGI_ERROR_INVALID_CALL");
1199 m_bResizeRequred = true;
1200 if (CreateWindowSizeDependentResources())
1201 m_nDeviceStatus = S_OK;
1203 case DXGI_STATUS_OCCLUDED: // decide what we should do when windows content is not visible
1204 // do not spam to log file
1205 if (m_nDeviceStatus != oldStatus)
1206 CLog::Log(LOGDEBUG, "DXGI_STATUS_OCCLUDED");
1207 // Status OCCLUDED is not an error and not handled by FAILED macro,
1208 // but if it occurs we should not render anything, this status will be accounted on present stage
1211 if (FAILED(m_nDeviceStatus))
1213 if (DXGI_ERROR_DEVICE_REMOVED == m_nDeviceStatus)
1221 m_pContext->OMSetRenderTargets(1, &m_pRenderTargetView, m_depthStencilView);
1227 bool CRenderSystemDX::EndRender()
1231 if (!m_bRenderCreated)
1234 if(m_nDeviceStatus != S_OK)
1240 bool CRenderSystemDX::ClearBuffers(color_t color)
1242 if (!m_bRenderCreated || m_resizeInProgress)
1246 CD3DHelper::XMStoreColor(fColor, color);
1247 ID3D11RenderTargetView* pRTView = m_pRenderTargetView;
1249 if ( m_stereoMode != RENDER_STEREO_MODE_OFF
1250 && m_stereoMode != RENDER_STEREO_MODE_MONO)
1252 // if stereo anaglyph/tab/sbs, data was cleared when left view was rendererd
1253 if (m_stereoView == RENDER_STEREO_VIEW_RIGHT)
1255 // execute command's queue
1256 FinishCommandList();
1258 // do not clear RT for anaglyph modes
1259 if ( m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA
1260 || m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN
1261 || m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_YELLOW_BLUE)
1265 // for interlaced/checkerboard/hw clear right view
1266 else if (m_pRenderTargetViewRight)
1267 pRTView = m_pRenderTargetViewRight;
1269 // for hw stereo clear depth view also
1270 if (m_stereoMode == RENDER_STEREO_MODE_HARDWAREBASED)
1271 m_pContext->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0, 0);
1275 if (pRTView == nullptr)
1278 CRect clRect(0, 0, m_nBackBufferWidth, m_nBackBufferHeight);
1280 // Unlike Direct3D 9, D3D11 ClearRenderTargetView always clears full extent of the resource view.
1281 // Viewport and scissor settings are not applied. So clear RT by drawing full sized rect with clear color
1282 if (m_ScissorsEnabled && m_scissor != clRect)
1284 bool alphaEnabled = m_BlendEnabled;
1286 SetAlphaBlendEnable(false);
1288 CGUITextureD3D::DrawQuad(clRect, color);
1291 SetAlphaBlendEnable(true);
1294 m_pContext->ClearRenderTargetView(pRTView, fColor);
1296 m_pContext->ClearDepthStencilView(m_depthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0, 0);
1300 bool CRenderSystemDX::IsExtSupported(const char* extension)
1305 bool CRenderSystemDX::PresentRender(const CDirtyRegionList &dirty)
1307 if (!m_bRenderCreated || m_resizeInProgress)
1310 bool result = PresentRenderImpl(dirty);
1315 void CRenderSystemDX::SetVSync(bool enable)
1320 void CRenderSystemDX::CaptureStateBlock()
1322 if (!m_bRenderCreated)
1326 void CRenderSystemDX::ApplyStateBlock()
1328 if (!m_bRenderCreated)
1331 m_pContext->RSSetState(m_ScissorsEnabled ? m_RSScissorEnable : m_RSScissorDisable);
1332 m_pContext->OMSetDepthStencilState(m_depthStencilState, 0);
1333 float factors[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1334 m_pContext->OMSetBlendState(m_BlendEnabled ? m_BlendEnableState : m_BlendDisableState, factors, 0xFFFFFFFF);
1336 m_pGUIShader->ApplyStateBlock();
1339 void CRenderSystemDX::SetCameraPosition(const CPoint &camera, int screenWidth, int screenHeight, float stereoFactor)
1341 if (!m_bRenderCreated)
1344 // grab the viewport dimensions and location
1345 float w = m_viewPort.Width*0.5f;
1346 float h = m_viewPort.Height*0.5f;
1348 XMFLOAT2 offset = XMFLOAT2(camera.x - screenWidth*0.5f, camera.y - screenHeight*0.5f);
1350 // world view. Until this is moved onto the GPU (via a vertex shader for instance), we set it to the identity here.
1351 m_pGUIShader->SetWorld(XMMatrixIdentity());
1353 // Initialize the view matrix
1354 // camera view. Multiply the Y coord by -1 then translate so that everything is relative to the camera
1356 XMMATRIX flipY, translate;
1357 flipY = XMMatrixScaling(1.0, -1.0f, 1.0f);
1358 translate = XMMatrixTranslation(-(w + offset.x - stereoFactor), -(h + offset.y), 2 * h);
1359 m_pGUIShader->SetView(XMMatrixMultiply(translate, flipY));
1361 // projection onto screen space
1362 m_pGUIShader->SetProjection(XMMatrixPerspectiveOffCenterLH((-w - offset.x)*0.5f, (w - offset.x)*0.5f, (-h + offset.y)*0.5f, (h + offset.y)*0.5f, h, 100 * h));
1365 void CRenderSystemDX::Project(float &x, float &y, float &z)
1367 if (!m_bRenderCreated)
1370 m_pGUIShader->Project(x, y, z);
1373 bool CRenderSystemDX::TestRender()
1376 static unsigned int lastTime = 0;
1377 static float delta = 0;
1379 unsigned int thisTime = XbmcThreads::SystemClockMillis();
1381 if(thisTime - lastTime > 10)
1383 lastTime = thisTime;
1387 CLog::Log(LOGINFO, "Delta = %d", delta);
1389 if(delta > m_nBackBufferWidth)
1392 LPDIRECT3DVERTEXBUFFER9 pVB = NULL;
1394 // A structure for our custom vertex type
1397 FLOAT x, y, z, rhw; // The transformed position for the vertex
1398 DWORD color; // The vertex color
1401 // Our custom FVF, which describes our custom vertex structure
1402 #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)
1404 // Initialize three vertices for rendering a triangle
1405 CUSTOMVERTEX vertices[] =
1407 { delta + 100.0f, 50.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
1408 { delta+200.0f, 250.0f, 0.5f, 1.0f, 0xff00ff00, },
1409 { delta, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
1412 // Create the vertex buffer. Here we are allocating enough memory
1413 // (from the default pool) to hold all our 3 custom vertices. We also
1414 // specify the FVF, so the vertex buffer knows what data it contains.
1415 if( FAILED( m_pD3DDevice->CreateVertexBuffer( 3 * sizeof( CUSTOMVERTEX ),
1416 0, D3DFVF_CUSTOMVERTEX,
1417 D3DPOOL_DEFAULT, &pVB, NULL ) ) )
1422 // Now we fill the vertex buffer. To do this, we need to Lock() the VB to
1423 // gain access to the vertices. This mechanism is required becuase vertex
1424 // buffers may be in device memory.
1426 if( FAILED( pVB->Lock( 0, sizeof( vertices ), ( void** )&pVertices, 0 ) ) )
1428 memcpy( pVertices, vertices, sizeof( vertices ) );
1431 m_pD3DDevice->SetStreamSource( 0, pVB, 0, sizeof( CUSTOMVERTEX ) );
1432 m_pD3DDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
1433 m_pD3DDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );
1440 void CRenderSystemDX::ApplyHardwareTransform(const TransformMatrix &finalMatrix)
1442 if (!m_bRenderCreated)
1446 void CRenderSystemDX::RestoreHardwareTransform()
1448 if (!m_bRenderCreated)
1452 void CRenderSystemDX::GetViewPort(CRect& viewPort)
1454 if (!m_bRenderCreated)
1457 viewPort.x1 = m_viewPort.TopLeftX;
1458 viewPort.y1 = m_viewPort.TopLeftY;
1459 viewPort.x2 = m_viewPort.TopLeftX + m_viewPort.Width;
1460 viewPort.y2 = m_viewPort.TopLeftY + m_viewPort.Height;
1463 void CRenderSystemDX::SetViewPort(CRect& viewPort)
1465 if (!m_bRenderCreated)
1468 m_viewPort.MinDepth = 0.0f;
1469 m_viewPort.MaxDepth = 1.0f;
1470 m_viewPort.TopLeftX = viewPort.x1;
1471 m_viewPort.TopLeftY = viewPort.y1;
1472 m_viewPort.Width = viewPort.x2 - viewPort.x1;
1473 m_viewPort.Height = viewPort.y2 - viewPort.y1;
1475 m_pContext->RSSetViewports(1, &m_viewPort);
1476 m_pGUIShader->SetViewPort(m_viewPort);
1479 void CRenderSystemDX::RestoreViewPort()
1481 if (!m_bRenderCreated)
1484 m_pContext->RSSetViewports(1, &m_viewPort);
1485 m_pGUIShader->SetViewPort(m_viewPort);
1488 bool CRenderSystemDX::ScissorsCanEffectClipping()
1490 if (!m_bRenderCreated)
1493 return m_pGUIShader != NULL && m_pGUIShader->HardwareClipIsPossible();
1496 CRect CRenderSystemDX::ClipRectToScissorRect(const CRect &rect)
1498 if (!m_bRenderCreated)
1501 float xFactor = m_pGUIShader->GetClipXFactor();
1502 float xOffset = m_pGUIShader->GetClipXOffset();
1503 float yFactor = m_pGUIShader->GetClipYFactor();
1504 float yOffset = m_pGUIShader->GetClipYOffset();
1506 return CRect(rect.x1 * xFactor + xOffset,
1507 rect.y1 * yFactor + yOffset,
1508 rect.x2 * xFactor + xOffset,
1509 rect.y2 * yFactor + yOffset);
1512 void CRenderSystemDX::SetScissors(const CRect& rect)
1514 if (!m_bRenderCreated)
1518 CD3D11_RECT scissor(MathUtils::round_int(rect.x1)
1519 , MathUtils::round_int(rect.y1)
1520 , MathUtils::round_int(rect.x2)
1521 , MathUtils::round_int(rect.y2));
1523 m_pContext->RSSetScissorRects(1, &scissor);
1524 m_pContext->RSSetState(m_RSScissorEnable);
1525 m_ScissorsEnabled = true;
1528 void CRenderSystemDX::ResetScissors()
1530 if (!m_bRenderCreated)
1533 m_scissor.SetRect(0, 0, m_nBackBufferWidth, m_nBackBufferHeight);
1535 m_pContext->RSSetState(m_RSScissorDisable);
1536 m_ScissorsEnabled = false;
1539 void CRenderSystemDX::Register(ID3DResource *resource)
1541 CSingleLock lock(m_resourceSection);
1542 m_resources.push_back(resource);
1545 void CRenderSystemDX::Unregister(ID3DResource* resource)
1547 CSingleLock lock(m_resourceSection);
1548 std::vector<ID3DResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource);
1549 if (i != m_resources.end())
1550 m_resources.erase(i);
1553 std::string CRenderSystemDX::GetErrorDescription(HRESULT hr)
1556 DXGetErrorDescription(hr, buff, 1024);
1557 std::wstring error(DXGetErrorString(hr));
1558 std::wstring descr(buff);
1559 return StringUtils::Format("%X - %ls (%ls)", hr, error.c_str(), descr.c_str());
1562 void CRenderSystemDX::SetStereoMode(RENDER_STEREO_MODE mode, RENDER_STEREO_VIEW view)
1564 CRenderSystemBase::SetStereoMode(mode, view);
1566 if (!m_bRenderCreated)
1569 UINT writeMask = D3D11_COLOR_WRITE_ENABLE_ALL;
1570 if(m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN)
1572 if(m_stereoView == RENDER_STEREO_VIEW_LEFT)
1573 writeMask = D3D11_COLOR_WRITE_ENABLE_RED;
1574 else if(m_stereoView == RENDER_STEREO_VIEW_RIGHT)
1575 writeMask = D3D11_COLOR_WRITE_ENABLE_BLUE | D3D11_COLOR_WRITE_ENABLE_GREEN;
1577 if(m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA)
1579 if(m_stereoView == RENDER_STEREO_VIEW_LEFT)
1580 writeMask = D3D11_COLOR_WRITE_ENABLE_GREEN;
1581 else if(m_stereoView == RENDER_STEREO_VIEW_RIGHT)
1582 writeMask = D3D11_COLOR_WRITE_ENABLE_BLUE | D3D11_COLOR_WRITE_ENABLE_RED;
1584 if (m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_YELLOW_BLUE)
1586 if (m_stereoView == RENDER_STEREO_VIEW_LEFT)
1587 writeMask = D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN;
1588 else if (m_stereoView == RENDER_STEREO_VIEW_RIGHT)
1589 writeMask = D3D11_COLOR_WRITE_ENABLE_BLUE;
1591 if ( RENDER_STEREO_MODE_INTERLACED == m_stereoMode
1592 || RENDER_STEREO_MODE_CHECKERBOARD == m_stereoMode
1593 || RENDER_STEREO_MODE_HARDWAREBASED == m_stereoMode)
1595 if (m_stereoView == RENDER_STEREO_VIEW_RIGHT)
1597 // render right eye view to right render target
1598 m_pContext->OMSetRenderTargets(1, &m_pRenderTargetViewRight, m_depthStencilView);
1602 D3D11_BLEND_DESC desc;
1603 m_BlendEnableState->GetDesc(&desc);
1604 // update blend state
1605 if (desc.RenderTarget[0].RenderTargetWriteMask != writeMask)
1607 SAFE_RELEASE(m_BlendDisableState);
1608 SAFE_RELEASE(m_BlendEnableState);
1610 desc.RenderTarget[0].RenderTargetWriteMask = writeMask;
1611 m_pD3DDev->CreateBlendState(&desc, &m_BlendEnableState);
1613 desc.RenderTarget[0].BlendEnable = false;
1614 m_pD3DDev->CreateBlendState(&desc, &m_BlendDisableState);
1616 float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f };
1617 m_pContext->OMSetBlendState(m_BlendEnabled ? m_BlendEnableState : m_BlendDisableState, blendFactors, 0xFFFFFFFF);
1621 bool CRenderSystemDX::SupportsStereo(RENDER_STEREO_MODE mode) const
1623 bool isHWStereoSupport = false;
1624 IDXGIFactory2* dxgiFactory2 = NULL;
1625 if (SUCCEEDED(m_dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast<void**>(&dxgiFactory2))))
1627 isHWStereoSupport = dxgiFactory2 && dxgiFactory2->IsWindowedStereoEnabled();
1629 SAFE_RELEASE(dxgiFactory2);
1633 case RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN:
1634 case RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA:
1635 case RENDER_STEREO_MODE_ANAGLYPH_YELLOW_BLUE:
1636 case RENDER_STEREO_MODE_INTERLACED:
1637 case RENDER_STEREO_MODE_CHECKERBOARD:
1639 case RENDER_STEREO_MODE_HARDWAREBASED:
1640 return isHWStereoSupport;
1642 return CRenderSystemBase::SupportsStereo(mode);
1646 void CRenderSystemDX::FlushGPU()
1648 if (!m_bRenderCreated)
1651 FinishCommandList();
1652 m_pImdContext->Flush();
1655 bool CRenderSystemDX::InitGUIShader()
1660 SAFE_DELETE(m_pGUIShader);
1661 m_pGUIShader = new CGUIShaderDX();
1662 if (!m_pGUIShader->Initialize())
1664 CLog::Log(LOGERROR, __FUNCTION__ " - Failed to initialize GUI shader.");
1668 m_pGUIShader->ApplyStateBlock();
1673 void CRenderSystemDX::SetAlphaBlendEnable(bool enable)
1675 if (!m_bRenderCreated)
1678 float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f };
1679 m_pContext->OMSetBlendState(enable ? m_BlendEnableState : m_BlendDisableState, 0, 0xFFFFFFFF);
1680 m_BlendEnabled = enable;
1683 void CRenderSystemDX::FinishCommandList(bool bExecute /*= true*/)
1685 if (m_pImdContext == m_pContext)
1688 ID3D11CommandList* pCommandList = NULL;
1689 if (FAILED(m_pContext->FinishCommandList(true, &pCommandList)))
1691 CLog::Log(LOGERROR, "%s - Failed to finish command queue.", __FUNCTION__);
1696 m_pImdContext->ExecuteCommandList(pCommandList, false);
1698 SAFE_RELEASE(pCommandList);