diff options
author | Anton Fedchin <anightik@gmail.com> | 2017-04-26 12:44:04 +0300 |
---|---|---|
committer | Anton Fedchin <anightik@gmail.com> | 2017-07-17 11:43:31 +0300 |
commit | 6c6a46c2a95267ec9a525c817c9d8cec7b67b583 (patch) | |
tree | 6040a2e42c4c5bc1e4519a6bc05f48528114e552 | |
parent | c8e1ba473b52d3f0501707dd4ea51f0ba6d4c9c8 (diff) |
[VideoPlayer] WinRenderer: rework to use new CWinRenderBuffer
6 files changed, 385 insertions, 921 deletions
diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.cpp index ccdc90a698..7abba569c5 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.cpp @@ -30,6 +30,7 @@ #include "DXVAHD.h" #include "cores/VideoPlayer/VideoRenderers/RenderManager.h" #include "cores/VideoPlayer/VideoRenderers/RenderFlags.h" +#include "cores/VideoPlayer/VideoRenderers/WinVideoBuffer.h" #include "settings/MediaSettings.h" #include "utils/Log.h" #include "utils/win32/memcpy_sse2.h" @@ -48,17 +49,14 @@ do { \ } while(0); CProcessorHD::CProcessorHD() + : m_width(0) + , m_height(0) + , m_pVideoDevice(nullptr) + , m_pVideoContext(nullptr) + , m_pEnumerator(nullptr) + , m_pVideoProcessor(nullptr) { - m_pVideoDevice = nullptr; - m_pVideoContext = nullptr; - m_pEnumerator = nullptr; - m_pVideoProcessor = nullptr; - m_eViewType = PROCESSOR_VIEW_TYPE_UNKNOWN; g_Windowing.Register(this); - - m_context = nullptr; - m_width = 0; - m_height = 0; } CProcessorHD::~CProcessorHD() @@ -79,9 +77,7 @@ void CProcessorHD::Close() CSingleLock lock(m_section); SAFE_RELEASE(m_pEnumerator); SAFE_RELEASE(m_pVideoProcessor); - SAFE_RELEASE(m_context); SAFE_RELEASE(m_pVideoContext); - m_eViewType = PROCESSOR_VIEW_TYPE_UNKNOWN; } bool CProcessorHD::PreInit() @@ -110,8 +106,6 @@ bool CProcessorHD::PreInit() return false; } - memset(&m_texDesc, 0, sizeof(D3D11_TEXTURE2D_DESC)); - SAFE_RELEASE(m_pEnumerator); return true; } @@ -182,8 +176,8 @@ bool CProcessorHD::InitProcessor() CLog::Log(LOGDEBUG, "%s: Selected video processor index: %d.", __FUNCTION__, m_procIndex); LOGIFERROR(m_pEnumerator->GetVideoProcessorRateConversionCaps(m_procIndex, &m_rateCaps)) - m_max_fwd_refs = m_rateCaps.FutureFrames; - m_max_back_refs = m_rateCaps.PastFrames; + m_max_fwd_refs = std::min(m_rateCaps.FutureFrames, 2u); + m_max_back_refs = std::min(m_rateCaps.PastFrames, 4u); CLog::Log(LOGNOTICE, "%s: Supported deinterlace methods: Blend:%s, Bob:%s, Adaptive:%s, MoComp:%s.", __FUNCTION__, (m_rateCaps.ProcessorCaps & 0x1) != 0 ? "yes" : "no", // BLEND @@ -194,7 +188,7 @@ bool CProcessorHD::InitProcessor() CLog::Log(LOGDEBUG, "%s: Selected video processor allows %d future frames and %d past frames.", __FUNCTION__, m_rateCaps.FutureFrames, m_rateCaps.PastFrames); - m_size = m_max_back_refs + 1 + m_max_fwd_refs + 3; // refs + 1 display + 3 safety frames + m_size = m_max_back_refs + 1 + m_max_fwd_refs; // refs + 1 display // Get the image filtering capabilities. for (long i = 0; i < NUM_FILTERS; i++) @@ -222,7 +216,7 @@ bool CProcessorHD::InitProcessor() return true; } -bool DXVA::CProcessorHD::IsFormatSupported(DXGI_FORMAT format, D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT support) const +bool CProcessorHD::IsFormatSupported(DXGI_FORMAT format, D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT support) const { UINT uiFlags; if (S_OK == m_pEnumerator->CheckVideoProcessorFormat(format, &uiFlags)) @@ -235,40 +229,15 @@ bool DXVA::CProcessorHD::IsFormatSupported(DXGI_FORMAT format, D3D11_VIDEO_PROCE return false; } -bool CProcessorHD::ConfigureProcessor(AVPixelFormat format, DXGI_FORMAT dxva_format) +bool CProcessorHD::CheckFormats() const { // check default output format DXGI_FORMAT_B8G8R8A8_UNORM (as render target) if (!IsFormatSupported(DXGI_FORMAT_B8G8R8A8_UNORM, D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_OUTPUT)) return false; - - if (format == AV_PIX_FMT_D3D11VA_VLD) - { - m_textureFormat = dxva_format; - m_eViewType = PROCESSOR_VIEW_TYPE_DECODER; - } - else - { - m_textureFormat = DXGI_FORMAT_NV12; // default - - if (format == AV_PIX_FMT_YUV420P) - m_textureFormat = DXGI_FORMAT_NV12; - if (format == AV_PIX_FMT_YUV420P10) - m_textureFormat = DXGI_FORMAT_P010; - if (format == AV_PIX_FMT_YUV420P16) - m_textureFormat = DXGI_FORMAT_P016; - - m_eViewType = PROCESSOR_VIEW_TYPE_PROCESSOR; - } - - if (!IsFormatSupported(m_textureFormat, D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT_INPUT)) - return false; - if (m_eViewType == PROCESSOR_VIEW_TYPE_PROCESSOR && !CreateSurfaces()) - return false; - return true; } -bool CProcessorHD::Open(UINT width, UINT height, unsigned int flags, AVPixelFormat format, DXGI_FORMAT dxva_format) +bool CProcessorHD::Open(UINT width, UINT height) { Close(); @@ -276,13 +245,11 @@ bool CProcessorHD::Open(UINT width, UINT height, unsigned int flags, AVPixelForm m_width = width; m_height = height; - m_flags = flags; - m_renderFormat = format; if (!InitProcessor()) return false; - if (!ConfigureProcessor(m_renderFormat, dxva_format)) + if (!CheckFormats()) return false; return OpenProcessor(); @@ -299,7 +266,7 @@ bool CProcessorHD::ReInit() if (!InitProcessor()) return false; - if (!ConfigureProcessor(m_renderFormat, m_textureFormat)) + if (!CheckFormats()) return false; return true; @@ -314,7 +281,7 @@ bool CProcessorHD::OpenProcessor() return false; SAFE_RELEASE(m_pVideoProcessor); - CLog::Log(LOGDEBUG, "%s: Creating processor with input format: (%d).", __FUNCTION__, m_textureFormat); + CLog::Log(LOGDEBUG, "%s: Creating processor.", __FUNCTION__); // create processor HRESULT hr = m_pVideoDevice->CreateVideoProcessor(m_pEnumerator, m_procIndex, &m_pVideoProcessor); @@ -324,18 +291,6 @@ bool CProcessorHD::OpenProcessor() return false; } - D3D11_VIDEO_PROCESSOR_COLOR_SPACE cs - { - 0, // 0 - Playback, 1 - Processing - 0, // 0 - Full (0-255), 1 - Limited (16-235) - m_flags & CONF_FLAGS_YUVCOEF_BT709 ? 1 : 0, // 0 - BT.601, 1 - BT.709 - 0, // 0 - Conventional YCbCr, 1 - xvYCC - m_flags & CONF_FLAGS_YUV_FULLRANGE ? 2 : 1, // 2 - Full luminance range [0-255], 1 - Studio luminance range [16-235], 0 - driver defaults - }; - if (m_vcaps.DeviceCaps & D3D11_VIDEO_PROCESSOR_DEVICE_CAPS_NOMINAL_RANGE) - cs.Nominal_Range = m_flags & CONF_FLAGS_YUV_FULLRANGE ? 2 : 1; - m_pVideoContext->VideoProcessorSetStreamColorSpace(m_pVideoProcessor, DEFAULT_STREAM_INDEX, &cs); - // Output background color (black) D3D11_VIDEO_COLOR color; color.YCbCr = { 0.0625f, 0.5f, 0.5f, 1.0f }; // black color @@ -344,124 +299,6 @@ bool CProcessorHD::OpenProcessor() return true; } -bool CProcessorHD::CreateSurfaces() -{ - HRESULT hr; - size_t idx; - ID3D11Device* pD3DDevice = g_Windowing.Get3D11Device(); - - // we cannot use texture array (like in decoder) for USAGE_DYNAMIC, so create separate textures - CD3D11_TEXTURE2D_DESC texDesc(m_textureFormat, FFALIGN(m_width, 16), FFALIGN(m_height, 16), 1, 1, D3D11_BIND_DECODER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC pivd = { 0, D3D11_VPIV_DIMENSION_TEXTURE2D }; - pivd.Texture2D.ArraySlice = 0; - pivd.Texture2D.MipSlice = 0; - - ID3D11VideoProcessorInputView* views[32] = { nullptr }; - CLog::Log(LOGDEBUG, "%s - Creating %d processor surfaces with format %d.", __FUNCTION__, m_size, m_textureFormat); - - for (idx = 0; idx < m_size; idx++) - { - ID3D11Texture2D* pTexture = nullptr; - hr = pD3DDevice->CreateTexture2D(&texDesc, nullptr, &pTexture); - if (FAILED(hr)) - break; - - hr = m_pVideoDevice->CreateVideoProcessorInputView(pTexture, m_pEnumerator, &pivd, &views[idx]); - SAFE_RELEASE(pTexture); - if (FAILED(hr)) - break; - } - - if (idx != m_size) - { - // something goes wrong - CLog::Log(LOGERROR, "%s: Failed to create processor surfaces.", __FUNCTION__); - for (idx = 0; idx < m_size; idx++) - { - SAFE_RELEASE(views[idx]); - } - return false; - } - - m_context = new CSurfaceContext(); - for (unsigned int i = 0; i < m_size; i++) - { - m_context->AddSurface(views[i]); - } - - m_texDesc = texDesc; - return true; -} - -CRenderPicture *CProcessorHD::Convert(const VideoPicture &picture) const -{ - if (!picture.videoBuffer) - return nullptr; - - AVPixelFormat format = picture.videoBuffer->GetFormat(); - if ( format != AV_PIX_FMT_YUV420P - && format != AV_PIX_FMT_YUV420P10 - && format != AV_PIX_FMT_YUV420P16 - && format != AV_PIX_FMT_D3D11VA_VLD) - { - CLog::Log(LOGERROR, "%s: colorspace not supported by processor, skipping frame.", __FUNCTION__); - return nullptr; - } - - if (format == AV_PIX_FMT_D3D11VA_VLD) - { - CDXVAVideoBuffer* pic = dynamic_cast<CDXVAVideoBuffer*>(picture.videoBuffer); - return pic->picture->Acquire(); - } - - ID3D11View *pView = m_context->GetFree(nullptr); - if (!pView) - { - CLog::Log(LOGERROR, "%s: no free video surface", __FUNCTION__); - return nullptr; - } - - ID3D11Resource* pResource = nullptr; - pView->GetResource(&pResource); - - D3D11_MAPPED_SUBRESOURCE rectangle; - ID3D11DeviceContext* pContext = g_Windowing.GetImmediateContext(); - - if (FAILED(pContext->Map(pResource, 0, D3D11_MAP_WRITE_DISCARD, 0, &rectangle))) - { - CLog::Log(LOGERROR, "%s: could not lock rect", __FUNCTION__); - m_context->ClearReference(pView); - return nullptr; - } - - uint8_t* planes[3]; picture.videoBuffer->GetPlanes(planes); - int strides[3]; picture.videoBuffer->GetStrides(strides); - - uint8_t* pData = static_cast<uint8_t*>(rectangle.pData); - uint8_t* dst[] = { pData, pData + m_texDesc.Height * rectangle.RowPitch }; - int dstStride[] = { rectangle.RowPitch, rectangle.RowPitch }; - - if (format == AV_PIX_FMT_YUV420P) - { - convert_yuv420_nv12(planes, strides, picture.iHeight, picture.iWidth, dst, dstStride); - } - else if(format == AV_PIX_FMT_YUV420P10 - || format == AV_PIX_FMT_YUV420P16) - { - convert_yuv420_p01x(planes, strides, picture.iHeight, picture.iWidth, dst, dstStride - , format == AV_PIX_FMT_YUV420P10 ? 10 : 16); - } - pContext->Unmap(pResource, 0); - SAFE_RELEASE(pResource); - - m_context->ClearReference(pView); - m_context->MarkRender(pView); - - CRenderPicture *pic = new CRenderPicture(m_context); - pic->view = pView; - return pic; -} - bool CProcessorHD::ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER filter, int value, int min, int max, int def) const { if (filter >= NUM_FILTERS) @@ -485,21 +322,18 @@ bool CProcessorHD::ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER filter, int value, i return true; } -ID3D11VideoProcessorInputView* CProcessorHD::GetInputView(ID3D11View* view) const +ID3D11VideoProcessorInputView* CProcessorHD::GetInputView(SWinVideoBuffer* view) const { ID3D11VideoProcessorInputView* inputView = nullptr; - if (m_eViewType == PROCESSOR_VIEW_TYPE_PROCESSOR) - { - inputView = reinterpret_cast<ID3D11VideoProcessorInputView*>(view); - inputView->AddRef(); // it will be released later - } - else if (m_eViewType == PROCESSOR_VIEW_TYPE_DECODER) + D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC vpivd = { 0, D3D11_VPIV_DIMENSION_TEXTURE2D,{ 0, 0 } }; + + if (view->format == BUFFER_FMT_DXVA_BYPASS) { // the view cames from decoder - ID3D11VideoDecoderOutputView* decoderView = reinterpret_cast<ID3D11VideoDecoderOutputView*>(view); + ID3D11VideoDecoderOutputView* decoderView = reinterpret_cast<ID3D11VideoDecoderOutputView*>(view->GetHWView()); if (!decoderView) { - CLog::Log(LOGERROR, "%s: cannot get view.", __FUNCTION__); + CLog::Log(LOGERROR, "%s: cannot get decoder view.", __FUNCTION__); return nullptr; } @@ -507,22 +341,39 @@ ID3D11VideoProcessorInputView* CProcessorHD::GetInputView(ID3D11View* view) cons D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC vdovd; decoderView->GetDesc(&vdovd); decoderView->GetResource(&resource); - - D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC vpivd; - vpivd.FourCC = 0; - vpivd.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; vpivd.Texture2D.ArraySlice = vdovd.Texture2D.ArraySlice; - vpivd.Texture2D.MipSlice = 0; if (FAILED(m_pVideoDevice->CreateVideoProcessorInputView(resource, m_pEnumerator, &vpivd, &inputView))) - CLog::Log(LOGERROR, "%s: cannot create processor view.", __FUNCTION__); + CLog::Log(LOGERROR, "%s: cannot create processor input view.", __FUNCTION__); resource->Release(); } + else if (view->format == BUFFER_FMT_DXVA_NV12 + || view->format == BUFFER_FMT_DXVA_P010 + || view->format == BUFFER_FMT_DXVA_P016) + { + if (FAILED(m_pVideoDevice->CreateVideoProcessorInputView(view->GetResource(), m_pEnumerator, &vpivd, &inputView))) + CLog::Log(LOGERROR, "%s: cannot create processor input view.", __FUNCTION__); + } + return inputView; } -bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, ID3D11View** views, DWORD flags, UINT frameIdx, UINT rotation) +static void ReleaseStream(D3D11_VIDEO_PROCESSOR_STREAM &stream_data) +{ + SAFE_RELEASE(stream_data.pInputSurface); + + for (size_t i = 0; i < stream_data.PastFrames; ++i) + SAFE_RELEASE(stream_data.ppPastSurfaces[i]); + + for (size_t i = 0; i < stream_data.FutureFrames; ++i) + SAFE_RELEASE(stream_data.ppFutureSurfaces[i]); + + delete[] stream_data.ppPastSurfaces; + delete[] stream_data.ppFutureSurfaces; +} + +bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, SWinVideoBuffer** views, DWORD flags, UINT frameIdx, UINT rotation) { HRESULT hr; CSingleLock lock(m_section); @@ -558,43 +409,51 @@ bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, ID3D11Vi stream_data.Enable = TRUE; stream_data.PastFrames = pastFrames; stream_data.FutureFrames = futureFrames; - stream_data.ppPastSurfaces = new ID3D11VideoProcessorInputView*[pastFrames]; - stream_data.ppFutureSurfaces = new ID3D11VideoProcessorInputView*[futureFrames]; - stream_data.pInputSurfaceRight = nullptr; - stream_data.ppPastSurfacesRight = nullptr; - stream_data.ppFutureSurfacesRight = nullptr; + if (pastFrames) + stream_data.ppPastSurfaces = new ID3D11VideoProcessorInputView*[pastFrames]; + if (futureFrames) + stream_data.ppFutureSurfaces = new ID3D11VideoProcessorInputView*[futureFrames]; + ID3D11VideoProcessorInputView* view = nullptr; int start = 2 - futureFrames; int end = 2 + pastFrames; - - D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC pivd; - ZeroMemory(&pivd, sizeof(D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC)); - pivd.FourCC = 0; - pivd.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D; - pivd.Texture2D.ArraySlice = 0; - pivd.Texture2D.MipSlice = 0; + int count = 0; for (int i = start; i <= end; i++) { if (!views[i]) continue; + view = GetInputView(views[i]); if (i > 2) { // frames order should be { ?, T-3, T-2, T-1 } - stream_data.ppPastSurfaces[2 + pastFrames - i] = GetInputView(views[i]); + stream_data.ppPastSurfaces[2 + pastFrames - i] = view; } else if (i == 2) { - stream_data.pInputSurface = GetInputView(views[2]); + stream_data.pInputSurface = view; } else if (i < 2) { // frames order should be { T+1, T+2, T+3, .. } - stream_data.ppFutureSurfaces[1 - i] = GetInputView(views[i]); + stream_data.ppFutureSurfaces[1 - i] = view; } + if (view) + count++; } + if (count != pastFrames + futureFrames + 1) + { + CLog::Log(LOGERROR, "%s: incomplete views set.", __FUNCTION__); + ReleaseStream(stream_data); + return false; + } + + // fix locked textures + for (int i = start; i <= end; i++) + if (i != 2 && views[i]) views[i]->StartRender(); + if (flags & RENDER_FLAG_FIELD0 && flags & RENDER_FLAG_TOP) dxvaFrameFormat = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST; else if (flags & RENDER_FLAG_FIELD1 && flags & RENDER_FLAG_BOT) @@ -612,6 +471,16 @@ bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, ID3D11Vi // input format m_pVideoContext->VideoProcessorSetStreamFrameFormat(m_pVideoProcessor, DEFAULT_STREAM_INDEX, dxvaFrameFormat); + // input colorspace + D3D11_VIDEO_PROCESSOR_COLOR_SPACE colorSpace + { + 0, // 0 - Playback, 1 - Processing + 0, // 0 - Full (0-255), 1 - Limited (16-235) (RGB) + views[2]->flags & CONF_FLAGS_YUVCOEF_BT709 ? 1 : 0, // 0 - BT.601, 1 - BT.709 + 0, // 0 - Conventional YCbCr, 1 - xvYCC + views[2]->flags & CONF_FLAGS_YUV_FULLRANGE ? 2 : 1, // 0 - driver defaults, 2 - Full range [0-255], 1 - Studio range [16-235] (YUV) + }; + m_pVideoContext->VideoProcessorSetStreamColorSpace(m_pVideoProcessor, DEFAULT_STREAM_INDEX, &colorSpace); // Source rect m_pVideoContext->VideoProcessorSetStreamSourceRect(m_pVideoProcessor, DEFAULT_STREAM_INDEX, TRUE, &sourceRECT); // Stream dest rect @@ -620,39 +489,30 @@ bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, ID3D11Vi m_pVideoContext->VideoProcessorSetOutputTargetRect(m_pVideoProcessor, TRUE, &dstRECT); // Output color space // don't apply any color range conversion, this will be fixed at later stage. - D3D11_VIDEO_PROCESSOR_COLOR_SPACE colorSpace = {}; colorSpace.Usage = 0; // 0 - playback, 1 - video processing colorSpace.RGB_Range = g_Windowing.UseLimitedColor() ? 1 : 0; // 0 - 0-255, 1 - 16-235 colorSpace.YCbCr_Matrix = 1; // 0 - BT.601, 1 = BT.709 colorSpace.YCbCr_xvYCC = 1; // 0 - Conventional YCbCr, 1 - xvYCC colorSpace.Nominal_Range = 0; // 2 - 0-255, 1 = 16-235, 0 - undefined - m_pVideoContext->VideoProcessorSetOutputColorSpace(m_pVideoProcessor, &colorSpace); - + // brightness ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_BRIGHTNESS, CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Brightness, 0, 100, 50); + // contrast ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_CONTRAST, CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Contrast, 0, 100, 50); + // unused filters ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_HUE, 50, 0, 100, 50); ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_SATURATION, 50, 0, 100, 50); // Rotation - m_pVideoContext->VideoProcessorSetStreamRotation(m_pVideoProcessor, DEFAULT_STREAM_INDEX, (rotation != 0), (D3D11_VIDEO_PROCESSOR_ROTATION)(rotation / 90)); - - // - // Create Output View of Output Surfaces. - // - D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC OutputViewDesc; - ZeroMemory(&OutputViewDesc, sizeof(OutputViewDesc)); - OutputViewDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D; - OutputViewDesc.Texture2D.MipSlice = 0; - OutputViewDesc.Texture2DArray.ArraySize = 0; // 2 for stereo - OutputViewDesc.Texture2DArray.MipSlice = 0; - OutputViewDesc.Texture2DArray.FirstArraySlice = 0; - - ID3D11VideoProcessorOutputView* pOutputView; + m_pVideoContext->VideoProcessorSetStreamRotation(m_pVideoProcessor, DEFAULT_STREAM_INDEX, rotation != 0 + , static_cast<D3D11_VIDEO_PROCESSOR_ROTATION>(rotation / 90)); + // create output view for surface. + D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC OutputViewDesc = { D3D11_VPOV_DIMENSION_TEXTURE2D, { 0 }}; + ID3D11VideoProcessorOutputView* pOutputView = nullptr; hr = m_pVideoDevice->CreateVideoProcessorOutputView(target, m_pEnumerator, &OutputViewDesc, &pOutputView); if (S_OK != hr) - CLog::Log(FAILED(hr) ? LOGERROR : LOGWARNING, "%s: Device returns result '%x' while creating processor output.", __FUNCTION__, hr); + CLog::Log(FAILED(hr) ? LOGERROR : LOGWARNING, "%s: Device returns result '%x' while creating processor output view.", __FUNCTION__, hr); if (SUCCEEDED(hr)) { @@ -664,16 +524,7 @@ bool CProcessorHD::Render(CRect src, CRect dst, ID3D11Resource* target, ID3D11Vi } SAFE_RELEASE(pOutputView); - SAFE_RELEASE(stream_data.pInputSurface); - - for (size_t i = 0; i < stream_data.PastFrames; ++i) - SAFE_RELEASE(stream_data.ppPastSurfaces[i]); - - for (size_t i = 0; i < stream_data.FutureFrames; ++i) - SAFE_RELEASE(stream_data.ppFutureSurfaces[i]); - - delete[] stream_data.ppPastSurfaces; - delete[] stream_data.ppFutureSurfaces; + ReleaseStream(stream_data); return !FAILED(hr); } diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.h index 031722d516..cb62fb77e1 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/DXVAHD.h @@ -25,6 +25,8 @@ #include "guilib/D3DResource.h" #include "guilib/Geometry.h" +class SWinVideoBuffer; + namespace DXVA { // ProcAmp filters d3d11 filters @@ -36,13 +38,6 @@ const D3D11_VIDEO_PROCESSOR_FILTER PROCAMP_FILTERS[] = D3D11_VIDEO_PROCESSOR_FILTER_SATURATION }; -enum PROCESSOR_VIEW_TYPE -{ - PROCESSOR_VIEW_TYPE_UNKNOWN = 0, - PROCESSOR_VIEW_TYPE_DECODER = 1, - PROCESSOR_VIEW_TYPE_PROCESSOR = 2 -}; - const DWORD NUM_FILTERS = ARRAYSIZE(PROCAMP_FILTERS); class CProcessorHD : public ID3DResource @@ -53,11 +48,10 @@ public: bool PreInit(); void UnInit(); - bool Open(UINT width, UINT height, unsigned int flags, AVPixelFormat format, DXGI_FORMAT dxva_format); + bool Open(UINT width, UINT height); void Close(); - CRenderPicture *Convert(const VideoPicture &picture) const; - bool Render(CRect src, CRect dst, ID3D11Resource* target, ID3D11View **views, DWORD flags, UINT frameIdx, UINT rotation); - uint8_t Size() const { if (m_pVideoProcessor) return m_size; return 0; } + bool Render(CRect src, CRect dst, ID3D11Resource* target, SWinVideoBuffer **views, DWORD flags, UINT frameIdx, UINT rotation); + uint8_t Size() const { return m_pVideoProcessor ? m_size : 0; } uint8_t PastRefs() const { return m_max_back_refs; } // ID3DResource overrides @@ -69,41 +63,33 @@ public: protected: bool ReInit(); bool InitProcessor(); - bool ConfigureProcessor(AVPixelFormat format, DXGI_FORMAT dxva_format); + bool CheckFormats() const; bool OpenProcessor(); - bool CreateSurfaces(); bool ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER filter, int value, int min, int max, int def) const; - ID3D11VideoProcessorInputView* GetInputView(ID3D11View* view) const; + ID3D11VideoProcessorInputView* GetInputView(SWinVideoBuffer* view) const; bool IsFormatSupported(DXGI_FORMAT format, D3D11_VIDEO_PROCESSOR_FORMAT_SUPPORT support) const; + CCriticalSection m_section; + uint32_t m_width; uint32_t m_height; - uint32_t m_flags = 0; - AVPixelFormat m_renderFormat = AV_PIX_FMT_NONE; - uint8_t m_size = 0; - uint8_t m_max_back_refs = 0; - uint8_t m_max_fwd_refs = 0; + uint8_t m_size; + uint8_t m_max_back_refs; + uint8_t m_max_fwd_refs; + uint32_t m_procIndex; + D3D11_VIDEO_PROCESSOR_CAPS m_vcaps; + D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS m_rateCaps; struct ProcAmpInfo { bool bSupported; - D3D11_VIDEO_PROCESSOR_FILTER_RANGE Range; + D3D11_VIDEO_PROCESSOR_FILTER_RANGE Range; }; ProcAmpInfo m_Filters[NUM_FILTERS]; - - DXGI_FORMAT m_textureFormat; ID3D11VideoDevice *m_pVideoDevice; ID3D11VideoContext *m_pVideoContext; ID3D11VideoProcessorEnumerator *m_pEnumerator; - D3D11_VIDEO_PROCESSOR_CAPS m_vcaps; ID3D11VideoProcessor *m_pVideoProcessor; - CSurfaceContext *m_context; - CCriticalSection m_section; - - uint32_t m_procIndex = 0; - D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS m_rateCaps; - D3D11_TEXTURE2D_DESC m_texDesc; - PROCESSOR_VIEW_TYPE m_eViewType; }; }; diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.cpp index 18d7685b76..e9063be2a2 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.cpp @@ -42,10 +42,10 @@ CYUV2RGBMatrix::CYUV2RGBMatrix() m_contrast = 0.0f; m_flags = 0; m_limitedRange = false; - m_format = SHADER_NONE; + m_format = BUFFER_FMT_NONE; } -void CYUV2RGBMatrix::SetParameters(float contrast, float blacklevel, unsigned int flags, EShaderFormat format) +void CYUV2RGBMatrix::SetParameters(float contrast, float blacklevel, unsigned int flags, EBufferFormat format) { if (m_contrast != contrast) { @@ -79,7 +79,10 @@ XMFLOAT4X4* CYUV2RGBMatrix::Matrix() if (m_NeedRecalc) { TransformMatrix matrix; - CalculateYUVMatrix(matrix, m_flags, m_format, m_blacklevel, m_contrast, m_limitedRange); + EShaderFormat fmt = SHADER_NONE; + if (m_format == BUFFER_FMT_YUV420P10 || m_format == BUFFER_FMT_DXVA_P010) + fmt = SHADER_YV12_10; + CalculateYUVMatrix(matrix, m_flags, fmt, m_blacklevel, m_contrast, m_limitedRange); m_mat._11 = matrix.m[0][0]; m_mat._12 = matrix.m[1][0]; @@ -480,41 +483,35 @@ void COutputShader::CreateDitherView() //================================================================================== -bool CYUV2RGBShader::Create(unsigned int sourceWidth, unsigned int sourceHeight, EShaderFormat fmt, COutputShader *pCLUT) +bool CYUV2RGBShader::Create(EBufferFormat fmt, COutputShader *pCLUT) { - CWinShader::CreateVertexBuffer(4, sizeof(CUSTOMVERTEX)); - - m_sourceWidth = sourceWidth; - m_sourceHeight = sourceHeight; m_format = fmt; m_pOutShader = pCLUT; - unsigned int texWidth; - DefinesMap defines; switch (fmt) { - case SHADER_YV12: - case SHADER_YV12_10: - case SHADER_YV12_16: + case BUFFER_FMT_YUV420P: + case BUFFER_FMT_YUV420P10: + case BUFFER_FMT_YUV420P16: defines["XBMC_YV12"] = ""; - texWidth = sourceWidth; break; - case SHADER_NV12: + case BUFFER_FMT_DXVA_BYPASS: + case BUFFER_FMT_DXVA_NV12: + case BUFFER_FMT_DXVA_P010: + case BUFFER_FMT_DXVA_P016: + case BUFFER_FMT_NV12: defines["XBMC_NV12"] = ""; - texWidth = sourceWidth; // FL 9.x doesn't support DXGI_FORMAT_R8G8_UNORM, so we have to use SNORM and correct values in shader if (!g_Windowing.IsFormatSupport(DXGI_FORMAT_R8G8_UNORM, D3D11_FORMAT_SUPPORT_TEXTURE2D)) defines["NV12_SNORM_UV"] = ""; break; - case SHADER_UYVY: + case BUFFER_FMT_UYVY422: defines["XBMC_UYVY"] = ""; - texWidth = sourceWidth >> 1; break; - case SHADER_YUY2: + case BUFFER_FMT_YUYV422: defines["XBMC_YUY2"] = ""; - texWidth = sourceWidth >> 1; break; default: return false; @@ -523,9 +520,6 @@ bool CYUV2RGBShader::Create(unsigned int sourceWidth, unsigned int sourceHeight, if (m_pOutShader) m_pOutShader->GetDefines(defines); - m_texSteps[0] = 1.0f/(float)texWidth; - m_texSteps[1] = 1.0f/(float)sourceHeight; - std::string effectString = "special://xbmc/system/shaders/yuv2rgb_d3d.fx"; if(!LoadEffect(effectString, &defines)) @@ -534,6 +528,7 @@ bool CYUV2RGBShader::Create(unsigned int sourceWidth, unsigned int sourceHeight, return false; } + CWinShader::CreateVertexBuffer(4, sizeof(CUSTOMVERTEX)); // Create input layout D3D11_INPUT_ELEMENT_DESC layout[] = { @@ -550,22 +545,17 @@ bool CYUV2RGBShader::Create(unsigned int sourceWidth, unsigned int sourceHeight, return true; } -void CYUV2RGBShader::Render(CRect sourceRect, CPoint dest[], - float contrast, - float brightness, - unsigned int flags, - YUVBuffer* YUVbuf) +void CYUV2RGBShader::Render(CRect sourceRect, CPoint dest[], float contrast, float brightness, SWinVideoBuffer* videoBuffer) { - PrepareParameters(sourceRect, dest, - contrast, brightness, flags); - SetShaderParameters(YUVbuf); + PrepareParameters(videoBuffer, sourceRect, dest, contrast, brightness); + SetShaderParameters(videoBuffer); Execute(nullptr, 4); } -CYUV2RGBShader::CYUV2RGBShader() : - m_sourceWidth(0) +CYUV2RGBShader::CYUV2RGBShader() + : m_sourceWidth(0) , m_sourceHeight(0) - , m_format(RENDER_FMT_NONE) + , m_format(BUFFER_FMT_NONE) , m_pOutShader(nullptr) { memset(&m_texSteps, 0, sizeof(m_texSteps)); @@ -575,19 +565,20 @@ CYUV2RGBShader::~CYUV2RGBShader() { } -void CYUV2RGBShader::PrepareParameters(CRect sourceRect, - CPoint dest[], - float contrast, - float brightness, - unsigned int flags) +void CYUV2RGBShader::PrepareParameters(SWinVideoBuffer* videoBuffer, CRect sourceRect, CPoint dest[], + float contrast, float brightness) { - if (m_sourceRect != sourceRect + if (m_sourceRect != sourceRect || m_dest[0] != dest[0] || m_dest[1] != dest[1] - || m_dest[2] != dest[2] || m_dest[3] != dest[3]) + || m_dest[2] != dest[2] || m_dest[3] != dest[3] + || videoBuffer->GetWidth() != m_sourceWidth + || videoBuffer->GetHeight() != m_sourceHeight) { m_sourceRect = sourceRect; for (size_t i = 0; i < 4; ++i) m_dest[i] = dest[i]; + m_sourceWidth = videoBuffer->GetWidth(); + m_sourceHeight = videoBuffer->GetHeight(); CUSTOMVERTEX* v; CWinShader::LockVertexBuffer(reinterpret_cast<void**>(&v)); @@ -627,23 +618,30 @@ void CYUV2RGBShader::PrepareParameters(CRect sourceRect, CWinShader::UnlockVertexBuffer(); } + unsigned int texWidth = m_sourceWidth; + if ( m_format == BUFFER_FMT_UYVY422 + || m_format == BUFFER_FMT_YUYV422) + texWidth = texWidth >> 1; + + m_texSteps[0] = 1.0f / texWidth; + m_texSteps[1] = 1.0f / m_sourceHeight; + m_matrix.SetParameters(contrast * 0.02f, brightness * 0.01f - 0.5f, - flags, + videoBuffer->flags, m_format); } -void CYUV2RGBShader::SetShaderParameters(YUVBuffer* YUVbuf) +void CYUV2RGBShader::SetShaderParameters(SWinVideoBuffer* videoBuffer) { m_effect.SetTechnique("YUV2RGB_T"); - SVideoPlane *planes = YUVbuf->planes; ID3D11ShaderResourceView* ppSRView[3] = { - planes[0].texture.GetShaderResource(), - planes[1].texture.GetShaderResource(), - planes[2].texture.GetShaderResource(), + reinterpret_cast<ID3D11ShaderResourceView*>(videoBuffer->GetView(0)), + reinterpret_cast<ID3D11ShaderResourceView*>(videoBuffer->GetView(1)), + reinterpret_cast<ID3D11ShaderResourceView*>(videoBuffer->GetView(2)), }; - m_effect.SetResources("g_Texture", ppSRView, YUVbuf->GetActivePlanes()); + m_effect.SetResources("g_Texture", ppSRView, videoBuffer->GetActivePlanes()); m_effect.SetMatrix("g_ColorMatrix", m_matrix.Matrix()); m_effect.SetFloatArray("g_StepXY", m_texSteps, ARRAY_SIZE(m_texSteps)); @@ -789,11 +787,9 @@ bool CConvolutionShader1Pass::Create(ESCALINGMETHOD method, COutputShader *pCLUT } void CConvolutionShader1Pass::Render(CD3DTexture &sourceTexture, - unsigned int sourceWidth, unsigned int sourceHeight, - unsigned int destWidth, unsigned int destHeight, - CRect sourceRect, - CRect destRect, - bool useLimitRange) + unsigned int sourceWidth, unsigned int sourceHeight, + unsigned int destWidth, unsigned int destHeight, + CRect sourceRect, CRect destRect, bool useLimitRange) { PrepareParameters(sourceWidth, sourceHeight, sourceRect, destRect); float texSteps[] = { 1.0f/(float)sourceWidth, 1.0f/(float)sourceHeight}; @@ -855,8 +851,8 @@ void CConvolutionShader1Pass::SetShaderParameters(CD3DTexture &sourceTexture, fl m_effect.SetFloatArray("g_viewPort", &viewPort.Width, 2); float colorRange[2] = { - (useLimitRange ? 16.f : 0.f) / 255.f, - (useLimitRange ? (235.f - 16.f) : 255.f) / 255.f, + (useLimitRange ? 16.f / 255.f : 0.f), + (useLimitRange ? 219.f / 255.f : 1.f), }; m_effect.SetFloatArray("g_colorRange", colorRange, _countof(colorRange)); if (m_pOutShader) @@ -938,11 +934,9 @@ bool CConvolutionShaderSeparable::Create(ESCALINGMETHOD method, COutputShader *p } void CConvolutionShaderSeparable::Render(CD3DTexture &sourceTexture, - unsigned int sourceWidth, unsigned int sourceHeight, - unsigned int destWidth, unsigned int destHeight, - CRect sourceRect, - CRect destRect, - bool useLimitRange) + unsigned int sourceWidth, unsigned int sourceHeight, + unsigned int destWidth, unsigned int destHeight, + CRect sourceRect, CRect destRect, bool useLimitRange) { if(m_destWidth != destWidth || m_sourceHeight != sourceHeight) CreateIntermediateRenderTarget(destWidth, sourceHeight); @@ -1105,8 +1099,8 @@ void CConvolutionShaderSeparable::SetShaderParameters(CD3DTexture &sourceTexture m_effect.SetFloatArray("g_StepXY", texSteps, texStepsCount); float colorRange[2] = { - (useLimitRange ? 16.f : 0.f) / 255.f, - (useLimitRange ? (235.f - 16.f) : 255.f) / 255.f, + (useLimitRange ? 16.f / 255.f : 0.f), + (useLimitRange ? 219.f / 255.f : 1.f) }; m_effect.SetFloatArray("g_colorRange", colorRange, _countof(colorRange)); if (m_pOutShader) diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.h b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.h index 770cfdcd5d..be3c6a8754 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/VideoShaders/WinVideoFilter.h @@ -20,7 +20,6 @@ * */ -#ifdef HAS_DX #include <vector> #include "../../guilib/Geometry.h" @@ -34,7 +33,7 @@ class CYUV2RGBMatrix { public: CYUV2RGBMatrix(); - void SetParameters(float contrast, float blacklevel, unsigned int flags, EShaderFormat format); + void SetParameters(float contrast, float blacklevel, unsigned int flags, EBufferFormat format); XMFLOAT4X4* Matrix(); private: @@ -43,7 +42,7 @@ private: float m_blacklevel; unsigned int m_flags; bool m_limitedRange; - EShaderFormat m_format; + EBufferFormat m_format; XMFLOAT4X4 m_mat; }; @@ -120,26 +119,22 @@ private: class CYUV2RGBShader : public CWinShader { public: - virtual bool Create(unsigned int sourceWidth, unsigned int sourceHeight, EShaderFormat fmt, COutputShader *pOutShader = nullptr); - virtual void Render(CRect sourceRect, CPoint dest[], float contrast, float brightness, - unsigned int flags, YUVBuffer* YUVbuf); CYUV2RGBShader(); virtual ~CYUV2RGBShader(); + virtual bool Create(EBufferFormat fmt, COutputShader *pOutShader = nullptr); + virtual void Render(CRect sourceRect, CPoint dest[], float contrast, float brightness, SWinVideoBuffer* videoBuffer); protected: - virtual void PrepareParameters(CRect sourceRect, - CPoint dest[], - float contrast, - float brightness, - unsigned int flags); - virtual void SetShaderParameters(YUVBuffer* YUVbuf); + void PrepareParameters(SWinVideoBuffer* videoBuffer, CRect sourceRect, CPoint dest[], + float contrast, float brightness); + void SetShaderParameters(SWinVideoBuffer* videoBuffer); private: CYUV2RGBMatrix m_matrix; unsigned int m_sourceWidth, m_sourceHeight; CRect m_sourceRect; CPoint m_dest[4]; - EShaderFormat m_format; + EBufferFormat m_format; float m_texSteps[2]; COutputShader *m_pOutShader; @@ -236,5 +231,3 @@ class CTestShader : public CWinShader public: virtual bool Create(); }; - -#endif diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderer.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderer.cpp index 1c5f8f3e1e..4664d65857 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderer.cpp +++ b/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderer.cpp @@ -47,7 +47,7 @@ static RenderMethodDetail RenderMethodDetails[] = { { RENDER_SW , "Software" }, { RENDER_PS , "Pixel Shaders" }, { RENDER_DXVA , "DXVA" }, - { RENDER_INVALID, NULL } + { RENDER_INVALID, nullptr } }; static RenderMethodDetail *FindRenderMethod(RenderMethod m) @@ -71,6 +71,8 @@ bool CWinRenderer::Register() } CWinRenderer::CWinRenderer() + : m_frameIdx(0) + , m_bufferFormat(BUFFER_FMT_NONE) { m_iYV12RenderBuffer = 0; m_NumYV12Buffers = 0; @@ -83,12 +85,12 @@ CWinRenderer::CWinRenderer() m_renderMethod = RENDER_PS; m_scalingMethod = VS_SCALINGMETHOD_LINEAR; - m_scalingMethodGui = (ESCALINGMETHOD)-1; + m_scalingMethodGui = static_cast<ESCALINGMETHOD>(-1); m_bUseHQScaler = false; m_bFilterInitialized = false; - for (int i = 0; i<NUM_BUFFERS; i++) + for (int i = 0; i < NUM_BUFFERS; i++) m_VideoBuffers[i] = nullptr; m_sw_scale_ctx = nullptr; @@ -132,70 +134,91 @@ void CWinRenderer::ManageTextures() void CWinRenderer::SelectRenderMethod() { - // Set rendering to dxva before trying it, in order to open the correct processor immediately, when deinterlacing method is auto. + EBufferFormat dxFormat = SelectBufferFormat(m_format, RENDER_DXVA); + EBufferFormat psFormat = SelectBufferFormat(m_format, RENDER_PS); + // modern drivers allow using HW pic in shaders + bool allowChangeMethod = dxFormat == psFormat; - // Force dxva renderer after dxva decoding: PS and SW renderers have performance issues after dxva decode. - if (g_advancedSettings.m_DXVAForceProcessorRenderer && m_format == AV_PIX_FMT_D3D11VA_VLD) + // old drivers + HW decoded picture -> we must force DXVA render method + if (!allowChangeMethod && m_format == AV_PIX_FMT_D3D11VA_VLD) { - CLog::Log(LOGNOTICE, "D3D: rendering method forced to DXVA processor"); + CLog::Log(LOGNOTICE, "%s: rendering method forced to DXVA processor.", __FUNCTION__); m_renderMethod = RENDER_DXVA; - if (!m_processor || !m_processor->Open(m_sourceWidth, m_sourceHeight, m_iFlags, m_format, m_dxva_format)) + if (!m_processor || !m_processor->Open(m_sourceWidth, m_sourceHeight)) { - CLog::Log(LOGNOTICE, "D3D: unable to open DXVA processor"); - if (m_processor) + CLog::Log(LOGNOTICE, "%s: unable to open DXVA processor.", __FUNCTION__); + if (m_processor) m_processor->Close(); m_renderMethod = RENDER_INVALID; } } else { - CLog::Log(LOGDEBUG, __FUNCTION__": Requested render method: %d", m_iRequestedMethod); - - switch(m_iRequestedMethod) + CLog::Log(LOGDEBUG, "%s: requested render method: %d", __FUNCTION__, m_iRequestedMethod); + switch (m_iRequestedMethod) { - case RENDER_METHOD_DXVA: - if (!m_processor || !m_processor->Open(m_sourceWidth, m_sourceHeight, m_iFlags, m_format, m_dxva_format)) - { - CLog::Log(LOGNOTICE, "D3D: unable to open DXVA processor"); - if (m_processor) - m_processor->Close(); - } - else + case RENDER_METHOD_DXVA: + { + // skip if format isn't DXVA compatible. + if (dxFormat >= BUFFER_FMT_DXVA_BYPASS) + { + if (m_processor && m_processor->Open(m_sourceWidth, m_sourceHeight)) { m_renderMethod = RENDER_DXVA; break; } - // Drop through to pixel shader - case RENDER_METHOD_AUTO: - case RENDER_METHOD_D3D_PS: + allowChangeMethod = false; + CLog::Log(LOGNOTICE, "%s: unable to open DXVA processor.", __FUNCTION__); + if (m_processor) + m_processor->Close(); + } + } + // fallback to auto + case RENDER_METHOD_AUTO: + if (allowChangeMethod) + { + // for modern drivers select method depends on input + // for HW decoded or interlaced picture prefer DXVA method. + if (m_format == RENDER_FMT_DXVA || m_iFlags & DVP_FLAG_INTERLACED) { - CTestShader shader; - if (shader.Create()) + if (m_processor && m_processor->Open(m_sourceWidth, m_sourceHeight)) { - m_renderMethod = RENDER_PS; - if (m_format == AV_PIX_FMT_D3D11VA_VLD) - m_format = AV_PIX_FMT_NV12; + m_renderMethod = RENDER_DXVA; break; } - else - { - CLog::Log(LOGNOTICE, "D3D: unable to load test shader - D3D installation is most likely incomplete"); - CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, "DirectX", g_localizeStrings.Get(2101)); - } - CLog::Log(LOGNOTICE, "D3D: falling back to SW mode"); + CLog::Log(LOGNOTICE, "%s: unable to open DXVA processor", __FUNCTION__); + if (m_processor) + m_processor->Close(); } - // drop through to software - case RENDER_METHOD_SOFTWARE: - default: - // So we'll do the color conversion in software. - m_renderMethod = RENDER_SW; + } + // drop through to pixel shader + case RENDER_METHOD_D3D_PS: + { + CTestShader shader; + if (shader.Create()) + { + m_renderMethod = RENDER_PS; break; + } + // this is something out of the ordinary + CLog::Log(LOGNOTICE, "%s: unable to load test shader - D3D installation is most likely incomplete, falling back to SW mode.", __FUNCTION__); + CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, "DirectX", g_localizeStrings.Get(2101)); + } + // drop through to software + case RENDER_METHOD_SOFTWARE: + default: + // so we'll do the color conversion in software. + m_renderMethod = RENDER_SW; + break; } } - RenderMethodDetail *rmdet = FindRenderMethod(m_renderMethod); - CLog::Log(LOGDEBUG, __FUNCTION__": Selected render method %d: %s", m_renderMethod, rmdet != nullptr ? rmdet->name : "unknown"); + m_bufferFormat = SelectBufferFormat(m_format, m_renderMethod); m_frameIdx = 0; + + RenderMethodDetail *rmdet = FindRenderMethod(m_renderMethod); + CLog::Log(LOGDEBUG, "%s: selected render method %d: %s", __FUNCTION__, m_renderMethod, rmdet != nullptr ? rmdet->name : "unknown"); + CLog::Log(LOGDEBUG, "%s: selected buffer format %d", __FUNCTION__, m_bufferFormat); } bool CWinRenderer::Configure(const VideoPicture &picture, float fps, unsigned flags, unsigned int orientation) @@ -232,12 +255,11 @@ bool CWinRenderer::Configure(const VideoPicture &picture, float fps, unsigned fl return true; } -int CWinRenderer::NextYV12Texture() +int CWinRenderer::NextYV12Texture() const { if(m_NumYV12Buffers) return (m_iYV12RenderBuffer + 1) % m_NumYV12Buffers; - else - return -1; + return -1; } void CWinRenderer::AddVideoPicture(const VideoPicture &picture, int index, double currentClock) @@ -246,23 +268,10 @@ void CWinRenderer::AddVideoPicture(const VideoPicture &picture, int index, doubl if (!m_VideoBuffers[index]) return; - if (m_renderMethod == RENDER_DXVA) - { - DXVABuffer *buf = reinterpret_cast<DXVABuffer*>(m_VideoBuffers[index]); - SAFE_RELEASE(buf->pic); - buf->pic = m_processor->Convert(picture); - buf->frameIdx = m_frameIdx; - buf->pictureFlags = picture.iFlags; - m_frameIdx += 2; - } - else - { - YUVBuffer *buf = reinterpret_cast<YUVBuffer*>(m_VideoBuffers[index]); - if (buf->IsReadyToRender()) - return; - - buf->CopyFromPicture(picture); - } + m_VideoBuffers[index]->ReleaseHWPicture(); + m_VideoBuffers[index]->ApplyPicture(picture); + m_VideoBuffers[index]->frameIdx = m_frameIdx; + m_frameIdx += 2; m_VideoBuffers[index]->videoBuffer = picture.videoBuffer; m_VideoBuffers[index]->videoBuffer->Acquire(); } @@ -305,8 +314,6 @@ void CWinRenderer::FlipPage(int source) if (m_iYV12RenderBuffer >= 0 && m_VideoBuffers[m_iYV12RenderBuffer] != nullptr) m_VideoBuffers[m_iYV12RenderBuffer]->StartRender(); - - return; } void CWinRenderer::PreInit() @@ -317,15 +324,11 @@ void CWinRenderer::PreInit() m_iRequestedMethod = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_VIDEOPLAYER_RENDERMETHOD); - if (g_advancedSettings.m_DXVAForceProcessorRenderer - || m_iRequestedMethod == RENDER_METHOD_DXVA) + m_processor = new DXVA::CProcessorHD(); + if (!m_processor->PreInit()) { - m_processor = new DXVA::CProcessorHD(); - if (!m_processor->PreInit()) - { - CLog::Log(LOGNOTICE, "CWinRenderer::Preinit - could not init DXVA processor - skipping"); - SAFE_DELETE(m_processor); - } + CLog::Log(LOGNOTICE, "%: - could not init DXVA processor - skipping.", __FUNCTION__); + SAFE_DELETE(m_processor); } } @@ -394,16 +397,77 @@ bool CWinRenderer::CreateIntermediateRenderTarget(unsigned int width, unsigned i if (m_IntermediateTarget.Get()) m_IntermediateTarget.Release(); - CLog::Log(LOGDEBUG, __FUNCTION__": format %i", format); + CLog::Log(LOGDEBUG, "%s: format %i.", __FUNCTION__, format); if (!m_IntermediateTarget.Create(width, height, 1, dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT, format)) { - CLog::Log(LOGERROR, __FUNCTION__": intermediate render target creation failed."); + CLog::Log(LOGERROR, "%s: intermediate render target creation failed.", __FUNCTION__); return false; } return true; } +EBufferFormat CWinRenderer::SelectBufferFormat(const ERenderFormat format, const RenderMethod method) const +{ + EBufferFormat buffer_format = BUFFER_FMT_NONE; + if (m_format == RENDER_FMT_DXVA) buffer_format = BUFFER_FMT_YUV420P; + if (m_format == RENDER_FMT_NV12) buffer_format = BUFFER_FMT_YUV420P; + if (m_format == RENDER_FMT_YUV420P) buffer_format = BUFFER_FMT_YUV420P; + if (m_format == RENDER_FMT_YUV420P10) buffer_format = BUFFER_FMT_YUV420P10; + if (m_format == RENDER_FMT_YUV420P16) buffer_format = BUFFER_FMT_YUV420P16; + // is they still used? + if (m_format == RENDER_FMT_YUYV422) buffer_format = BUFFER_FMT_YUYV422; + if (m_format == RENDER_FMT_UYVY422) buffer_format = BUFFER_FMT_UYVY422; + + if (method == RENDER_SW) + return buffer_format; + + ID3D11Device* pDevice = g_Windowing.Get3D11Device(); + CD3D11_TEXTURE2D_DESC texDesc(DXGI_FORMAT_UNKNOWN, + m_sourceWidth, m_sourceHeight, 1, 1, + D3D11_BIND_SHADER_RESOURCE, + D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); + if (method == RENDER_DXVA) + texDesc.BindFlags |= D3D11_BIND_DECODER; + + switch (format) + { + case RENDER_FMT_NV12: + case RENDER_FMT_YUV420P: + case RENDER_FMT_YUV420P10: + case RENDER_FMT_YUV420P16: + { + texDesc.Format = DXGI_FORMAT_NV12; + if (m_format == RENDER_FMT_YUV420P10) texDesc.Format = DXGI_FORMAT_P010; + if (m_format == RENDER_FMT_YUV420P16) texDesc.Format = DXGI_FORMAT_P016; + + if (SUCCEEDED(pDevice->CreateTexture2D(&texDesc, nullptr, nullptr))) + { + buffer_format = BUFFER_FMT_DXVA_NV12; + if (m_format == RENDER_FMT_YUV420P10) buffer_format = BUFFER_FMT_DXVA_P010; + if (m_format == RENDER_FMT_YUV420P16) buffer_format = BUFFER_FMT_DXVA_P016; + } + return buffer_format; + } + case RENDER_FMT_DXVA: + { + texDesc.Format = m_dxva_format; + texDesc.Usage = D3D11_USAGE_DEFAULT; + texDesc.CPUAccessFlags = 0; + + if (method == RENDER_DXVA || SUCCEEDED(pDevice->CreateTexture2D(&texDesc, nullptr, nullptr))) + return BUFFER_FMT_DXVA_BYPASS; + + if (m_dxva_format == DXGI_FORMAT_P010) + return BUFFER_FMT_YUV420P10; + if (m_dxva_format == DXGI_FORMAT_P016) + return BUFFER_FMT_YUV420P16; + } + default: + return buffer_format; + } +} + void CWinRenderer::SelectSWVideoFilter() { CreateIntermediateRenderTarget(m_sourceWidth, m_sourceHeight, true); @@ -449,7 +513,8 @@ void CWinRenderer::SelectPSVideoFilter() if (m_scalingMethod == VS_SCALINGMETHOD_AUTO) { bool scaleSD = m_sourceHeight < 720 && m_sourceWidth < 1280; - bool scaleUp = (int)m_sourceHeight < g_graphicsContext.GetHeight() && (int)m_sourceWidth < g_graphicsContext.GetWidth(); + bool scaleUp = static_cast<int>(m_sourceHeight) < g_graphicsContext.GetHeight() + && static_cast<int>(m_sourceWidth) < g_graphicsContext.GetWidth(); bool scaleFps = m_fps < (g_advancedSettings.m_videoAutoScaleMaxFps + 0.01f); if (m_renderMethod == RENDER_DXVA) @@ -479,7 +544,7 @@ void CWinRenderer::UpdatePSVideoFilter() if (!m_scalerShader->Create(m_scalingMethod, m_outputShader)) { SAFE_DELETE(m_scalerShader); - CLog::Log(LOGNOTICE, __FUNCTION__": two pass convolution shader init problem, falling back to one pass."); + CLog::Log(LOGNOTICE, "%s: two pass convolution shader init problem, falling back to one pass.", __FUNCTION__); } // Fallback on the one pass version @@ -514,8 +579,7 @@ void CWinRenderer::UpdatePSVideoFilter() } m_colorShader = new CYUV2RGBShader(); - EShaderFormat shaderFormat = GetShaderFormat(); - if (!m_colorShader->Create(m_sourceWidth, m_sourceHeight, shaderFormat, m_bUseHQScaler ? nullptr : m_outputShader)) + if (!m_colorShader->Create(m_bufferFormat, m_bUseHQScaler ? nullptr : m_outputShader)) { if (m_bUseHQScaler) { @@ -541,11 +605,8 @@ void CWinRenderer::UpdateVideoFilter() bool cmsChanged = m_cmsOn != m_colorManager->IsEnabled() || m_cmsOn && !m_colorManager->CheckConfiguration(m_cmsToken, m_iFlags); if (m_scalingMethodGui == CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ScalingMethod - && m_bFilterInitialized - && !cmsChanged) - { + && m_bFilterInitialized && !cmsChanged) return; - } m_bFilterInitialized = true; m_scalingMethodGui = CMediaSettings::GetInstance().GetCurrentVideoSettings().m_ScalingMethod; @@ -553,14 +614,12 @@ void CWinRenderer::UpdateVideoFilter() if (!Supports(m_scalingMethod)) { - CLog::Log(LOGWARNING, __FUNCTION__" - chosen scaling method %d is not supported by renderer", (int)m_scalingMethod); + CLog::Log(LOGWARNING, "%s: chosen scaling method %d is not supported by renderer", __FUNCTION__, static_cast<int>(m_scalingMethod)); m_scalingMethod = VS_SCALINGMETHOD_AUTO; } if (cmsChanged) - { ColorManagmentUpdate(); - } if (cmsChanged || !m_outputShader) { @@ -643,26 +702,17 @@ void CWinRenderer::RenderSW() m_sourceWidth, m_sourceHeight, AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); - YUVBuffer* buf = reinterpret_cast<YUVBuffer*>(m_VideoBuffers[m_iYV12RenderBuffer]); + SWinVideoBuffer* buf = m_VideoBuffers[m_iYV12RenderBuffer]; - D3D11_MAPPED_SUBRESOURCE srclr[3]; - uint8_t* src[3]; - int srcStride[3]; + uint8_t* src[MAX_PLANES]; + int srcStride[MAX_PLANES]; for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++) - { - if(!(buf->planes[idx].texture.LockRect(0, &srclr[idx], D3D11_MAP_READ))) - CLog::Log(LOGERROR, __FUNCTION__" - failed to lock yuv textures into memory"); - else - { - src[idx] = (uint8_t*)srclr[idx].pData; - srcStride[idx] = srclr[idx].RowPitch; - } - } + buf->MapPlane(idx, reinterpret_cast<void**>(&src[idx]), &srcStride[idx]); D3D11_MAPPED_SUBRESOURCE destlr; if (!m_IntermediateTarget.LockRect(0, &destlr, D3D11_MAP_WRITE_DISCARD)) - CLog::Log(LOGERROR, __FUNCTION__" - failed to lock swtarget texture into memory"); + CLog::Log(LOGERROR, "%s: failed to lock swtarget texture into memory.", __FUNCTION__); uint8_t *dst[] = { static_cast<uint8_t*>(destlr.pData), nullptr, nullptr }; int dstStride[] = { static_cast<int>(destlr.RowPitch), 0, 0 }; @@ -670,11 +720,10 @@ void CWinRenderer::RenderSW() sws_scale(m_sw_scale_ctx, src, srcStride, 0, m_sourceHeight, dst, dstStride); for (unsigned int idx = 0; idx < buf->GetActivePlanes(); idx++) - if(!(buf->planes[idx].texture.UnlockRect(0))) - CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock yuv textures"); + buf->UnmapPlane(idx); if (!m_IntermediateTarget.UnlockRect(0)) - CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock swtarget texture"); + CLog::Log(LOGERROR, "%s: failed to unlock swtarget texture.", __FUNCTION__); // 2. output to display @@ -685,7 +734,7 @@ void CWinRenderer::RenderSW() void CWinRenderer::RenderPS() { - CD3D11_VIEWPORT viewPort(0.0f, 0.0f, 0.0f, 0.0f); + CD3D11_VIEWPORT viewPort; ID3D11DeviceContext* pContext = g_Windowing.Get3D11Context(); ID3D11RenderTargetView *oldRTView = nullptr; ID3D11DepthStencilView* oldDSView = nullptr; @@ -730,7 +779,7 @@ void CWinRenderer::RenderPS() m_colorShader->Render(m_sourceRect, destPoints, CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Contrast, CMediaSettings::GetInstance().GetCurrentVideoSettings().m_Brightness, - m_iFlags, reinterpret_cast<YUVBuffer*>(m_VideoBuffers[m_iYV12RenderBuffer])); + m_VideoBuffers[m_iYV12RenderBuffer]); // Restore our view port. g_Windowing.RestoreViewPort(); // Restore the render target and depth view. @@ -751,17 +800,22 @@ void CWinRenderer::RenderHQ() void CWinRenderer::RenderHW(DWORD flags) { - DXVABuffer *image = reinterpret_cast<DXVABuffer*>(m_VideoBuffers[m_iYV12RenderBuffer]); - if (!image->pic) + SWinVideoBuffer *image = m_VideoBuffers[m_iYV12RenderBuffer]; + if (image->format != BUFFER_FMT_DXVA_BYPASS + && image->format != BUFFER_FMT_DXVA_NV12 + && image->format != BUFFER_FMT_DXVA_P010 + && image->format != BUFFER_FMT_DXVA_P016) return; + if (!image->HasPic()) + return; + int past = 0; int future = 0; - DXVABuffer **buffers = reinterpret_cast<DXVABuffer**>(m_VideoBuffers); - ID3D11View* views[8]; - memset(views, 0, 8 * sizeof(ID3D11View*)); - views[2] = image->pic->view; + SWinVideoBuffer* views[8]; + memset(views, 0, 8 * sizeof(SWinVideoBuffer*)); + views[2] = image; // set future frames while (future < 2) @@ -769,9 +823,10 @@ void CWinRenderer::RenderHW(DWORD flags) bool found = false; for (int i = 0; i < m_NumYV12Buffers; i++) { - if (buffers[i] && buffers[i]->pic && buffers[i]->frameIdx == image->frameIdx + (future*2 + 2)) + if (m_VideoBuffers[i] && m_VideoBuffers[i]->HasPic() + && m_VideoBuffers[i]->frameIdx == image->frameIdx + (future*2 + 2)) { - views[1 - future++] = buffers[i]->pic->view; + views[1 - future++] = m_VideoBuffers[i]; found = true; break; } @@ -786,9 +841,10 @@ void CWinRenderer::RenderHW(DWORD flags) bool found = false; for (int i = 0; i < m_NumYV12Buffers; i++) { - if (buffers[i] && buffers[i]->pic && buffers[i]->frameIdx == image->frameIdx - (past*2 + 2)) + if (m_VideoBuffers[i] && m_VideoBuffers[i]->HasPic() + && m_VideoBuffers[i]->frameIdx == image->frameIdx - (past*2 + 2)) { - views[3 + past++] = buffers[i]->pic->view; + views[3 + past++] = m_VideoBuffers[i]; found = true; break; } @@ -886,7 +942,7 @@ bool CWinRenderer::RenderCapture(CRenderCapture* capture) CRect saveSize = m_destRect; saveRotatedCoords();//backup current m_rotatedDestCoords - m_destRect.SetRect(0, 0, (float)capture->GetWidth(), (float)capture->GetHeight()); + m_destRect.SetRect(0, 0, static_cast<float>(capture->GetWidth()), static_cast<float>(capture->GetHeight())); syncDestRectToRotatedPoints();//syncs the changed destRect to m_rotatedDestCoords ID3D11DepthStencilView* oldDepthView; @@ -928,26 +984,17 @@ bool CWinRenderer::CreateYV12Texture(int index) CSingleLock lock(g_graphicsContext); DeleteYV12Texture(index); - if (m_renderMethod == RENDER_DXVA) - { - m_VideoBuffers[index] = new DXVABuffer(); - } - else + m_VideoBuffers[index] = new SWinVideoBuffer(); + if (!m_VideoBuffers[index]->CreateBuffer(m_bufferFormat, m_sourceWidth, m_sourceHeight, m_renderMethod == RENDER_SW)) { - YUVBuffer *buf = new YUVBuffer(); - if (!buf->Create(m_format, m_sourceWidth, m_sourceHeight, m_renderMethod == RENDER_PS)) - { - CLog::Log(LOGERROR, __FUNCTION__" - Unable to create YV12 video texture %i", index); - delete buf; - return false; - } - m_VideoBuffers[index] = buf; + CLog::Log(LOGERROR, "%s: unable to create video buffer %i", __FUNCTION__, index); + SAFE_DELETE(m_VideoBuffers[index]); + return false; } - m_VideoBuffers[index]->StartDecode(); m_VideoBuffers[index]->Clear(); - CLog::Log(LOGDEBUG, "created video buffer %i", index); + CLog::Log(LOGDEBUG, "%s: created video buffer %i", __FUNCTION__, index); return true; } @@ -968,7 +1015,6 @@ bool CWinRenderer::Supports(ERENDERFEATURE feature) feature == RENDERFEATURE_POSTPROCESS) return true; - return false; } @@ -999,8 +1045,8 @@ bool CWinRenderer::Supports(ESCALINGMETHOD method) || method == VS_SCALINGMETHOD_LANCZOS3) { // if scaling is below level, avoid hq scaling - float scaleX = fabs(((float)m_sourceWidth - m_destRect.Width())/m_sourceWidth)*100; - float scaleY = fabs(((float)m_sourceHeight - m_destRect.Height())/m_sourceHeight)*100; + float scaleX = fabs((static_cast<float>(m_sourceWidth) - m_destRect.Width())/m_sourceWidth)*100; + float scaleY = fabs((static_cast<float>(m_sourceHeight) - m_destRect.Height())/m_sourceHeight)*100; int minScale = CServiceBroker::GetSettings().GetInt(CSettings::SETTING_VIDEOPLAYER_HQSCALERS); if (scaleX < minScale && scaleY < minScale) return false; @@ -1058,7 +1104,8 @@ CRenderInfo CWinRenderer::GetRenderInfo() info.max_buffer_size = NUM_BUFFERS; if (m_renderMethod == RENDER_DXVA && m_processor) { - info.optimal_buffer_size = m_processor->Size(); + int buffers = m_processor->Size() + m_processor->PastRefs(); // extra buffers for past refs + info.optimal_buffer_size = std::min(NUM_BUFFERS, buffers); if (m_format != AV_PIX_FMT_D3D11VA_VLD) info.m_deintMethods.push_back(VS_INTERLACEMETHOD_DXVA_AUTO); } @@ -1073,7 +1120,7 @@ void CWinRenderer::ReleaseBuffer(int idx) SAFE_RELEASE(m_VideoBuffers[idx]->videoBuffer); if (m_renderMethod == RENDER_DXVA && m_VideoBuffers[idx]) - SAFE_RELEASE(reinterpret_cast<DXVABuffer*>(m_VideoBuffers[idx])->pic); + m_VideoBuffers[idx]->ReleaseHWPicture(); } bool CWinRenderer::NeedBuffer(int idx) @@ -1081,13 +1128,10 @@ bool CWinRenderer::NeedBuffer(int idx) // check if processor wants to keep past frames if (m_renderMethod == RENDER_DXVA && m_processor) { - DXVABuffer** buffers = reinterpret_cast<DXVABuffer**>(m_VideoBuffers); - int numPast = m_processor->PastRefs(); - if (buffers[idx] && buffers[idx]->pic && - (buffers[idx]->pictureFlags & DVP_FLAG_INTERLACED)) + if (m_VideoBuffers[idx] && m_VideoBuffers[idx]->HasPic()) { - if (buffers[idx]->frameIdx + numPast*2 >= buffers[m_iYV12RenderBuffer]->frameIdx) + if (m_VideoBuffers[idx]->frameIdx + numPast*2 >= m_VideoBuffers[m_iYV12RenderBuffer]->frameIdx) return true; } } @@ -1132,339 +1176,3 @@ bool CWinRenderer::LoadCLUT() free(pCLUT); return true; } - - -//============================================ - -YUVBuffer::~YUVBuffer() -{ - Release(); -} - -bool YUVBuffer::Create(AVPixelFormat format, unsigned int width, unsigned int height, bool dynamic) -{ - m_format = format; - m_width = width; - m_height = height; - m_mapType = dynamic ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE; - // Create the buffers with D3D11_USAGE_DYNAMIC which can be used as shader resource for PS rendering - // or D3D11_USAGE_STAGING which can be read and written for SW rendering - D3D11_USAGE usage = dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_STAGING; - - switch(m_format) - { - case AV_PIX_FMT_YUV420P10: - case AV_PIX_FMT_YUV420P16: - { - if ( !planes[PLANE_Y].texture.Create(m_width, m_height, 1, usage, DXGI_FORMAT_R16_UNORM) - || !planes[PLANE_U].texture.Create(m_width >> 1, m_height >> 1, 1, usage, DXGI_FORMAT_R16_UNORM) - || !planes[PLANE_V].texture.Create(m_width >> 1, m_height >> 1, 1, usage, DXGI_FORMAT_R16_UNORM)) - return false; - m_activeplanes = 3; - break; - } - case AV_PIX_FMT_YUV420P: - { - if ( !planes[PLANE_Y].texture.Create(m_width, m_height, 1, usage, DXGI_FORMAT_R8_UNORM) - || !planes[PLANE_U].texture.Create(m_width >> 1, m_height >> 1, 1, usage, DXGI_FORMAT_R8_UNORM) - || !planes[PLANE_V].texture.Create(m_width >> 1, m_height >> 1, 1, usage, DXGI_FORMAT_R8_UNORM)) - return false; - m_activeplanes = 3; - break; - } - case AV_PIX_FMT_D3D11VA_VLD: - case AV_PIX_FMT_NV12: - { - DXGI_FORMAT uvFormat = DXGI_FORMAT_R8G8_UNORM; - // FL 9.x doesn't support DXGI_FORMAT_R8G8_UNORM, so we have to use SNORM and correct values in shader - if (!g_Windowing.IsFormatSupport(uvFormat, D3D11_FORMAT_SUPPORT_TEXTURE2D)) - uvFormat = DXGI_FORMAT_R8G8_SNORM; - if ( !planes[PLANE_Y].texture.Create( m_width, m_height, 1, usage, DXGI_FORMAT_R8_UNORM) - || !planes[PLANE_UV].texture.Create(m_width >> 1, m_height >> 1, 1, usage, uvFormat)) - return false; - m_activeplanes = 2; - break; - } - case AV_PIX_FMT_YUYV422: - { - if ( !planes[PLANE_Y].texture.Create(m_width >> 1, m_height, 1, usage, DXGI_FORMAT_B8G8R8A8_UNORM)) - return false; - m_activeplanes = 1; - break; - } - case AV_PIX_FMT_UYVY422: - { - if ( !planes[PLANE_Y].texture.Create(m_width >> 1, m_height, 1, usage, DXGI_FORMAT_B8G8R8A8_UNORM)) - return false; - m_activeplanes = 1; - break; - } - default: - m_activeplanes = 0; - return false; - } - - return true; -} - -void YUVBuffer::Release() -{ - SAFE_RELEASE(m_staging); - for(unsigned i = 0; i < m_activeplanes; i++) - { - // unlock before release - if (m_locked && planes[i].texture.Get() && planes[i].rect.pData) - planes[i].texture.UnlockRect(0); - - planes[i].texture.Release(); - memset(&planes[i].rect, 0, sizeof(planes[i].rect)); - } -} - -void YUVBuffer::StartRender() -{ - if (!m_locked) - return; - - if (m_bPending) - { - PerformCopy(); - m_bPending = false; - } - - m_locked = false; - - for (unsigned i = 0; i < m_activeplanes; i++) - { - if (planes[i].texture.Get() && planes[i].rect.pData) - if (!planes[i].texture.UnlockRect(0)) - CLog::Log(LOGERROR, __FUNCTION__" - failed to unlock texture %d", i); - memset(&planes[i].rect, 0, sizeof(planes[i].rect)); - } -} - -void YUVBuffer::StartDecode() -{ - if (m_locked) - return; - - m_locked = true; - m_bPending = false; - - for(unsigned i = 0; i < m_activeplanes; i++) - { - if(planes[i].texture.Get() - && planes[i].texture.LockRect(0, &planes[i].rect, m_mapType) == false) - { - memset(&planes[i].rect, 0, sizeof(planes[i].rect)); - CLog::Log(LOGERROR, __FUNCTION__" - failed to lock texture %d into memory", i); - m_locked = false; - } - } -} - -void YUVBuffer::Clear() -{ - // Set Y to 0 and U,V to 128 (RGB 0,0,0) to avoid visual artifacts at the start of playback - - switch(m_format) - { - case AV_PIX_FMT_YUV420P16: - { - wmemset((wchar_t*)planes[PLANE_Y].rect.pData, 0, planes[PLANE_Y].rect.RowPitch * m_height / 2); - wmemset((wchar_t*)planes[PLANE_U].rect.pData, 32768, planes[PLANE_U].rect.RowPitch * (m_height / 2) / 2); - wmemset((wchar_t*)planes[PLANE_V].rect.pData, 32768, planes[PLANE_V].rect.RowPitch * (m_height / 2) / 2); - break; - } - case AV_PIX_FMT_YUV420P10: - { - wmemset((wchar_t*)planes[PLANE_Y].rect.pData, 0, planes[PLANE_Y].rect.RowPitch * m_height / 2); - wmemset((wchar_t*)planes[PLANE_U].rect.pData, 512, planes[PLANE_U].rect.RowPitch * (m_height / 2) / 2); - wmemset((wchar_t*)planes[PLANE_V].rect.pData, 512, planes[PLANE_V].rect.RowPitch * (m_height / 2) / 2); - break; - } - case AV_PIX_FMT_YUV420P: - { - memset(planes[PLANE_Y].rect.pData, 0, planes[PLANE_Y].rect.RowPitch * m_height); - memset(planes[PLANE_U].rect.pData, 128, planes[PLANE_U].rect.RowPitch * (m_height / 2)); - memset(planes[PLANE_V].rect.pData, 128, planes[PLANE_V].rect.RowPitch * (m_height / 2)); - break; - } - case AV_PIX_FMT_D3D11VA_VLD: - case AV_PIX_FMT_NV12: - { - memset(planes[PLANE_Y].rect.pData, 0, planes[PLANE_Y].rect.RowPitch * m_height); - memset(planes[PLANE_UV].rect.pData, 128, planes[PLANE_U].rect.RowPitch * (m_height / 2)); - break; - } - // YUY2, UYVY: wmemset to set a 16bit pattern, byte-swapped because x86 is LE - case AV_PIX_FMT_YUYV422: - { - wmemset((wchar_t*)planes[PLANE_Y].rect.pData, 0x8000, planes[PLANE_Y].rect.RowPitch / 2 * m_height); - break; - } - case AV_PIX_FMT_UYVY422: - { - wmemset((wchar_t*)planes[PLANE_Y].rect.pData, 0x0080, planes[PLANE_Y].rect.RowPitch / 2 * m_height); - break; - } - - } -} - -bool YUVBuffer::IsReadyToRender() -{ - return !m_locked; -} - -bool YUVBuffer::CopyFromPicture(const VideoPicture &picture) -{ - AVPixelFormat format = picture.videoBuffer->GetFormat(); - if (format == AV_PIX_FMT_D3D11VA_VLD) - { - DXVA::CDXVAVideoBuffer *hwpic = static_cast<DXVA::CDXVAVideoBuffer*>(picture.videoBuffer); - return CopyFromDXVA(reinterpret_cast<ID3D11VideoDecoderOutputView*>(hwpic->picture->view)); - } - - if ( format == AV_PIX_FMT_YUV420P - || format == AV_PIX_FMT_YUV420P10 - || format == AV_PIX_FMT_YUV420P16 - || format == AV_PIX_FMT_NV12) - { - uint8_t* bufData[3]; - int srcLines[3]; - picture.videoBuffer->GetPlanes(bufData); - picture.videoBuffer->GetStrides(srcLines); - std::vector<Concurrency::task<void>> tasks; - - for(unsigned plane = 0; plane < m_activeplanes; ++plane) - { - uint8_t* dst = static_cast<uint8_t*>(planes[plane].rect.pData); - uint8_t* src = bufData[plane]; - int srcLine = srcLines[plane]; - int dstLine = planes[plane].rect.RowPitch; - int height = plane == 0 ? picture.iHeight : picture.iHeight >> 1; - - auto task = Concurrency::create_task([src, dst, srcLine, dstLine, height]() - { - if (srcLine == dstLine) - { - memcpy(dst, src, srcLine * height); - } - else - { - uint8_t* s = src; - uint8_t* d = dst; - for(unsigned i = 0; i < height; ++i) - { - memcpy(d, s, std::min(srcLine, dstLine)); - d += dstLine; - s += srcLine; - } - } - }); - tasks.push_back(task); - } - - when_all(tasks.begin(), tasks.end()).wait();//.then([this]() { StartRender(); }); - return true; - } - return false; -} - -bool YUVBuffer::CopyFromDXVA(ID3D11VideoDecoderOutputView* pView) -{ - if (!pView) - return false; - - HRESULT hr = S_OK; - D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC vpivd; - pView->GetDesc(&vpivd); - ID3D11Resource* resource = nullptr; - pView->GetResource(&resource); - - if (!m_staging) - { - // create staging texture - ID3D11Texture2D* surface = nullptr; - hr = resource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&surface)); - if (SUCCEEDED(hr)) - { - D3D11_TEXTURE2D_DESC tDesc; - surface->GetDesc(&tDesc); - SAFE_RELEASE(surface); - - CD3D11_TEXTURE2D_DESC sDesc(tDesc); - sDesc.ArraySize = 1; - sDesc.Usage = D3D11_USAGE_STAGING; - sDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - sDesc.BindFlags = 0; - - hr = g_Windowing.Get3D11Device()->CreateTexture2D(&sDesc, nullptr, &m_staging); - if (SUCCEEDED(hr)) - m_sDesc = sDesc; - } - } - - if (m_staging) - { - ID3D11DeviceContext* pContext = g_Windowing.GetImmediateContext(); - // copy content from decoder texture to temporary texture. - pContext->CopySubresourceRegion(m_staging, - D3D11CalcSubresource(0, 0, 1), - 0, 0, 0, - resource, - D3D11CalcSubresource(0, vpivd.Texture2D.ArraySlice, 1), - nullptr); - m_bPending = true; - } - SAFE_RELEASE(resource); - - return SUCCEEDED(hr); -} - -void YUVBuffer::PerformCopy() -{ - if (!m_locked) - return; - - ID3D11DeviceContext* pContext = g_Windowing.GetImmediateContext(); - D3D11_MAPPED_SUBRESOURCE rectangle; - if (SUCCEEDED(pContext->Map(m_staging, 0, D3D11_MAP_READ, 0, &rectangle))) - { - void* (*copy_func)(void* d, const void* s, size_t size) = - ((g_cpuInfo.GetCPUFeatures() & CPU_FEATURE_SSE4) != 0) ? gpu_memcpy : memcpy; - - uint8_t* s_y = static_cast<uint8_t*>(rectangle.pData); - uint8_t *s_uv = static_cast<uint8_t*>(rectangle.pData) + m_sDesc.Height * rectangle.RowPitch; - uint8_t* d_y = static_cast<uint8_t*>(planes[PLANE_Y].rect.pData); - uint8_t *d_uv = static_cast<uint8_t*>(planes[PLANE_UV].rect.pData); - - if ( planes[PLANE_Y ].rect.RowPitch == rectangle.RowPitch - && planes[PLANE_UV].rect.RowPitch == rectangle.RowPitch) - { - copy_func(d_y, s_y, rectangle.RowPitch * m_height); - copy_func(d_uv, s_uv, rectangle.RowPitch * m_height >> 1); - } - else - { - for (unsigned y = 0; y < m_sDesc.Height >> 1; ++y) - { - // Copy Y - copy_func(d_y, s_y, planes[PLANE_Y].rect.RowPitch); - s_y += rectangle.RowPitch; - d_y += planes[PLANE_Y].rect.RowPitch; - // Copy Y - copy_func(d_y, s_y, planes[PLANE_Y].rect.RowPitch); - s_y += rectangle.RowPitch; - d_y += planes[PLANE_Y].rect.RowPitch; - // Copy UV - copy_func(d_uv, s_uv, planes[PLANE_UV].rect.RowPitch); - s_uv += rectangle.RowPitch; - d_uv += planes[PLANE_UV].rect.RowPitch; - } - } - pContext->Unmap(m_staging, 0); - } -} - diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderer.h b/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderer.h index 8999a6b893..8c10a508c7 100644 --- a/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderer.h +++ b/xbmc/cores/VideoPlayer/VideoRenderers/WinRenderer.h @@ -25,6 +25,7 @@ #include "HwDecRender/DXVAHD.h" #include "guilib/D3DResource.h" #include "RenderCapture.h" +#include "WinVideoBuffer.h" #include "settings/Settings.h" #define ALIGN(value, alignment) (((value)+((alignment)-1))&~((alignment)-1)) @@ -77,80 +78,12 @@ enum RenderMethod #define PLANE_U 1 #define PLANE_V 2 #define PLANE_UV 1 +#define PLANE_DXVA 0 #define FIELD_FULL 0 #define FIELD_TOP 1 #define FIELD_BOT 2 -struct SVideoBuffer -{ - SVideoBuffer() : videoBuffer(nullptr) {} - virtual ~SVideoBuffer() {} - virtual void Release() {}; // Release any allocated resource - virtual void StartDecode() {}; // Prepare the buffer to receive data from VideoPlayer - virtual void StartRender() {}; // VideoPlayer finished filling the buffer with data - virtual void Clear() {}; // clear the buffer with solid black - virtual bool IsReadyToRender() { return true; }; - - CVideoBuffer* videoBuffer = nullptr; -}; - -// YV12 decoder textures -struct SVideoPlane -{ - CD3DTexture texture; - D3D11_MAPPED_SUBRESOURCE rect; // rect.pBits != NULL is used to know if the texture is locked -}; - -struct YUVBuffer : SVideoBuffer -{ - YUVBuffer() : m_width(0), m_height(0) - , m_format(AV_PIX_FMT_NONE) - , m_activeplanes(0) - , m_locked(false) - , m_staging(nullptr) - , m_bPending(false) - { - memset(&m_sDesc, 0, sizeof(CD3D11_TEXTURE2D_DESC)); - } - ~YUVBuffer(); - bool Create(AVPixelFormat format, unsigned int width, unsigned int height, bool dynamic); - unsigned int GetActivePlanes() { return m_activeplanes; } - bool CopyFromPicture(const VideoPicture &picture); - - // SVideoBuffer overrides - void Release() override; - void StartDecode() override; - void StartRender() override; - void Clear() override; - bool IsReadyToRender() override; - - SVideoPlane planes[3]; - -private: - bool CopyFromDXVA(ID3D11VideoDecoderOutputView* pView); - void PerformCopy(); - - unsigned int m_width; - unsigned int m_height; - AVPixelFormat m_format; - unsigned int m_activeplanes; - bool m_locked; - D3D11_MAP m_mapType; - ID3D11Texture2D* m_staging; - CD3D11_TEXTURE2D_DESC m_sDesc; - bool m_bPending; -}; - -struct DXVABuffer : SVideoBuffer -{ - DXVABuffer() { pic = nullptr; } - ~DXVABuffer() { SAFE_RELEASE(pic); } - DXVA::CRenderPicture *pic; - unsigned int frameIdx; - unsigned int pictureFlags; -}; - class CWinRenderer : public CBaseRenderer { public: @@ -197,7 +130,7 @@ protected: void ManageTextures(); void DeleteYV12Texture(int index); bool CreateYV12Texture(int index); - int NextYV12Texture(); + int NextYV12Texture() const; void SelectRenderMethod(); void UpdateVideoFilter(); void SelectSWVideoFilter(); @@ -205,46 +138,45 @@ protected: void UpdatePSVideoFilter(); void ColorManagmentUpdate(); bool CreateIntermediateRenderTarget(unsigned int width, unsigned int height, bool dynamic); + EBufferFormat SelectBufferFormat(const ERenderFormat format, const RenderMethod method) const; bool LoadCLUT(); - int m_iYV12RenderBuffer; - int m_NumYV12Buffers; - - bool m_bConfigured; - SVideoBuffer *m_VideoBuffers[NUM_BUFFERS]; - RenderMethod m_renderMethod; - DXVA::CProcessorHD *m_processor; - - // software scale libraries (fallback if required pixel shaders version is not available) - struct SwsContext *m_sw_scale_ctx; + bool m_bConfigured; bool m_bUseHQScaler; - CD3DTexture m_IntermediateTarget; - CYUV2RGBShader* m_colorShader; - CConvolutionShader* m_scalerShader; - COutputShader* m_outputShader; + bool m_bFilterInitialized; + bool m_cmsOn{ false }; + bool m_useDithering; - ESCALINGMETHOD m_scalingMethod; - ESCALINGMETHOD m_scalingMethodGui; + unsigned int m_destWidth; + unsigned int m_destHeight; + unsigned int m_frameIdx; - bool m_bFilterInitialized; + int m_iYV12RenderBuffer; + int m_NumYV12Buffers; + int m_neededBuffers; int m_iRequestedMethod; - DXGI_FORMAT m_dxva_format; + int m_cmsToken{ -1 }; + int m_CLUTSize{ 0 }; + int m_ditherDepth; - // Width and height of the render target - // the separable HQ scalers need this info, but could the m_destRect be used instead? - unsigned int m_destWidth; - unsigned int m_destHeight; + DXGI_FORMAT m_dxva_format; + RenderMethod m_renderMethod; + EBufferFormat m_bufferFormat; + ESCALINGMETHOD m_scalingMethod; + ESCALINGMETHOD m_scalingMethodGui; - int m_neededBuffers; - unsigned int m_frameIdx = 0; - CRenderCapture* m_capture = nullptr; + std::vector<ERenderFormat> m_formats; - int m_cmsToken{ -1 }; - bool m_cmsOn{ false }; - int m_CLUTSize{ 0 }; + SWinVideoBuffer *m_VideoBuffers[NUM_BUFFERS]; + DXVA::CProcessorHD *m_processor; + struct SwsContext *m_sw_scale_ctx; + CYUV2RGBShader* m_colorShader; + CConvolutionShader* m_scalerShader; + COutputShader* m_outputShader; + CRenderCapture* m_capture = nullptr; std::unique_ptr<CColorManager> m_colorManager; ID3D11ShaderResourceView *m_pCLUTView{ nullptr }; - bool m_useDithering; - int m_ditherDepth; + + CD3DTexture m_IntermediateTarget; }; |