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"
31 using namespace Microsoft::WRL
;
35 // magic constants taken from Chromium:
36 // https://chromium.googlesource.com/chromium/src/+/refs/heads/main/ui/gl/swap_chain_presenter.cc#180
37 constexpr GUID GUID_INTEL_VPE_INTERFACE
= {
38 0xedd1d4b9, 0x8659, 0x4cbc, {0xa4, 0xd6, 0x98, 0x31, 0xa2, 0x16, 0x3a, 0xc3}};
40 constexpr UINT kIntelVpeFnVersion
= 0x01;
41 constexpr UINT kIntelVpeFnMode
= 0x20;
42 constexpr UINT kIntelVpeFnScaling
= 0x37;
43 constexpr UINT kIntelVpeVersion3
= 0x0003;
44 constexpr UINT kIntelVpeModePreproc
= 0x01;
45 constexpr UINT kIntelVpeScalingSuperResolution
= 0x2;
47 constexpr GUID GUID_NVIDIA_PPE_INTERFACE
= {
48 0xd43ce1b3, 0x1f4b, 0x48ac, {0xba, 0xee, 0xc3, 0xc2, 0x53, 0x75, 0xe6, 0xf7}};
50 constexpr UINT kStreamExtensionVersionV1
= 0x1;
51 constexpr UINT kStreamExtensionMethodSuperResolution
= 0x2;
52 } // unnamed namespace
54 struct DXVA::ProcColorSpaces
56 DXGI_COLOR_SPACE_TYPE inputColorSpace
;
57 DXGI_COLOR_SPACE_TYPE outputColorSpace
;
60 CProcessorHD::CProcessorHD()
62 DX::Windowing()->Register(this);
65 CProcessorHD::~CProcessorHD()
67 DX::Windowing()->Unregister(this);
71 void CProcessorHD::UnInit()
73 std::unique_lock
<CCriticalSection
> lock(m_section
);
74 m_enumerator
= nullptr;
78 void CProcessorHD::Close()
80 std::unique_lock
<CCriticalSection
> lock(m_section
);
81 m_pVideoProcessor
= nullptr;
82 m_pVideoContext
= nullptr;
83 m_pVideoDevice
= nullptr;
84 m_superResolutionEnabled
= false;
88 bool CProcessorHD::InitProcessor()
91 m_pVideoDevice
= nullptr;
92 m_pVideoContext
= nullptr;
94 ComPtr
<ID3D11DeviceContext1
> pD3DDeviceContext
= DX::DeviceResources::Get()->GetImmediateContext();
95 ComPtr
<ID3D11Device
> pD3DDevice
= DX::DeviceResources::Get()->GetD3DDevice();
97 if (FAILED(hr
= pD3DDeviceContext
.As(&m_pVideoContext
)))
99 CLog::LogF(LOGWARNING
, "video context initialization is failed. Error {}",
100 DX::GetErrorDescription(hr
));
103 if (FAILED(hr
= pD3DDevice
.As(&m_pVideoDevice
)))
105 CLog::LogF(LOGWARNING
, "video device initialization is failed. Error {}",
106 DX::GetErrorDescription(hr
));
113 m_procCaps
= m_enumerator
->ProbeProcessorCaps();
114 if (!m_procCaps
.m_valid
)
120 bool CProcessorHD::CheckFormats() const
122 if (!m_isValidConversion
)
125 // check default output format (as render target)
126 return m_enumerator
&& m_enumerator
->IsFormatSupportedOutput(m_conversion
.m_outputFormat
);
129 bool CProcessorHD::Open(const VideoPicture
& picture
,
130 std::shared_ptr
<DXVA::CEnumeratorHD
> enumerator
)
134 std::unique_lock
<CCriticalSection
> lock(m_section
);
136 m_color_primaries
= picture
.color_primaries
;
137 m_color_transfer
= picture
.color_transfer
;
138 m_enumerator
= enumerator
;
140 if (!InitProcessor())
143 return OpenProcessor();
146 bool CProcessorHD::ReInit()
148 std::unique_lock
<CCriticalSection
> lock(m_section
);
151 if (!InitProcessor())
160 bool CProcessorHD::OpenProcessor()
162 std::unique_lock
<CCriticalSection
> lock(m_section
);
164 if ((!m_pVideoDevice
|| !m_pVideoContext
|| !m_enumerator
|| !m_procCaps
.m_valid
) && !ReInit())
166 CLog::LogF(LOGDEBUG
, "invalid state, failed to re-initialize.");
170 CLog::LogF(LOGDEBUG
, "creating processor.");
173 m_pVideoProcessor
= m_enumerator
->CreateVideoProcessor(m_procCaps
.m_procIndex
);
175 if (!m_pVideoProcessor
)
177 CLog::LogF(LOGDEBUG
, "failed creating video processor.");
181 m_pVideoContext
->VideoProcessorSetStreamAutoProcessingMode(m_pVideoProcessor
.Get(), 0, FALSE
);
182 m_pVideoContext
->VideoProcessorSetStreamOutputRate(
183 m_pVideoProcessor
.Get(), 0, D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_NORMAL
, FALSE
, 0);
185 ComPtr
<ID3D11VideoContext1
> videoCtx1
;
186 if (SUCCEEDED(m_pVideoContext
.As(&videoCtx1
)))
188 videoCtx1
->VideoProcessorSetOutputShaderUsage(m_pVideoProcessor
.Get(), 1);
192 CLog::LogF(LOGWARNING
, "unable to retrieve ID3D11VideoContext1 to allow usage of shaders on "
193 "video processor output surfaces.");
196 // Output background color (black)
197 D3D11_VIDEO_COLOR color
;
198 color
.YCbCr
= { 0.0625f
, 0.5f
, 0.5f
, 1.0f
}; // black color
199 m_pVideoContext
->VideoProcessorSetOutputBackgroundColor(m_pVideoProcessor
.Get(), TRUE
, &color
);
201 // AMD/HDR (as of 2023-06-16): processor tone maps by default and modifies high code values
202 // We want "passthrough" of the signal and to do our own tone mapping when needed.
203 // Disable the functionality by pretending that the display supports all PQ levels (0-10000)
204 const DXGI_ADAPTER_DESC ad
= DX::DeviceResources::Get()->GetAdapterDesc();
206 (m_color_primaries
== AVCOL_PRI_BT2020
) &&
207 (m_color_transfer
== AVCOL_TRC_SMPTE2084
|| m_color_transfer
== AVCOL_TRC_ARIB_STD_B67
);
209 if (m_procCaps
.m_hasMetadataHDR10Support
&& ad
.VendorId
== PCIV_AMD
&& streamIsHDR
)
211 ComPtr
<ID3D11VideoContext2
> videoCtx2
;
212 if (SUCCEEDED(m_pVideoContext
.As(&videoCtx2
)))
214 DXGI_HDR_METADATA_HDR10 hdr10
{};
215 hdr10
.MaxMasteringLuminance
= 10000;
216 hdr10
.MinMasteringLuminance
= 0;
218 videoCtx2
->VideoProcessorSetOutputHDRMetaData(m_pVideoProcessor
.Get(),
219 DXGI_HDR_METADATA_TYPE_HDR10
,
220 sizeof(DXGI_HDR_METADATA_HDR10
), &hdr10
);
222 CLog::LogF(LOGDEBUG
, "video processor tone mapping disabled.");
227 "unable to retrieve ID3D11VideoContext2 to disable video processor tone mapping.");
234 void CProcessorHD::ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER filter
, int value
, int min
, int max
, int def
) const
236 if (filter
>= static_cast<D3D11_VIDEO_PROCESSOR_FILTER
>(NUM_FILTERS
))
239 // Unsupported filter. Ignore.
240 if (!m_procCaps
.m_Filters
[filter
].bSupported
)
243 D3D11_VIDEO_PROCESSOR_FILTER_RANGE range
= m_procCaps
.m_Filters
[filter
].Range
;
247 val
= range
.Default
+ (range
.Maximum
- range
.Default
) * (value
- def
) / (max
- def
);
249 val
= range
.Default
+ (range
.Minimum
- range
.Default
) * (value
- def
) / (min
- def
);
253 m_pVideoContext
->VideoProcessorSetStreamFilter(m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
, filter
, val
!= range
.Default
, val
);
256 ComPtr
<ID3D11VideoProcessorInputView
> CProcessorHD::GetInputView(CRenderBuffer
* view
) const
260 D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC vpivd
= {0, D3D11_VPIV_DIMENSION_TEXTURE2D
, {0, 0}};
262 ComPtr
<ID3D11Resource
> resource
;
263 unsigned arrayIdx
= 0;
264 HRESULT hr
= view
->GetResource(resource
.GetAddressOf(), &arrayIdx
);
267 vpivd
.Texture2D
.ArraySlice
= arrayIdx
;
268 return m_enumerator
->CreateVideoProcessorInputView(resource
.Get(), &vpivd
);
274 bool CProcessorHD::CheckVideoParameters(const CRect
& src
,
276 const UINT
& rotation
,
277 const float& contrast
,
278 const float& brightness
,
279 const CRenderBuffer
& rb
)
281 bool updatedParameter
{false};
283 if (!m_configured
|| m_lastSrc
!= src
)
285 const RECT sourceRECT
= {static_cast<LONG
>(src
.x1
), static_cast<LONG
>(src
.y1
),
286 static_cast<LONG
>(src
.x2
), static_cast<LONG
>(src
.y2
)};
288 m_pVideoContext
->VideoProcessorSetStreamSourceRect(m_pVideoProcessor
.Get(),
289 DEFAULT_STREAM_INDEX
, TRUE
, &sourceRECT
);
291 updatedParameter
= true;
294 if (!m_configured
|| m_lastDst
!= dst
)
296 const RECT dstRECT
= {static_cast<LONG
>(dst
.x1
), static_cast<LONG
>(dst
.y1
),
297 static_cast<LONG
>(dst
.x2
), static_cast<LONG
>(dst
.y2
)};
299 m_pVideoContext
->VideoProcessorSetStreamDestRect(m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
,
301 m_pVideoContext
->VideoProcessorSetOutputTargetRect(m_pVideoProcessor
.Get(), TRUE
, &dstRECT
);
304 updatedParameter
= true;
307 if (!m_configured
|| m_lastBrightness
!= brightness
)
309 ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_BRIGHTNESS
, static_cast<int>(brightness
), 0, 100, 50);
311 m_lastBrightness
= brightness
;
312 updatedParameter
= true;
315 if (!m_configured
|| m_lastContrast
!= contrast
)
317 ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_CONTRAST
, static_cast<int>(contrast
), 0, 100, 50);
319 m_lastContrast
= contrast
;
320 updatedParameter
= true;
323 // unused filters - set once and forget
326 ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_HUE
, 50, 0, 100, 50);
327 ApplyFilter(D3D11_VIDEO_PROCESSOR_FILTER_SATURATION
, 50, 0, 100, 50);
330 if (!m_configured
|| m_lastRotation
!= rotation
)
332 m_pVideoContext
->VideoProcessorSetStreamRotation(
333 m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
, rotation
!= 0,
334 static_cast<D3D11_VIDEO_PROCESSOR_ROTATION
>(rotation
/ 90));
336 m_lastRotation
= rotation
;
337 updatedParameter
= true;
340 ComPtr
<ID3D11VideoContext1
> videoCtx1
;
341 if (SUCCEEDED(m_pVideoContext
.As(&videoCtx1
)))
343 if (!m_configured
|| m_lastConversion
!= m_conversion
)
345 videoCtx1
->VideoProcessorSetStreamColorSpace1(m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
,
346 m_conversion
.m_inputCS
);
347 videoCtx1
->VideoProcessorSetOutputColorSpace1(m_pVideoProcessor
.Get(),
348 m_conversion
.m_outputCS
);
350 m_lastConversion
= m_conversion
;
351 updatedParameter
= true;
354 else if (!m_configured
|| m_lastColorSpace
!= rb
.color_space
|| m_lastFullRange
!= rb
.full_range
)
357 bool isBT601
= rb
.color_space
== AVCOL_SPC_BT470BG
|| rb
.color_space
== AVCOL_SPC_SMPTE170M
;
359 D3D11_VIDEO_PROCESSOR_COLOR_SPACE colorSpace
361 0u, // 0 - Playback, 1 - Processing
362 rb
.full_range
? 0u : 1u, // 0 - Full (0-255), 1 - Limited (16-235) (RGB)
363 isBT601
? 1u : 0u, // 0 - BT.601, 1 - BT.709
364 0u, // 0 - Conventional YCbCr, 1 - xvYCC
365 rb
.full_range
? 2u : 1u // 0 - driver defaults, 2 - Full range [0-255], 1 - Studio range [16-235] (YUV)
368 m_pVideoContext
->VideoProcessorSetStreamColorSpace(m_pVideoProcessor
.Get(),
369 DEFAULT_STREAM_INDEX
, &colorSpace
);
370 // Output color space
371 // don't apply any color range conversion, this will be fixed at later stage.
372 colorSpace
.Usage
= 0; // 0 - playback, 1 - video processing
373 colorSpace
.RGB_Range
= DX::Windowing()->UseLimitedColor() ? 1 : 0; // 0 - 0-255, 1 - 16-235
374 colorSpace
.YCbCr_Matrix
= 1; // 0 - BT.601, 1 = BT.709
375 colorSpace
.YCbCr_xvYCC
= 1; // 0 - Conventional YCbCr, 1 - xvYCC
376 colorSpace
.Nominal_Range
= 0; // 2 - 0-255, 1 = 16-235, 0 - undefined
377 m_pVideoContext
->VideoProcessorSetOutputColorSpace(m_pVideoProcessor
.Get(), &colorSpace
);
379 m_lastColorSpace
= rb
.color_space
;
380 m_lastFullRange
= rb
.full_range
;
381 updatedParameter
= true;
384 return updatedParameter
;
387 bool CProcessorHD::Render(CRect src
, CRect dst
, ID3D11Resource
* target
, CRenderBuffer
** views
, DWORD flags
, UINT frameIdx
, UINT rotation
, float contrast
, float brightness
)
389 std::unique_lock
<CCriticalSection
> lock(m_section
);
391 // restore processor if it was lost
392 if (!m_pVideoProcessor
&& !OpenProcessor())
398 const bool updatedParam
=
399 CheckVideoParameters(src
, dst
, rotation
, contrast
, brightness
, *views
[2]);
401 D3D11_VIDEO_FRAME_FORMAT dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE
;
403 if ((flags
& RENDER_FLAG_FIELD0
) && (flags
& RENDER_FLAG_TOP
))
404 dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST
;
405 else if ((flags
& RENDER_FLAG_FIELD1
) && (flags
& RENDER_FLAG_BOT
))
406 dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST
;
407 else if ((flags
& RENDER_FLAG_FIELD0
) && (flags
& RENDER_FLAG_BOT
))
408 dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST
;
409 else if ((flags
& RENDER_FLAG_FIELD1
) && (flags
& RENDER_FLAG_TOP
))
410 dxvaFrameFormat
= D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST
;
412 m_pVideoContext
->VideoProcessorSetStreamFrameFormat(m_pVideoProcessor
.Get(), DEFAULT_STREAM_INDEX
,
415 D3D11_VIDEO_PROCESSOR_STREAM stream_data
= {};
416 stream_data
.Enable
= TRUE
;
418 const bool frameProgressive
= dxvaFrameFormat
== D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE
;
420 // Progressive or Interlaced video at normal rate.
421 const bool secondField
= ((flags
& RENDER_FLAG_FIELD1
) && !frameProgressive
) ? 1 : 0;
422 stream_data
.InputFrameOrField
= frameIdx
+ (secondField
? 1 : 0);
423 stream_data
.OutputIndex
= secondField
;
425 // Render() gets called once for each displayed frame, following the pattern necessary to adapt
426 // the source fps to the display fps, with repetitions as needed (ex. 3:2 for 23.98fps at 59Hz)
427 // However there is no need to render the same frame more than once, the intermediate target is
428 // not cleared and the output of the previous processing is still there.
429 // For nVidia deinterlacing it's more than an optimization. The processor must see each field
430 // only once or it won't switch from bob to a more advanced algorithm.
431 // for ex. when playing 25i at 60fps, decoded frames A B => output A0 A1 B0 B1 B1
432 // B1 field is repeated and the second B1 must be skipped.
433 // Exception: always process when a parameter changes to provide immediate feedback to the user
435 if (m_configured
&& m_lastInputFrameOrField
== stream_data
.InputFrameOrField
&&
436 m_lastOutputIndex
== stream_data
.OutputIndex
&& !updatedParam
)
439 m_lastInputFrameOrField
= stream_data
.InputFrameOrField
;
440 m_lastOutputIndex
= stream_data
.OutputIndex
;
442 unsigned int providedPast
= 0;
443 for (int i
= 3; i
< 8; i
++)
448 unsigned int providedFuture
= 0;
449 for (int i
= 1; i
>= 0; i
--)
454 const int futureFrames
= std::min(providedFuture
, m_procCaps
.m_rateCaps
.FutureFrames
);
455 const int pastFrames
= std::min(providedPast
, m_procCaps
.m_rateCaps
.PastFrames
);
456 std::vector
<ID3D11VideoProcessorInputView
*> pastViews(pastFrames
, nullptr);
457 std::vector
<ID3D11VideoProcessorInputView
*> futureViews(futureFrames
, nullptr);
459 stream_data
.PastFrames
= pastFrames
;
460 stream_data
.FutureFrames
= futureFrames
;
461 stream_data
.ppPastSurfaces
= pastViews
.data();
462 stream_data
.ppFutureSurfaces
= futureViews
.data();
464 std::vector
<ComPtr
<ID3D11VideoProcessorInputView
>> all_views
;
465 const int start
= 2 - futureFrames
;
466 const int end
= 2 + pastFrames
;
469 for (int i
= start
; i
<= end
; i
++)
474 ComPtr
<ID3D11VideoProcessorInputView
> view
= GetInputView(views
[i
]);
478 // frames order should be { ?, T-3, T-2, T-1 }
479 pastViews
[2 + pastFrames
- i
] = view
.Get();
483 stream_data
.pInputSurface
= view
.Get();
487 // frames order should be { T+1, T+2, T+3, .. }
488 futureViews
[1 - i
] = view
.Get();
493 all_views
.push_back(view
);
497 if (count
!= pastFrames
+ futureFrames
+ 1)
499 CLog::LogF(LOGERROR
, "incomplete views set.");
503 // create output view for surface.
504 const D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outputViewDesc
= {D3D11_VPOV_DIMENSION_TEXTURE2D
,
506 ComPtr
<ID3D11VideoProcessorOutputView
> pOutputView
=
507 m_enumerator
->CreateVideoProcessorOutputView(target
, &outputViewDesc
);
512 hr
= m_pVideoContext
->VideoProcessorBlt(m_pVideoProcessor
.Get(), pOutputView
.Get(), 0, 1,
516 CLog::LogF(FAILED(hr
) ? LOGERROR
: LOGWARNING
,
517 "VideoProcessorBlt returned {} while VideoProcessorBlt execution.",
518 DX::GetErrorDescription(hr
));
525 return pOutputView
&& !FAILED(hr
);
528 bool CProcessorHD::IsSuperResolutionSuitable(const VideoPicture
& picture
)
530 if (picture
.iWidth
> 1920)
533 const UINT outputWidth
= DX::Windowing()->GetBackBuffer().GetWidth();
535 if (outputWidth
<= picture
.iWidth
)
538 if (picture
.color_primaries
== AVCOL_PRI_BT2020
||
539 picture
.color_transfer
== AVCOL_TRC_SMPTE2084
||
540 picture
.color_transfer
== AVCOL_TRC_ARIB_STD_B67
)
546 void CProcessorHD::TryEnableVideoSuperResolution()
548 if (!m_pVideoContext
|| !m_pVideoProcessor
)
551 const DXGI_ADAPTER_DESC ad
= DX::DeviceResources::Get()->GetAdapterDesc();
553 if (ad
.VendorId
== PCIV_Intel
)
555 EnableIntelVideoSuperResolution();
557 else if (ad
.VendorId
== PCIV_NVIDIA
)
559 EnableNvidiaRTXVideoSuperResolution();
563 void CProcessorHD::EnableIntelVideoSuperResolution()
573 IntelVpeExt ext
{0, ¶m
};
575 ext
.function
= kIntelVpeFnVersion
;
576 param
= kIntelVpeVersion3
;
578 HRESULT hr
= m_pVideoContext
->VideoProcessorSetOutputExtension(
579 m_pVideoProcessor
.Get(), &GUID_INTEL_VPE_INTERFACE
, sizeof(ext
), &ext
);
582 CLog::LogF(LOGWARNING
, "Failed to set the Intel VPE version with error {}.",
583 DX::GetErrorDescription(hr
));
587 ext
.function
= kIntelVpeFnMode
;
588 param
= kIntelVpeModePreproc
;
590 hr
= m_pVideoContext
->VideoProcessorSetOutputExtension(
591 m_pVideoProcessor
.Get(), &GUID_INTEL_VPE_INTERFACE
, sizeof(ext
), &ext
);
594 CLog::LogF(LOGWARNING
, "Failed to set the Intel VPE mode with error {}.",
595 DX::GetErrorDescription(hr
));
599 ext
.function
= kIntelVpeFnScaling
;
600 param
= kIntelVpeScalingSuperResolution
;
602 hr
= m_pVideoContext
->VideoProcessorSetStreamExtension(
603 m_pVideoProcessor
.Get(), 0, &GUID_INTEL_VPE_INTERFACE
, sizeof(ext
), &ext
);
606 CLog::LogF(LOGWARNING
, "Failed to set the Intel VPE scaling type with error {}.",
607 DX::GetErrorDescription(hr
));
611 CLog::LogF(LOGINFO
, "Intel Video Super Resolution request enable successfully");
612 m_superResolutionEnabled
= true;
615 void CProcessorHD::EnableNvidiaRTXVideoSuperResolution()
617 struct NvidiaStreamExt
624 NvidiaStreamExt ext
= {kStreamExtensionVersionV1
, kStreamExtensionMethodSuperResolution
, 1u};
626 HRESULT hr
= m_pVideoContext
->VideoProcessorSetStreamExtension(
627 m_pVideoProcessor
.Get(), 0, &GUID_NVIDIA_PPE_INTERFACE
, sizeof(ext
), &ext
);
630 CLog::LogF(LOGWARNING
, "Failed to set the NVIDIA video process stream extension with error {}.",
631 DX::GetErrorDescription(hr
));
635 CLog::LogF(LOGINFO
, "RTX Video Super Resolution request enable successfully");
636 m_superResolutionEnabled
= true;
639 bool CProcessorHD::SetConversion(const ProcessorConversion
& conversion
)
641 std::unique_lock
<CCriticalSection
> lock(m_section
);
646 if (!m_enumerator
|| !m_enumerator
->IsFormatSupportedInput(conversion
.m_inputFormat
) ||
647 !m_enumerator
->IsFormatSupportedOutput(conversion
.m_outputFormat
))
650 if (m_enumerator
->IsEnumerator1Available() &&
651 !m_enumerator
->CheckConversion(conversion
.m_inputFormat
, conversion
.m_inputCS
,
652 conversion
.m_outputFormat
, conversion
.m_outputCS
))
654 CLog::LogF(LOGERROR
, "Conversion {} is not supported", conversion
.ToString());
658 m_conversion
= conversion
;
659 m_isValidConversion
= true;
664 bool CProcessorHD::Supports(ERENDERFEATURE feature
) const
668 case RENDERFEATURE_BRIGHTNESS
:
669 return m_procCaps
.m_Filters
[D3D11_VIDEO_PROCESSOR_FILTER_BRIGHTNESS
].bSupported
;
670 case RENDERFEATURE_CONTRAST
:
671 return m_procCaps
.m_Filters
[D3D11_VIDEO_PROCESSOR_FILTER_CONTRAST
].bSupported
;
672 case RENDERFEATURE_ROTATION
:
673 return (m_procCaps
.m_vcaps
.FeatureCaps
& D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION
);