2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 // setting that here because otherwise SampleFormat is defined to AVSampleFormat
10 // which we don't use here
11 #define FF_API_OLD_SAMPLE_FMT 0
12 #define DEFAULT_STREAM_INDEX (0)
16 #include "VideoRenderers/RenderFlags.h"
17 #include "VideoRenderers/RenderManager.h"
18 #include "VideoRenderers/windows/RendererBase.h"
19 #include "VideoRenderers/windows/RendererDXVA.h"
20 #include "rendering/dx/RenderContext.h"
21 #include "utils/StringUtils.h"
22 #include "utils/log.h"
24 #include "platform/win32/WIN32Util.h"
33 using namespace Microsoft::WRL
;
37 // magic constants taken from Chromium:
38 // https://chromium.googlesource.com/chromium/src/+/refs/heads/main/ui/gl/swap_chain_presenter.cc#180
39 constexpr GUID GUID_INTEL_VPE_INTERFACE
= {
40 0xedd1d4b9, 0x8659, 0x4cbc, {0xa4, 0xd6, 0x98, 0x31, 0xa2, 0x16, 0x3a, 0xc3}};
42 constexpr UINT kIntelVpeFnVersion
= 0x01;
43 constexpr UINT kIntelVpeFnMode
= 0x20;
44 constexpr UINT kIntelVpeFnScaling
= 0x37;
45 constexpr UINT kIntelVpeVersion3
= 0x0003;
46 constexpr UINT kIntelVpeModePreproc
= 0x01;
47 constexpr UINT kIntelVpeScalingSuperResolution
= 0x2;
49 constexpr GUID GUID_NVIDIA_PPE_INTERFACE
= {
50 0xd43ce1b3, 0x1f4b, 0x48ac, {0xba, 0xee, 0xc3, 0xc2, 0x53, 0x75, 0xe6, 0xf7}};
52 constexpr UINT kStreamExtensionVersionV1
= 0x1;
53 constexpr UINT kStreamExtensionMethodSuperResolution
= 0x2;
54 } // unnamed namespace
56 struct DXVA::ProcColorSpaces
58 DXGI_COLOR_SPACE_TYPE inputColorSpace
;
59 DXGI_COLOR_SPACE_TYPE outputColorSpace
;
62 CProcessorHD::CProcessorHD()
64 DX::Windowing()->Register(this);
67 CProcessorHD::~CProcessorHD()
69 DX::Windowing()->Unregister(this);
73 void CProcessorHD::UnInit()
75 std::unique_lock
<CCriticalSection
> lock(m_section
);
76 m_enumerator
= nullptr;
80 void CProcessorHD::Close()
82 std::unique_lock
<CCriticalSection
> lock(m_section
);
83 m_pVideoProcessor
= nullptr;
84 m_pVideoContext
= nullptr;
85 m_pVideoDevice
= nullptr;
86 m_superResolutionEnabled
= false;
90 bool CProcessorHD::InitProcessor()
93 m_pVideoDevice
= nullptr;
94 m_pVideoContext
= nullptr;
96 ComPtr
<ID3D11DeviceContext1
> pD3DDeviceContext
= DX::DeviceResources::Get()->GetImmediateContext();
97 ComPtr
<ID3D11Device
> pD3DDevice
= DX::DeviceResources::Get()->GetD3DDevice();
99 if (FAILED(hr
= pD3DDeviceContext
.As(&m_pVideoContext
)))
101 CLog::LogF(LOGWARNING
, "video context initialization is failed. Error {}",
102 CWIN32Util::FormatHRESULT(hr
));
105 if (FAILED(hr
= pD3DDevice
.As(&m_pVideoDevice
)))
107 CLog::LogF(LOGWARNING
, "video device initialization is failed. Error {}",
108 CWIN32Util::FormatHRESULT(hr
));
115 m_procCaps
= m_enumerator
->ProbeProcessorCaps();
116 if (!m_procCaps
.m_valid
)
122 bool CProcessorHD::CheckFormats() const
124 if (!m_isValidConversion
)
127 // check default output format (as render target)
128 return m_enumerator
&& m_enumerator
->IsFormatSupportedOutput(m_conversion
.m_outputFormat
);
131 bool CProcessorHD::Open(const VideoPicture
& picture
,
132 std::shared_ptr
<DXVA::CEnumeratorHD
> enumerator
)
136 std::unique_lock
<CCriticalSection
> lock(m_section
);
138 m_color_primaries
= picture
.color_primaries
;
139 m_color_transfer
= picture
.color_transfer
;
140 m_enumerator
= enumerator
;
142 if (!InitProcessor())
145 return OpenProcessor();
148 bool CProcessorHD::ReInit()
150 std::unique_lock
<CCriticalSection
> lock(m_section
);
153 if (!InitProcessor())
162 bool CProcessorHD::OpenProcessor()
164 std::unique_lock
<CCriticalSection
> lock(m_section
);
166 if ((!m_pVideoDevice
|| !m_pVideoContext
|| !m_enumerator
|| !m_procCaps
.m_valid
) && !ReInit())
168 CLog::LogF(LOGDEBUG
, "invalid state, failed to re-initialize.");
172 CLog::LogF(LOGDEBUG
, "creating processor.");
175 m_pVideoProcessor
= m_enumerator
->CreateVideoProcessor(m_procCaps
.m_procIndex
);
177 if (!m_pVideoProcessor
)
179 CLog::LogF(LOGDEBUG
, "failed creating video processor.");
183 m_pVideoContext
->VideoProcessorSetStreamAutoProcessingMode(m_pVideoProcessor
.Get(), 0, FALSE
);
184 m_pVideoContext
->VideoProcessorSetStreamOutputRate(
185 m_pVideoProcessor
.Get(), 0, D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_NORMAL
, FALSE
, 0);
187 ComPtr
<ID3D11VideoContext1
> videoCtx1
;
188 if (SUCCEEDED(m_pVideoContext
.As(&videoCtx1
)))
190 videoCtx1
->VideoProcessorSetOutputShaderUsage(m_pVideoProcessor
.Get(), 1);
194 CLog::LogF(LOGWARNING
, "unable to retrieve ID3D11VideoContext1 to allow usage of shaders on "
195 "video processor output surfaces.");
198 // Output background color (black)
199 D3D11_VIDEO_COLOR color
;
200 color
.YCbCr
= { 0.0625f
, 0.5f
, 0.5f
, 1.0f
}; // black color
201 m_pVideoContext
->VideoProcessorSetOutputBackgroundColor(m_pVideoProcessor
.Get(), TRUE
, &color
);
203 // AMD/HDR (as of 2023-06-16): processor tone maps by default and modifies high code values
204 // We want "passthrough" of the signal and to do our own tone mapping when needed.
205 // Disable the functionality by pretending that the display supports all PQ levels (0-10000)
206 const DXGI_ADAPTER_DESC ad
= DX::DeviceResources::Get()->GetAdapterDesc();
208 (m_color_primaries
== AVCOL_PRI_BT2020
) &&
209 (m_color_transfer
== AVCOL_TRC_SMPTE2084
|| m_color_transfer
== AVCOL_TRC_ARIB_STD_B67
);
211 if (m_procCaps
.m_hasMetadataHDR10Support
&& ad
.VendorId
== PCIV_AMD
&& streamIsHDR
)
213 ComPtr
<ID3D11VideoContext2
> videoCtx2
;
214 if (SUCCEEDED(m_pVideoContext
.As(&videoCtx2
)))
216 DXGI_HDR_METADATA_HDR10 hdr10
{};
217 hdr10
.MaxMasteringLuminance
= 10000;
218 hdr10
.MinMasteringLuminance
= 0;
220 videoCtx2
->VideoProcessorSetOutputHDRMetaData(m_pVideoProcessor
.Get(),
221 DXGI_HDR_METADATA_TYPE_HDR10
,
222 sizeof(DXGI_HDR_METADATA_HDR10
), &hdr10
);
224 CLog::LogF(LOGDEBUG
, "video processor tone mapping disabled.");
229 "unable to retrieve ID3D11VideoContext2 to disable video processor tone mapping.");
236 void CProcessorHD::ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER filter
, int value
, int min
, int max
, int def
) const
238 if (filter
>= static_cast<D3D11_VIDEO_PROCESSOR_FILTER
>(NUM_FILTERS
))
241 // Unsupported filter. Ignore.
242 if (!m_procCaps
.m_Filters
[filter
].bSupported
)
245 D3D11_VIDEO_PROCESSOR_FILTER_RANGE range
= m_procCaps
.m_Filters
[filter
].Range
;
249 val
= range
.Default
+ (range
.Maximum
- range
.Default
) * (value
- def
) / (max
- def
);
251 val
= range
.Default
+ (range
.Minimum
- range
.Default
) * (value
- def
) / (min
- def
);
255 m_pVideoContext
->VideoProcessorSetStreamFilter(m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
, filter
, val
!= range
.Default
, val
);
258 ComPtr
<ID3D11VideoProcessorInputView
> CProcessorHD::GetInputView(CRenderBuffer
* view
) const
262 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC vpivd
= {0, D3D11_VPIV_DIMENSION_TEXTURE2D
, {0, 0}};
264 ComPtr
<ID3D11Resource
> resource
;
265 unsigned arrayIdx
= 0;
266 HRESULT hr
= view
->GetResource(resource
.GetAddressOf(), &arrayIdx
);
269 vpivd
.Texture2D
.ArraySlice
= arrayIdx
;
270 return m_enumerator
->CreateVideoProcessorInputView(resource
.Get(), &vpivd
);
276 bool CProcessorHD::CheckVideoParameters(const CRect
& src
,
278 const UINT
& rotation
,
279 const float& contrast
,
280 const float& brightness
,
281 const CRenderBuffer
& rb
)
283 bool updatedParameter
{false};
285 if (!m_configured
|| m_lastSrc
!= src
)
287 const RECT sourceRECT
= {static_cast<LONG
>(src
.x1
), static_cast<LONG
>(src
.y1
),
288 static_cast<LONG
>(src
.x2
), static_cast<LONG
>(src
.y2
)};
290 m_pVideoContext
->VideoProcessorSetStreamSourceRect(m_pVideoProcessor
.Get(),
291 DEFAULT_STREAM_INDEX
, TRUE
, &sourceRECT
);
293 updatedParameter
= true;
296 if (!m_configured
|| m_lastDst
!= dst
)
298 const RECT dstRECT
= {static_cast<LONG
>(dst
.x1
), static_cast<LONG
>(dst
.y1
),
299 static_cast<LONG
>(dst
.x2
), static_cast<LONG
>(dst
.y2
)};
301 m_pVideoContext
->VideoProcessorSetStreamDestRect(m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
,
303 m_pVideoContext
->VideoProcessorSetOutputTargetRect(m_pVideoProcessor
.Get(), TRUE
, &dstRECT
);
306 updatedParameter
= true;
309 if (!m_configured
|| m_lastBrightness
!= brightness
)
311 ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_BRIGHTNESS
, static_cast<int>(brightness
), 0, 100, 50);
313 m_lastBrightness
= brightness
;
314 updatedParameter
= true;
317 if (!m_configured
|| m_lastContrast
!= contrast
)
319 ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_CONTRAST
, static_cast<int>(contrast
), 0, 100, 50);
321 m_lastContrast
= contrast
;
322 updatedParameter
= true;
325 // unused filters - set once and forget
328 ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_HUE
, 50, 0, 100, 50);
329 ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_SATURATION
, 50, 0, 100, 50);
332 if (!m_configured
|| m_lastRotation
!= rotation
)
334 m_pVideoContext
->VideoProcessorSetStreamRotation(
335 m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
, rotation
!= 0,
336 static_cast<D3D11_VIDEO_PROCESSOR_ROTATION
>(rotation
/ 90));
338 m_lastRotation
= rotation
;
339 updatedParameter
= true;
342 ComPtr
<ID3D11VideoContext1
> videoCtx1
;
343 if (SUCCEEDED(m_pVideoContext
.As(&videoCtx1
)))
345 if (!m_configured
|| m_lastConversion
!= m_conversion
)
347 videoCtx1
->VideoProcessorSetStreamColorSpace1(m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
,
348 m_conversion
.m_inputCS
);
349 videoCtx1
->VideoProcessorSetOutputColorSpace1(m_pVideoProcessor
.Get(),
350 m_conversion
.m_outputCS
);
352 m_lastConversion
= m_conversion
;
353 updatedParameter
= true;
356 else if (!m_configured
|| m_lastColorSpace
!= rb
.color_space
|| m_lastFullRange
!= rb
.full_range
)
359 bool isBT601
= rb
.color_space
== AVCOL_SPC_BT470BG
|| rb
.color_space
== AVCOL_SPC_SMPTE170M
;
361 D3D11_VIDEO_PROCESSOR_COLOR_SPACE colorSpace
363 0u, // 0 - Playback, 1 - Processing
364 rb
.full_range
? 0u : 1u, // 0 - Full (0-255), 1 - Limited (16-235) (RGB)
365 isBT601
? 1u : 0u, // 0 - BT.601, 1 - BT.709
366 0u, // 0 - Conventional YCbCr, 1 - xvYCC
367 rb
.full_range
? 2u : 1u // 0 - driver defaults, 2 - Full range [0-255], 1 - Studio range [16-235] (YUV)
370 m_pVideoContext
->VideoProcessorSetStreamColorSpace(m_pVideoProcessor
.Get(),
371 DEFAULT_STREAM_INDEX
, &colorSpace
);
372 // Output color space
373 // don't apply any color range conversion, this will be fixed at later stage.
374 colorSpace
.Usage
= 0; // 0 - playback, 1 - video processing
375 colorSpace
.RGB_Range
= DX::Windowing()->UseLimitedColor() ? 1 : 0; // 0 - 0-255, 1 - 16-235
376 colorSpace
.YCbCr_Matrix
= 1; // 0 - BT.601, 1 = BT.709
377 colorSpace
.YCbCr_xvYCC
= 1; // 0 - Conventional YCbCr, 1 - xvYCC
378 colorSpace
.Nominal_Range
= 0; // 2 - 0-255, 1 = 16-235, 0 - undefined
379 m_pVideoContext
->VideoProcessorSetOutputColorSpace(m_pVideoProcessor
.Get(), &colorSpace
);
381 m_lastColorSpace
= rb
.color_space
;
382 m_lastFullRange
= rb
.full_range
;
383 updatedParameter
= true;
386 return updatedParameter
;
389 bool CProcessorHD::Render(CRect src
, CRect dst
, ID3D11Resource
* target
, CRenderBuffer
** views
, DWORD flags
, UINT frameIdx
, UINT rotation
, float contrast
, float brightness
)
391 std::unique_lock
<CCriticalSection
> lock(m_section
);
393 // restore processor if it was lost
394 if (!m_pVideoProcessor
&& !OpenProcessor())
400 const bool updatedParam
=
401 CheckVideoParameters(src
, dst
, rotation
, contrast
, brightness
, *views
[2]);
403 D3D11_VIDEO_FRAME_FORMAT dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE
;
405 if ((flags
& RENDER_FLAG_FIELD0
) && (flags
& RENDER_FLAG_TOP
))
406 dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST
;
407 else if ((flags
& RENDER_FLAG_FIELD1
) && (flags
& RENDER_FLAG_BOT
))
408 dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST
;
409 else if ((flags
& RENDER_FLAG_FIELD0
) && (flags
& RENDER_FLAG_BOT
))
410 dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST
;
411 else if ((flags
& RENDER_FLAG_FIELD1
) && (flags
& RENDER_FLAG_TOP
))
412 dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST
;
414 m_pVideoContext
->VideoProcessorSetStreamFrameFormat(m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
,
417 D3D11_VIDEO_PROCESSOR_STREAM stream_data
= {};
418 stream_data
.Enable
= TRUE
;
420 const bool frameProgressive
= dxvaFrameFormat
== D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE
;
422 // Progressive or Interlaced video at normal rate.
423 const bool secondField
= ((flags
& RENDER_FLAG_FIELD1
) && !frameProgressive
) ? 1 : 0;
424 stream_data
.InputFrameOrField
= frameIdx
+ (secondField
? 1 : 0);
425 stream_data
.OutputIndex
= secondField
;
427 // Render() gets called once for each displayed frame, following the pattern necessary to adapt
428 // the source fps to the display fps, with repetitions as needed (ex. 3:2 for 23.98fps at 59Hz)
429 // However there is no need to render the same frame more than once, the intermediate target is
430 // not cleared and the output of the previous processing is still there.
431 // For nVidia deinterlacing it's more than an optimization. The processor must see each field
432 // only once or it won't switch from bob to a more advanced algorithm.
433 // for ex. when playing 25i at 60fps, decoded frames A B => output A0 A1 B0 B1 B1
434 // B1 field is repeated and the second B1 must be skipped.
435 // Exception: always process when a parameter changes to provide immediate feedback to the user
437 if (m_configured
&& m_lastInputFrameOrField
== stream_data
.InputFrameOrField
&&
438 m_lastOutputIndex
== stream_data
.OutputIndex
&& !updatedParam
)
441 m_lastInputFrameOrField
= stream_data
.InputFrameOrField
;
442 m_lastOutputIndex
= stream_data
.OutputIndex
;
444 unsigned int providedPast
= 0;
445 for (int i
= 3; i
< 8; i
++)
450 unsigned int providedFuture
= 0;
451 for (int i
= 1; i
>= 0; i
--)
456 const int futureFrames
= std::min(providedFuture
, m_procCaps
.m_rateCaps
.FutureFrames
);
457 const int pastFrames
= std::min(providedPast
, m_procCaps
.m_rateCaps
.PastFrames
);
458 std::vector
<ID3D11VideoProcessorInputView
*> pastViews(pastFrames
, nullptr);
459 std::vector
<ID3D11VideoProcessorInputView
*> futureViews(futureFrames
, nullptr);
461 stream_data
.PastFrames
= pastFrames
;
462 stream_data
.FutureFrames
= futureFrames
;
463 stream_data
.ppPastSurfaces
= pastViews
.data();
464 stream_data
.ppFutureSurfaces
= futureViews
.data();
466 std::vector
<ComPtr
<ID3D11VideoProcessorInputView
>> all_views
;
467 const int start
= 2 - futureFrames
;
468 const int end
= 2 + pastFrames
;
471 for (int i
= start
; i
<= end
; i
++)
476 ComPtr
<ID3D11VideoProcessorInputView
> view
= GetInputView(views
[i
]);
480 // frames order should be { ?, T-3, T-2, T-1 }
481 pastViews
[2 + pastFrames
- i
] = view
.Get();
485 stream_data
.pInputSurface
= view
.Get();
489 // frames order should be { T+1, T+2, T+3, .. }
490 futureViews
[1 - i
] = view
.Get();
495 all_views
.push_back(view
);
499 if (count
!= pastFrames
+ futureFrames
+ 1)
501 CLog::LogF(LOGERROR
, "incomplete views set.");
505 // create output view for surface.
506 const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputViewDesc
= {D3D11_VPOV_DIMENSION_TEXTURE2D
,
508 ComPtr
<ID3D11VideoProcessorOutputView
> pOutputView
=
509 m_enumerator
->CreateVideoProcessorOutputView(target
, &outputViewDesc
);
514 hr
= m_pVideoContext
->VideoProcessorBlt(m_pVideoProcessor
.Get(), pOutputView
.Get(), 0, 1,
518 CLog::LogF(FAILED(hr
) ? LOGERROR
: LOGWARNING
,
519 "VideoProcessorBlt returned {} while VideoProcessorBlt execution.",
520 CWIN32Util::FormatHRESULT(hr
));
527 return pOutputView
&& !FAILED(hr
);
530 bool CProcessorHD::IsSuperResolutionSuitable(const VideoPicture
& picture
)
532 if (picture
.iWidth
> 1920)
535 const UINT outputWidth
= DX::Windowing()->GetBackBuffer().GetWidth();
537 if (outputWidth
<= picture
.iWidth
)
540 if (picture
.color_primaries
== AVCOL_PRI_BT2020
||
541 picture
.color_transfer
== AVCOL_TRC_SMPTE2084
||
542 picture
.color_transfer
== AVCOL_TRC_ARIB_STD_B67
)
548 void CProcessorHD::TryEnableVideoSuperResolution()
550 if (!m_pVideoContext
|| !m_pVideoProcessor
)
553 const DXGI_ADAPTER_DESC ad
= DX::DeviceResources::Get()->GetAdapterDesc();
555 if (ad
.VendorId
== PCIV_Intel
)
557 EnableIntelVideoSuperResolution();
559 else if (ad
.VendorId
== PCIV_NVIDIA
)
561 EnableNvidiaRTXVideoSuperResolution();
565 void CProcessorHD::EnableIntelVideoSuperResolution()
575 IntelVpeExt ext
{0, ¶m
};
577 ext
.function
= kIntelVpeFnVersion
;
578 param
= kIntelVpeVersion3
;
580 HRESULT hr
= m_pVideoContext
->VideoProcessorSetOutputExtension(
581 m_pVideoProcessor
.Get(), &GUID_INTEL_VPE_INTERFACE
, sizeof(ext
), &ext
);
584 CLog::LogF(LOGWARNING
, "Failed to set the Intel VPE version with error {}.",
585 CWIN32Util::FormatHRESULT(hr
));
589 ext
.function
= kIntelVpeFnMode
;
590 param
= kIntelVpeModePreproc
;
592 hr
= m_pVideoContext
->VideoProcessorSetOutputExtension(
593 m_pVideoProcessor
.Get(), &GUID_INTEL_VPE_INTERFACE
, sizeof(ext
), &ext
);
596 CLog::LogF(LOGWARNING
, "Failed to set the Intel VPE mode with error {}.",
597 CWIN32Util::FormatHRESULT(hr
));
601 ext
.function
= kIntelVpeFnScaling
;
602 param
= kIntelVpeScalingSuperResolution
;
604 hr
= m_pVideoContext
->VideoProcessorSetStreamExtension(
605 m_pVideoProcessor
.Get(), 0, &GUID_INTEL_VPE_INTERFACE
, sizeof(ext
), &ext
);
608 CLog::LogF(LOGWARNING
, "Failed to set the Intel VPE scaling type with error {}.",
609 CWIN32Util::FormatHRESULT(hr
));
613 CLog::LogF(LOGINFO
, "Intel Video Super Resolution request enable successfully");
614 m_superResolutionEnabled
= true;
617 void CProcessorHD::EnableNvidiaRTXVideoSuperResolution()
619 struct NvidiaStreamExt
626 NvidiaStreamExt ext
= {kStreamExtensionVersionV1
, kStreamExtensionMethodSuperResolution
, 1u};
628 HRESULT hr
= m_pVideoContext
->VideoProcessorSetStreamExtension(
629 m_pVideoProcessor
.Get(), 0, &GUID_NVIDIA_PPE_INTERFACE
, sizeof(ext
), &ext
);
632 CLog::LogF(LOGWARNING
, "Failed to set the NVIDIA video process stream extension with error {}.",
633 CWIN32Util::FormatHRESULT(hr
));
637 CLog::LogF(LOGINFO
, "RTX Video Super Resolution request enable successfully");
638 m_superResolutionEnabled
= true;
641 bool CProcessorHD::SetConversion(const ProcessorConversion
& conversion
)
643 std::unique_lock
<CCriticalSection
> lock(m_section
);
648 if (!m_enumerator
|| !m_enumerator
->IsFormatSupportedInput(conversion
.m_inputFormat
) ||
649 !m_enumerator
->IsFormatSupportedOutput(conversion
.m_outputFormat
))
652 if (m_enumerator
->IsEnumerator1Available() &&
653 !m_enumerator
->CheckConversion(conversion
.m_inputFormat
, conversion
.m_inputCS
,
654 conversion
.m_outputFormat
, conversion
.m_outputCS
))
656 CLog::LogF(LOGERROR
, "Conversion {} is not supported", conversion
.ToString());
660 m_conversion
= conversion
;
661 m_isValidConversion
= true;
666 bool CProcessorHD::Supports(ERENDERFEATURE feature
) const
670 case RENDERFEATURE_BRIGHTNESS
:
671 return m_procCaps
.m_Filters
[D3D11_VIDEO_PROCESSOR_FILTER_BRIGHTNESS
].bSupported
;
672 case RENDERFEATURE_CONTRAST
:
673 return m_procCaps
.m_Filters
[D3D11_VIDEO_PROCESSOR_FILTER_CONTRAST
].bSupported
;
674 case RENDERFEATURE_ROTATION
:
675 return (m_procCaps
.m_vcaps
.FeatureCaps
& D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION
);