diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/rendering/dx/RenderSystemDX.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | xbmc/rendering/dx/RenderSystemDX.cpp | 706 |
1 files changed, 706 insertions, 0 deletions
diff --git a/xbmc/rendering/dx/RenderSystemDX.cpp b/xbmc/rendering/dx/RenderSystemDX.cpp new file mode 100644 index 0000000..cb1b0d5 --- /dev/null +++ b/xbmc/rendering/dx/RenderSystemDX.cpp @@ -0,0 +1,706 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ +#include "RenderSystemDX.h" + +#include "application/Application.h" + +#include <mutex> +#if defined(TARGET_WINDOWS_DESKTOP) +#include "cores/RetroPlayer/process/windows/RPProcessInfoWin.h" +#include "cores/RetroPlayer/rendering/VideoRenderers/RPWinRenderer.h" +#endif +#include "cores/VideoPlayer/DVDCodecs/DVDFactoryCodec.h" +#include "cores/VideoPlayer/DVDCodecs/Video/DXVA.h" +#if defined(TARGET_WINDOWS_STORE) +#include "cores/VideoPlayer/Process/windows/ProcessInfoWin10.h" +#else +#include "cores/VideoPlayer/Process/windows/ProcessInfoWin.h" +#endif +#include "cores/VideoPlayer/VideoRenderers/RenderFactory.h" +#include "cores/VideoPlayer/VideoRenderers/WinRenderer.h" +#include "cores/VideoPlayer/VideoRenderers/RenderManager.h" +#include "guilib/D3DResource.h" +#include "guilib/GUIShaderDX.h" +#include "guilib/GUITextureD3D.h" +#include "guilib/GUIWindowManager.h" +#include "utils/MathUtils.h" +#include "utils/log.h" + +#include <DirectXPackedVector.h> + +extern "C" { +#include <libavutil/pixfmt.h> +} + +using namespace KODI; +using namespace DirectX; +using namespace DirectX::PackedVector; +using namespace Microsoft::WRL; +using namespace std::chrono_literals; + +CRenderSystemDX::CRenderSystemDX() : CRenderSystemBase() + , m_interlaced(false) +{ + m_bVSync = true; + + memset(&m_viewPort, 0, sizeof m_viewPort); + memset(&m_scissor, 0, sizeof m_scissor); +} + +CRenderSystemDX::~CRenderSystemDX() = default; + +bool CRenderSystemDX::InitRenderSystem() +{ + m_bVSync = true; + + // check various device capabilities + CheckDeviceCaps(); + + if (!CreateStates() || !InitGUIShader()) + return false; + + m_bRenderCreated = true; + m_deviceResources->RegisterDeviceNotify(this); + + // register platform dependent objects +#if defined(TARGET_WINDOWS_STORE) + VIDEOPLAYER::CProcessInfoWin10::Register(); +#else + VIDEOPLAYER::CProcessInfoWin::Register(); +#endif + CDVDFactoryCodec::ClearHWAccels(); + DXVA::CDecoder::Register(); + VIDEOPLAYER::CRendererFactory::ClearRenderer(); + CWinRenderer::Register(); +#if defined(TARGET_WINDOWS_DESKTOP) + RETRO::CRPProcessInfoWin::Register(); + RETRO::CRPProcessInfoWin::RegisterRendererFactory(new RETRO::CWinRendererFactory); +#endif + m_viewPort = m_deviceResources->GetScreenViewport(); + RestoreViewPort(); + + auto outputSize = m_deviceResources->GetOutputSize(); + // set camera to center of screen + CPoint camPoint = { outputSize.Width * 0.5f, outputSize.Height * 0.5f }; + SetCameraPosition(camPoint, outputSize.Width, outputSize.Height); + + DXGI_ADAPTER_DESC AIdentifier = {}; + m_deviceResources->GetAdapterDesc(&AIdentifier); + m_RenderRenderer = KODI::PLATFORM::WINDOWS::FromW(AIdentifier.Description); + uint32_t version = 0; + for (uint32_t decimal = m_deviceResources->GetDeviceFeatureLevel() >> 8, round = 0; decimal > 0; decimal >>= 4, ++round) + version += (decimal % 16) * std::pow(10, round); + m_RenderVersion = StringUtils::Format("{:.1f}", static_cast<float>(version) / 10.0f); + + CGUITextureD3D::Register(); + + return true; +} + +void CRenderSystemDX::OnResize() +{ + if (!m_bRenderCreated) + return; + + auto outputSize = m_deviceResources->GetOutputSize(); + + // set camera to center of screen + CPoint camPoint = { outputSize.Width * 0.5f, outputSize.Height * 0.5f }; + SetCameraPosition(camPoint, outputSize.Width, outputSize.Height); + + CheckInterlacedStereoView(); +} + +bool CRenderSystemDX::IsFormatSupport(DXGI_FORMAT format, unsigned int usage) const +{ + ComPtr<ID3D11Device1> pD3DDev = m_deviceResources->GetD3DDevice(); + UINT supported; + pD3DDev->CheckFormatSupport(format, &supported); + return (supported & usage) != 0; +} + +bool CRenderSystemDX::DestroyRenderSystem() +{ + std::unique_lock<CCriticalSection> lock(m_resourceSection); + + if (m_pGUIShader) + { + m_pGUIShader->End(); + delete m_pGUIShader; + m_pGUIShader = nullptr; + } + m_rightEyeTex.Release(); + m_BlendEnableState = nullptr; + m_BlendDisableState = nullptr; + m_RSScissorDisable = nullptr; + m_RSScissorEnable = nullptr; + m_depthStencilState = nullptr; + + return true; +} + +void CRenderSystemDX::CheckInterlacedStereoView() +{ + RENDER_STEREO_MODE stereoMode = CServiceBroker::GetWinSystem()->GetGfxContext().GetStereoMode(); + + if ( m_rightEyeTex.Get() + && RENDER_STEREO_MODE_INTERLACED != stereoMode + && RENDER_STEREO_MODE_CHECKERBOARD != stereoMode) + { + m_rightEyeTex.Release(); + } + + if ( !m_rightEyeTex.Get() + && ( RENDER_STEREO_MODE_INTERLACED == stereoMode + || RENDER_STEREO_MODE_CHECKERBOARD == stereoMode)) + { + const auto outputSize = m_deviceResources->GetOutputSize(); + DXGI_FORMAT texFormat = m_deviceResources->GetBackBuffer().GetFormat(); + if (!m_rightEyeTex.Create(outputSize.Width, outputSize.Height, 1, D3D11_USAGE_DEFAULT, texFormat)) + { + CLog::Log(LOGERROR, "{} - Failed to create right eye buffer.", __FUNCTION__); + CServiceBroker::GetWinSystem()->GetGfxContext().SetStereoMode(RENDER_STEREO_MODE_SPLIT_HORIZONTAL); // try fallback to split horizontal + } + else + m_deviceResources->Unregister(&m_rightEyeTex); // we will handle its health + } +} + +bool CRenderSystemDX::CreateStates() +{ + auto m_pD3DDev = m_deviceResources->GetD3DDevice(); + auto m_pContext = m_deviceResources->GetD3DContext(); + + if (!m_pD3DDev) + return false; + + m_BlendEnableState = nullptr; + m_BlendDisableState = nullptr; + + // Initialize the description of the stencil state. + D3D11_DEPTH_STENCIL_DESC depthStencilDesc = {}; + + // Set up the description of the stencil state. + depthStencilDesc.DepthEnable = false; + depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D11_COMPARISON_NEVER; + depthStencilDesc.StencilEnable = false; + depthStencilDesc.StencilReadMask = 0xFF; + depthStencilDesc.StencilWriteMask = 0xFF; + + // Stencil operations if pixel is front-facing. + depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; + depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + // Stencil operations if pixel is back-facing. + depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR; + depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; + depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + + // Create the depth stencil state. + HRESULT hr = m_pD3DDev->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilState); + if(FAILED(hr)) + return false; + + // Set the depth stencil state. + m_pContext->OMSetDepthStencilState(m_depthStencilState.Get(), 0); + + D3D11_RASTERIZER_DESC rasterizerState; + rasterizerState.CullMode = D3D11_CULL_NONE; + rasterizerState.FillMode = D3D11_FILL_SOLID;// DEBUG - D3D11_FILL_WIREFRAME + rasterizerState.FrontCounterClockwise = false; + rasterizerState.DepthBias = 0; + rasterizerState.DepthBiasClamp = 0.0f; + rasterizerState.DepthClipEnable = true; + rasterizerState.SlopeScaledDepthBias = 0.0f; + rasterizerState.ScissorEnable = false; + rasterizerState.MultisampleEnable = false; + rasterizerState.AntialiasedLineEnable = false; + + if (FAILED(m_pD3DDev->CreateRasterizerState(&rasterizerState, &m_RSScissorDisable))) + return false; + + rasterizerState.ScissorEnable = true; + if (FAILED(m_pD3DDev->CreateRasterizerState(&rasterizerState, &m_RSScissorEnable))) + return false; + + m_pContext->RSSetState(m_RSScissorDisable.Get()); // by default + + D3D11_BLEND_DESC blendState = {}; + blendState.RenderTarget[0].BlendEnable = true; + blendState.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; // D3D11_BLEND_SRC_ALPHA; + blendState.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; // D3D11_BLEND_INV_SRC_ALPHA; + blendState.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + blendState.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blendState.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; + blendState.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + blendState.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + m_pD3DDev->CreateBlendState(&blendState, &m_BlendEnableState); + + blendState.RenderTarget[0].BlendEnable = false; + m_pD3DDev->CreateBlendState(&blendState, &m_BlendDisableState); + + // by default + m_pContext->OMSetBlendState(m_BlendEnableState.Get(), nullptr, 0xFFFFFFFF); + m_BlendEnabled = true; + + return true; +} + +void CRenderSystemDX::PresentRender(bool rendered, bool videoLayer) +{ + if (!m_bRenderCreated) + return; + + if ( rendered + && ( m_stereoMode == RENDER_STEREO_MODE_INTERLACED + || m_stereoMode == RENDER_STEREO_MODE_CHECKERBOARD)) + { + auto m_pContext = m_deviceResources->GetD3DContext(); + + // all views prepared, let's merge them before present + m_pContext->OMSetRenderTargets(1, m_deviceResources->GetBackBuffer().GetAddressOfRTV(), m_deviceResources->GetDSV()); + + auto outputSize = m_deviceResources->GetOutputSize(); + CRect destRect = { 0.0f, 0.0f, float(outputSize.Width), float(outputSize.Height) }; + + SHADER_METHOD method = RENDER_STEREO_MODE_INTERLACED == m_stereoMode + ? SHADER_METHOD_RENDER_STEREO_INTERLACED_RIGHT + : SHADER_METHOD_RENDER_STEREO_CHECKERBOARD_RIGHT; + SetAlphaBlendEnable(true); + CD3DTexture::DrawQuad(destRect, 0, &m_rightEyeTex, nullptr, method); + CD3DHelper::PSClearShaderResources(m_pContext); + } + + // time for decoder that may require the context + { + std::unique_lock<CCriticalSection> lock(m_decoderSection); + XbmcThreads::EndTime<> timer; + timer.Set(5ms); + while (!m_decodingTimer.IsTimePast() && !timer.IsTimePast()) + { + m_decodingEvent.wait(lock, 1ms); + } + } + + PresentRenderImpl(rendered); +} + +void CRenderSystemDX::RequestDecodingTime() +{ + std::unique_lock<CCriticalSection> lock(m_decoderSection); + m_decodingTimer.Set(3ms); +} + +void CRenderSystemDX::ReleaseDecodingTime() +{ + std::unique_lock<CCriticalSection> lock(m_decoderSection); + m_decodingTimer.SetExpired(); + m_decodingEvent.notify(); +} + +bool CRenderSystemDX::BeginRender() +{ + if (!m_bRenderCreated) + return false; + + m_limitedColorRange = CServiceBroker::GetWinSystem()->UseLimitedColor(); + m_inScene = m_deviceResources->Begin(); + return m_inScene; +} + +bool CRenderSystemDX::EndRender() +{ + m_inScene = false; + + if (!m_bRenderCreated) + return false; + + return true; +} + +bool CRenderSystemDX::ClearBuffers(UTILS::COLOR::Color color) +{ + if (!m_bRenderCreated) + return false; + + float fColor[4]; + CD3DHelper::XMStoreColor(fColor, color); + ID3D11RenderTargetView* pRTView = m_deviceResources->GetBackBuffer().GetRenderTarget(); + + if ( m_stereoMode != RENDER_STEREO_MODE_OFF + && m_stereoMode != RENDER_STEREO_MODE_MONO) + { + // if stereo anaglyph/tab/sbs, data was cleared when left view was rendered + if (m_stereoView == RENDER_STEREO_VIEW_RIGHT) + { + // execute command's queue + m_deviceResources->FinishCommandList(); + + // do not clear RT for anaglyph modes + if ( m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA + || m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN + || m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_YELLOW_BLUE) + { + pRTView = nullptr; + } + // for interlaced/checkerboard clear view for right texture + else if (m_stereoMode == RENDER_STEREO_MODE_INTERLACED + || m_stereoMode == RENDER_STEREO_MODE_CHECKERBOARD) + { + pRTView = m_rightEyeTex.GetRenderTarget(); + } + } + } + + if (pRTView == nullptr) + return true; + + auto outputSize = m_deviceResources->GetOutputSize(); + CRect clRect(0.0f, 0.0f, + static_cast<float>(outputSize.Width), + static_cast<float>(outputSize.Height)); + + // Unlike Direct3D 9, D3D11 ClearRenderTargetView always clears full extent of the resource view. + // Viewport and scissor settings are not applied. So clear RT by drawing full sized rect with clear color + if (m_ScissorsEnabled && m_scissor != clRect) + { + bool alphaEnabled = m_BlendEnabled; + if (alphaEnabled) + SetAlphaBlendEnable(false); + + CGUITextureD3D::DrawQuad(clRect, color); + + if (alphaEnabled) + SetAlphaBlendEnable(true); + } + else + m_deviceResources->ClearRenderTarget(pRTView, fColor); + + m_deviceResources->ClearDepthStencil(); + return true; +} + +void CRenderSystemDX::CaptureStateBlock() +{ + if (!m_bRenderCreated) + return; +} + +void CRenderSystemDX::ApplyStateBlock() +{ + if (!m_bRenderCreated) + return; + + auto m_pContext = m_deviceResources->GetD3DContext(); + + m_pContext->RSSetState(m_ScissorsEnabled ? m_RSScissorEnable.Get() : m_RSScissorDisable.Get()); + m_pContext->OMSetDepthStencilState(m_depthStencilState.Get(), 0); + float factors[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + m_pContext->OMSetBlendState(m_BlendEnabled ? m_BlendEnableState.Get() : m_BlendDisableState.Get(), factors, 0xFFFFFFFF); + + m_pGUIShader->ApplyStateBlock(); +} + +void CRenderSystemDX::SetCameraPosition(const CPoint &camera, int screenWidth, int screenHeight, float stereoFactor) +{ + if (!m_bRenderCreated) + return; + + // grab the viewport dimensions and location + float w = m_viewPort.Width * 0.5f; + float h = m_viewPort.Height * 0.5f; + + XMFLOAT2 offset = XMFLOAT2(camera.x - screenWidth*0.5f, camera.y - screenHeight*0.5f); + + // world view. Until this is moved onto the GPU (via a vertex shader for instance), we set it to the identity here. + m_pGUIShader->SetWorld(XMMatrixIdentity()); + + // Initialize the view matrix camera view. + // Multiply the Y coord by -1 then translate so that everything is relative to the camera position. + XMMATRIX flipY = XMMatrixScaling(1.0, -1.0f, 1.0f); + XMMATRIX translate = XMMatrixTranslation(-(w + offset.x - stereoFactor), -(h + offset.y), 2 * h); + m_pGUIShader->SetView(XMMatrixMultiply(translate, flipY)); + + // projection onto screen space + 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)); +} + +void CRenderSystemDX::Project(float &x, float &y, float &z) +{ + if (!m_bRenderCreated) + return; + + m_pGUIShader->Project(x, y, z); +} + +CRect CRenderSystemDX::GetBackBufferRect() +{ + auto outputSize = m_deviceResources->GetOutputSize(); + return CRect(0.f, 0.f, static_cast<float>(outputSize.Width), static_cast<float>(outputSize.Height)); +} + +void CRenderSystemDX::GetViewPort(CRect& viewPort) +{ + if (!m_bRenderCreated) + return; + + viewPort.x1 = m_viewPort.TopLeftX; + viewPort.y1 = m_viewPort.TopLeftY; + viewPort.x2 = m_viewPort.TopLeftX + m_viewPort.Width; + viewPort.y2 = m_viewPort.TopLeftY + m_viewPort.Height; +} + +void CRenderSystemDX::SetViewPort(const CRect& viewPort) +{ + if (!m_bRenderCreated) + return; + + m_viewPort.MinDepth = 0.0f; + m_viewPort.MaxDepth = 1.0f; + m_viewPort.TopLeftX = viewPort.x1; + m_viewPort.TopLeftY = viewPort.y1; + m_viewPort.Width = viewPort.x2 - viewPort.x1; + m_viewPort.Height = viewPort.y2 - viewPort.y1; + + m_deviceResources->SetViewPort(m_viewPort); + m_pGUIShader->SetViewPort(m_viewPort); +} + +void CRenderSystemDX::RestoreViewPort() +{ + if (!m_bRenderCreated) + return; + + m_deviceResources->SetViewPort(m_viewPort); + m_pGUIShader->SetViewPort(m_viewPort); +} + +bool CRenderSystemDX::ScissorsCanEffectClipping() +{ + if (!m_bRenderCreated) + return false; + + return m_pGUIShader != nullptr && m_pGUIShader->HardwareClipIsPossible(); +} + +CRect CRenderSystemDX::ClipRectToScissorRect(const CRect &rect) +{ + if (!m_bRenderCreated) + return CRect(); + + float xFactor = m_pGUIShader->GetClipXFactor(); + float xOffset = m_pGUIShader->GetClipXOffset(); + float yFactor = m_pGUIShader->GetClipYFactor(); + float yOffset = m_pGUIShader->GetClipYOffset(); + + return CRect(rect.x1 * xFactor + xOffset, + rect.y1 * yFactor + yOffset, + rect.x2 * xFactor + xOffset, + rect.y2 * yFactor + yOffset); +} + +void CRenderSystemDX::SetScissors(const CRect& rect) +{ + if (!m_bRenderCreated) + return; + + auto m_pContext = m_deviceResources->GetD3DContext(); + + m_scissor = rect; + CD3D11_RECT scissor(MathUtils::round_int(rect.x1) + , MathUtils::round_int(rect.y1) + , MathUtils::round_int(rect.x2) + , MathUtils::round_int(rect.y2)); + + m_pContext->RSSetScissorRects(1, &scissor); + m_pContext->RSSetState(m_RSScissorEnable.Get()); + m_ScissorsEnabled = true; +} + +void CRenderSystemDX::ResetScissors() +{ + if (!m_bRenderCreated) + return; + + auto m_pContext = m_deviceResources->GetD3DContext(); + auto outputSize = m_deviceResources->GetOutputSize(); + + m_scissor.SetRect(0.0f, 0.0f, + static_cast<float>(outputSize.Width), + static_cast<float>(outputSize.Height)); + + m_pContext->RSSetState(m_RSScissorDisable.Get()); + m_ScissorsEnabled = false; +} + +void CRenderSystemDX::OnDXDeviceLost() +{ + CRenderSystemDX::DestroyRenderSystem(); +} + +void CRenderSystemDX::OnDXDeviceRestored() +{ + CRenderSystemDX::InitRenderSystem(); +} + +void CRenderSystemDX::SetStereoMode(RENDER_STEREO_MODE mode, RENDER_STEREO_VIEW view) +{ + CRenderSystemBase::SetStereoMode(mode, view); + + if (!m_bRenderCreated) + return; + + auto m_pContext = m_deviceResources->GetD3DContext(); + + UINT writeMask = D3D11_COLOR_WRITE_ENABLE_ALL; + if(m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN) + { + if(m_stereoView == RENDER_STEREO_VIEW_LEFT) + writeMask = D3D11_COLOR_WRITE_ENABLE_RED; + else if(m_stereoView == RENDER_STEREO_VIEW_RIGHT) + writeMask = D3D11_COLOR_WRITE_ENABLE_BLUE | D3D11_COLOR_WRITE_ENABLE_GREEN; + } + if(m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA) + { + if(m_stereoView == RENDER_STEREO_VIEW_LEFT) + writeMask = D3D11_COLOR_WRITE_ENABLE_GREEN; + else if(m_stereoView == RENDER_STEREO_VIEW_RIGHT) + writeMask = D3D11_COLOR_WRITE_ENABLE_BLUE | D3D11_COLOR_WRITE_ENABLE_RED; + } + if (m_stereoMode == RENDER_STEREO_MODE_ANAGLYPH_YELLOW_BLUE) + { + if (m_stereoView == RENDER_STEREO_VIEW_LEFT) + writeMask = D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN; + else if (m_stereoView == RENDER_STEREO_VIEW_RIGHT) + writeMask = D3D11_COLOR_WRITE_ENABLE_BLUE; + } + if ( RENDER_STEREO_MODE_INTERLACED == m_stereoMode + || RENDER_STEREO_MODE_CHECKERBOARD == m_stereoMode) + { + if (m_stereoView == RENDER_STEREO_VIEW_RIGHT) + { + m_pContext->OMSetRenderTargets(1, m_rightEyeTex.GetAddressOfRTV(), m_deviceResources->GetDSV()); + } + } + else if (RENDER_STEREO_MODE_HARDWAREBASED == m_stereoMode) + { + m_deviceResources->SetStereoIdx(m_stereoView == RENDER_STEREO_VIEW_RIGHT ? 1 : 0); + + m_pContext->OMSetRenderTargets(1, m_deviceResources->GetBackBuffer().GetAddressOfRTV(), m_deviceResources->GetDSV()); + } + + auto m_pD3DDev = m_deviceResources->GetD3DDevice(); + + D3D11_BLEND_DESC desc; + m_BlendEnableState->GetDesc(&desc); + // update blend state + if (desc.RenderTarget[0].RenderTargetWriteMask != writeMask) + { + m_BlendDisableState = nullptr; + m_BlendEnableState = nullptr; + + desc.RenderTarget[0].RenderTargetWriteMask = writeMask; + m_pD3DDev->CreateBlendState(&desc, &m_BlendEnableState); + + desc.RenderTarget[0].BlendEnable = false; + m_pD3DDev->CreateBlendState(&desc, &m_BlendDisableState); + + float blendFactors[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + m_pContext->OMSetBlendState(m_BlendEnabled ? m_BlendEnableState.Get() : m_BlendDisableState.Get(), blendFactors, 0xFFFFFFFF); + } +} + +bool CRenderSystemDX::SupportsStereo(RENDER_STEREO_MODE mode) const +{ + switch (mode) + { + case RENDER_STEREO_MODE_ANAGLYPH_RED_CYAN: + case RENDER_STEREO_MODE_ANAGLYPH_GREEN_MAGENTA: + case RENDER_STEREO_MODE_ANAGLYPH_YELLOW_BLUE: + case RENDER_STEREO_MODE_INTERLACED: + case RENDER_STEREO_MODE_CHECKERBOARD: + return true; + case RENDER_STEREO_MODE_HARDWAREBASED: + return m_deviceResources->IsStereoAvailable(); + default: + return CRenderSystemBase::SupportsStereo(mode); + } +} + +void CRenderSystemDX::FlushGPU() const +{ + if (!m_bRenderCreated) + return; + + m_deviceResources->FinishCommandList(); + m_deviceResources->GetImmediateContext()->Flush(); +} + +bool CRenderSystemDX::InitGUIShader() +{ + delete m_pGUIShader; + m_pGUIShader = nullptr; + + m_pGUIShader = new CGUIShaderDX(); + if (!m_pGUIShader->Initialize()) + { + CLog::LogF(LOGERROR, "Failed to initialize GUI shader."); + return false; + } + + m_pGUIShader->ApplyStateBlock(); + return true; +} + +void CRenderSystemDX::SetAlphaBlendEnable(bool enable) +{ + if (!m_bRenderCreated) + return; + + m_deviceResources->GetD3DContext()->OMSetBlendState(enable ? m_BlendEnableState.Get() : m_BlendDisableState.Get(), nullptr, 0xFFFFFFFF); + m_BlendEnabled = enable; +} + +CD3DTexture& CRenderSystemDX::GetBackBuffer() +{ + if (m_stereoView == RENDER_STEREO_VIEW_RIGHT && m_rightEyeTex.Get()) + return m_rightEyeTex; + + return m_deviceResources->GetBackBuffer(); +} + +void CRenderSystemDX::CheckDeviceCaps() +{ + const auto feature_level = m_deviceResources->GetDeviceFeatureLevel(); + if (feature_level < D3D_FEATURE_LEVEL_9_3) + m_maxTextureSize = D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION; + else if (feature_level < D3D_FEATURE_LEVEL_10_0) + m_maxTextureSize = D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION; + else if (feature_level < D3D_FEATURE_LEVEL_11_0) + m_maxTextureSize = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + else + // 11_x and greater feature level. Limit this size to avoid memory overheads + m_maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION >> 1; +} + +bool CRenderSystemDX::SupportsNPOT(bool dxt) const +{ + // MSDN says: + // 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: + // 1) only one MIP-map level for each texture can be created - we are using both 1 and 0 mipmap levels + // 2) no wrap sampler modes for textures are allowed - we are using clamp everywhere + // 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. + // taking in account first condition we setup caps NPOT for FE > 9.x only + return m_deviceResources->GetDeviceFeatureLevel() > D3D_FEATURE_LEVEL_9_3 ? true : false; +} |