This commit is contained in:
elwrcl committed 2026-06-06 13:25:15 +03:00
1 parent 04d4dc8b09
commit 818cab85dc
12511 files changed
+6156641

No files matched your search

@@ -0,0 +1,66 @@
BasedOnStyle: InheritParentConfig
DisableFormat: false
ColumnLimit: 132
SortIncludes: CaseSensitive
AlignConsecutiveAssignments: None
AlignConsecutiveDeclarations: None
AlignTrailingComments: true
PenaltyExcessCharacter: 75
AlwaysBreakTemplateDeclarations: Yes
BreakConstructorInitializers: BeforeColon
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 3
IndentCaseLabels: true
BreakBeforeTernaryOperators: false
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: false
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
FixNamespaceComments: true
KeepEmptyLinesAtTheStartOfBlocks: true
AlwaysBreakAfterReturnType: TopLevel
BinPackArguments: false
BinPackParameters: false
Cpp11BracedListStyle: false
SpaceAfterCStyleCast: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpacesInContainerLiterals: true
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: false
SpacesBeforeTrailingComments: 3
SpacesInAngles: Never
SpacesInParentheses: true
SpacesInSquareBrackets: false
SpacesInCStyleCastParentheses: false
SpaceAfterLogicalNot: false
SpaceBeforeAssignmentOperators: true
SpaceInEmptyParentheses: false
SpaceInEmptyBlock: true
MaxEmptyLinesToKeep: 3
@@ -0,0 +1,9 @@
# Making changes to IDL files on mediafoundation frontend
When changing any .idl on this folder, these must be recompiled with midlrt to produce the public, private headers and the .winmd files.
## How to build the modified IDL files
```
midlrt.EXE <input_idl_file>.idl /metadata_dir C:\Windows\System32\WinMetadata
```
@@ -0,0 +1,321 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* Header file automatically generated from dx12enchmft.idl */
/*
* File built with Microsoft(R) MIDLRT Compiler Engine Version 10.00.0231
*/
#pragma warning( disable: 4049 ) /* more than 64k source lines */
/* verify that the <rpcndr.h> version is high enough to compile this file*/
#ifndef __REQUIRED_RPCNDR_H_VERSION__
#define __REQUIRED_RPCNDR_H_VERSION__ 500
#endif
/* verify that the <rpcsal.h> version is high enough to compile this file*/
#ifndef __REQUIRED_RPCSAL_H_VERSION__
#define __REQUIRED_RPCSAL_H_VERSION__ 100
#endif
#include <rpc.h>
#include <rpcndr.h>
#ifndef __RPCNDR_H_VERSION__
#error this stub requires an updated version of <rpcndr.h>
#endif /* __RPCNDR_H_VERSION__ */
#ifndef COM_NO_WINDOWS_H
#include <windows.h>
#include <ole2.h>
#endif /*COM_NO_WINDOWS_H*/
#ifndef __dx12enchmft_h__
#define __dx12enchmft_h__
#ifndef __dx12enchmft_p_h__
#define __dx12enchmft_p_h__
#pragma once
// Ensure that the setting of the /ns_prefix command line switch is consistent for all headers.
// If you get an error from the compiler indicating "warning C4005: 'CHECK_NS_PREFIX_STATE': macro redefinition", this
// indicates that you have included two different headers with different settings for the /ns_prefix MIDL command line switch
#if !defined(DISABLE_NS_PREFIX_CHECKS)
#define CHECK_NS_PREFIX_STATE "always"
#endif // !defined(DISABLE_NS_PREFIX_CHECKS)
#pragma push_macro("MIDL_CONST_ID")
#undef MIDL_CONST_ID
#define MIDL_CONST_ID const __declspec(selectany)
// API Contract Inclusion Definitions
#if !defined(SPECIFIC_API_CONTRACT_DEFINITIONS)
#if !defined(WINDOWS_APPLICATIONMODEL_ACTIVATION_ACTIVATEDEVENTSCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_ACTIVATION_ACTIVATEDEVENTSCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_APPLICATIONMODEL_ACTIVATION_ACTIVATEDEVENTSCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_ACTIVATION_ACTIVATIONCAMERASETTINGSCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_ACTIVATION_ACTIVATIONCAMERASETTINGSCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_APPLICATIONMODEL_ACTIVATION_ACTIVATIONCAMERASETTINGSCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_ACTIVATION_CONTACTACTIVATEDEVENTSCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_ACTIVATION_CONTACTACTIVATEDEVENTSCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_APPLICATIONMODEL_ACTIVATION_CONTACTACTIVATEDEVENTSCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_ACTIVATION_WEBUISEARCHACTIVATEDEVENTSCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_ACTIVATION_WEBUISEARCHACTIVATEDEVENTSCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_APPLICATIONMODEL_ACTIVATION_WEBUISEARCHACTIVATEDEVENTSCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_BACKGROUND_BACKGROUNDALARMAPPLICATIONCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_BACKGROUND_BACKGROUNDALARMAPPLICATIONCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_APPLICATIONMODEL_BACKGROUND_BACKGROUNDALARMAPPLICATIONCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_CALLS_BACKGROUND_CALLSBACKGROUNDCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_CALLS_BACKGROUND_CALLSBACKGROUNDCONTRACT_VERSION 0x40000
#endif // defined(WINDOWS_APPLICATIONMODEL_CALLS_BACKGROUND_CALLSBACKGROUNDCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_CALLS_CALLSPHONECONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_CALLS_CALLSPHONECONTRACT_VERSION 0x70000
#endif // defined(WINDOWS_APPLICATIONMODEL_CALLS_CALLSPHONECONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_CALLS_CALLSVOIPCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_CALLS_CALLSVOIPCONTRACT_VERSION 0x40000
#endif // defined(WINDOWS_APPLICATIONMODEL_CALLS_CALLSVOIPCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_CALLS_LOCKSCREENCALLCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_CALLS_LOCKSCREENCALLCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_APPLICATIONMODEL_CALLS_LOCKSCREENCALLCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_COMMUNICATIONBLOCKING_COMMUNICATIONBLOCKINGCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_COMMUNICATIONBLOCKING_COMMUNICATIONBLOCKINGCONTRACT_VERSION 0x20000
#endif // defined(WINDOWS_APPLICATIONMODEL_COMMUNICATIONBLOCKING_COMMUNICATIONBLOCKINGCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_FULLTRUSTAPPCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_FULLTRUSTAPPCONTRACT_VERSION 0x20000
#endif // defined(WINDOWS_APPLICATIONMODEL_FULLTRUSTAPPCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_SEARCH_SEARCHCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_SEARCH_SEARCHCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_APPLICATIONMODEL_SEARCH_SEARCHCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_STARTUPTASKCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_STARTUPTASKCONTRACT_VERSION 0x30000
#endif // defined(WINDOWS_APPLICATIONMODEL_STARTUPTASKCONTRACT_VERSION)
#if !defined(WINDOWS_APPLICATIONMODEL_WALLET_WALLETCONTRACT_VERSION)
#define WINDOWS_APPLICATIONMODEL_WALLET_WALLETCONTRACT_VERSION 0x20000
#endif // defined(WINDOWS_APPLICATIONMODEL_WALLET_WALLETCONTRACT_VERSION)
#if !defined(WINDOWS_DEVICES_PRINTERS_EXTENSIONS_EXTENSIONSCONTRACT_VERSION)
#define WINDOWS_DEVICES_PRINTERS_EXTENSIONS_EXTENSIONSCONTRACT_VERSION 0x20000
#endif // defined(WINDOWS_DEVICES_PRINTERS_EXTENSIONS_EXTENSIONSCONTRACT_VERSION)
#if !defined(WINDOWS_DEVICES_SMARTCARDS_SMARTCARDBACKGROUNDTRIGGERCONTRACT_VERSION)
#define WINDOWS_DEVICES_SMARTCARDS_SMARTCARDBACKGROUNDTRIGGERCONTRACT_VERSION 0x30000
#endif // defined(WINDOWS_DEVICES_SMARTCARDS_SMARTCARDBACKGROUNDTRIGGERCONTRACT_VERSION)
#if !defined(WINDOWS_DEVICES_SMARTCARDS_SMARTCARDEMULATORCONTRACT_VERSION)
#define WINDOWS_DEVICES_SMARTCARDS_SMARTCARDEMULATORCONTRACT_VERSION 0x60000
#endif // defined(WINDOWS_DEVICES_SMARTCARDS_SMARTCARDEMULATORCONTRACT_VERSION)
#if !defined(WINDOWS_DEVICES_SMS_LEGACYSMSAPICONTRACT_VERSION)
#define WINDOWS_DEVICES_SMS_LEGACYSMSAPICONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_DEVICES_SMS_LEGACYSMSAPICONTRACT_VERSION)
#if !defined(WINDOWS_FOUNDATION_FOUNDATIONCONTRACT_VERSION)
#define WINDOWS_FOUNDATION_FOUNDATIONCONTRACT_VERSION 0x40000
#endif // defined(WINDOWS_FOUNDATION_FOUNDATIONCONTRACT_VERSION)
#if !defined(WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION)
#define WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION 0xf0000
#endif // defined(WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION)
#if !defined(WINDOWS_GAMING_INPUT_GAMINGINPUTPREVIEWCONTRACT_VERSION)
#define WINDOWS_GAMING_INPUT_GAMINGINPUTPREVIEWCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_GAMING_INPUT_GAMINGINPUTPREVIEWCONTRACT_VERSION)
#if !defined(WINDOWS_GLOBALIZATION_GLOBALIZATIONJAPANESEPHONETICANALYZERCONTRACT_VERSION)
#define WINDOWS_GLOBALIZATION_GLOBALIZATIONJAPANESEPHONETICANALYZERCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_GLOBALIZATION_GLOBALIZATIONJAPANESEPHONETICANALYZERCONTRACT_VERSION)
#if !defined(WINDOWS_MEDIA_CAPTURE_APPBROADCASTCONTRACT_VERSION)
#define WINDOWS_MEDIA_CAPTURE_APPBROADCASTCONTRACT_VERSION 0x20000
#endif // defined(WINDOWS_MEDIA_CAPTURE_APPBROADCASTCONTRACT_VERSION)
#if !defined(WINDOWS_MEDIA_CAPTURE_APPCAPTURECONTRACT_VERSION)
#define WINDOWS_MEDIA_CAPTURE_APPCAPTURECONTRACT_VERSION 0x40000
#endif // defined(WINDOWS_MEDIA_CAPTURE_APPCAPTURECONTRACT_VERSION)
#if !defined(WINDOWS_MEDIA_CAPTURE_APPCAPTUREMETADATACONTRACT_VERSION)
#define WINDOWS_MEDIA_CAPTURE_APPCAPTUREMETADATACONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_MEDIA_CAPTURE_APPCAPTUREMETADATACONTRACT_VERSION)
#if !defined(WINDOWS_MEDIA_CAPTURE_CAMERACAPTUREUICONTRACT_VERSION)
#define WINDOWS_MEDIA_CAPTURE_CAMERACAPTUREUICONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_MEDIA_CAPTURE_CAMERACAPTUREUICONTRACT_VERSION)
#if !defined(WINDOWS_MEDIA_CAPTURE_GAMEBARCONTRACT_VERSION)
#define WINDOWS_MEDIA_CAPTURE_GAMEBARCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_MEDIA_CAPTURE_GAMEBARCONTRACT_VERSION)
#if !defined(WINDOWS_MEDIA_DEVICES_CALLCONTROLCONTRACT_VERSION)
#define WINDOWS_MEDIA_DEVICES_CALLCONTROLCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_MEDIA_DEVICES_CALLCONTROLCONTRACT_VERSION)
#if !defined(WINDOWS_MEDIA_MEDIACONTROLCONTRACT_VERSION)
#define WINDOWS_MEDIA_MEDIACONTROLCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_MEDIA_MEDIACONTROLCONTRACT_VERSION)
#if !defined(WINDOWS_MEDIA_PROTECTION_PROTECTIONRENEWALCONTRACT_VERSION)
#define WINDOWS_MEDIA_PROTECTION_PROTECTIONRENEWALCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_MEDIA_PROTECTION_PROTECTIONRENEWALCONTRACT_VERSION)
#if !defined(WINDOWS_NETWORKING_CONNECTIVITY_WWANCONTRACT_VERSION)
#define WINDOWS_NETWORKING_CONNECTIVITY_WWANCONTRACT_VERSION 0x20000
#endif // defined(WINDOWS_NETWORKING_CONNECTIVITY_WWANCONTRACT_VERSION)
#if !defined(WINDOWS_NETWORKING_SOCKETS_CONTROLCHANNELTRIGGERCONTRACT_VERSION)
#define WINDOWS_NETWORKING_SOCKETS_CONTROLCHANNELTRIGGERCONTRACT_VERSION 0x30000
#endif // defined(WINDOWS_NETWORKING_SOCKETS_CONTROLCHANNELTRIGGERCONTRACT_VERSION)
#if !defined(WINDOWS_PHONE_PHONECONTRACT_VERSION)
#define WINDOWS_PHONE_PHONECONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_PHONE_PHONECONTRACT_VERSION)
#if !defined(WINDOWS_PHONE_PHONEINTERNALCONTRACT_VERSION)
#define WINDOWS_PHONE_PHONEINTERNALCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_PHONE_PHONEINTERNALCONTRACT_VERSION)
#if !defined(WINDOWS_SECURITY_ENTERPRISEDATA_ENTERPRISEDATACONTRACT_VERSION)
#define WINDOWS_SECURITY_ENTERPRISEDATA_ENTERPRISEDATACONTRACT_VERSION 0x50000
#endif // defined(WINDOWS_SECURITY_ENTERPRISEDATA_ENTERPRISEDATACONTRACT_VERSION)
#if !defined(WINDOWS_STORAGE_PROVIDER_CLOUDFILESCONTRACT_VERSION)
#define WINDOWS_STORAGE_PROVIDER_CLOUDFILESCONTRACT_VERSION 0x70000
#endif // defined(WINDOWS_STORAGE_PROVIDER_CLOUDFILESCONTRACT_VERSION)
#if !defined(WINDOWS_SYSTEM_SYSTEMMANAGEMENTCONTRACT_VERSION)
#define WINDOWS_SYSTEM_SYSTEMMANAGEMENTCONTRACT_VERSION 0x70000
#endif // defined(WINDOWS_SYSTEM_SYSTEMMANAGEMENTCONTRACT_VERSION)
#if !defined(WINDOWS_UI_CORE_COREWINDOWDIALOGSCONTRACT_VERSION)
#define WINDOWS_UI_CORE_COREWINDOWDIALOGSCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_UI_CORE_COREWINDOWDIALOGSCONTRACT_VERSION)
#if !defined(WINDOWS_UI_VIEWMANAGEMENT_VIEWMANAGEMENTVIEWSCALINGCONTRACT_VERSION)
#define WINDOWS_UI_VIEWMANAGEMENT_VIEWMANAGEMENTVIEWSCALINGCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_UI_VIEWMANAGEMENT_VIEWMANAGEMENTVIEWSCALINGCONTRACT_VERSION)
#if !defined(WINDOWS_UI_WEBUI_CORE_WEBUICOMMANDBARCONTRACT_VERSION)
#define WINDOWS_UI_WEBUI_CORE_WEBUICOMMANDBARCONTRACT_VERSION 0x10000
#endif // defined(WINDOWS_UI_WEBUI_CORE_WEBUICOMMANDBARCONTRACT_VERSION)
#endif // defined(SPECIFIC_API_CONTRACT_DEFINITIONS)
// Header files for imported files
#include "Windows.Media.h"
#if defined(__cplusplus) && !defined(CINTERFACE)
/* Forward Declarations */
#pragma warning (push)
#pragma warning (disable:4668)
#pragma warning (disable:4001)
#pragma once
#pragma warning (pop)
namespace ABI {
namespace DX12Encoder {
class CDX12EncHMFT;
} /* DX12Encoder */
} /* ABI */
#ifndef ____x_ABI_CWindows_CMedia_CIMediaExtension_FWD_DEFINED__
#define ____x_ABI_CWindows_CMedia_CIMediaExtension_FWD_DEFINED__
namespace ABI {
namespace Windows {
namespace Media {
interface IMediaExtension;
} /* Media */
} /* Windows */
} /* ABI */
#define __x_ABI_CWindows_CMedia_CIMediaExtension ABI::Windows::Media::IMediaExtension
#endif // ____x_ABI_CWindows_CMedia_CIMediaExtension_FWD_DEFINED__
/*
*
* Class DX12Encoder.CDX12EncHMFT
*
* Class implements the following interfaces:
* Windows.Media.IMediaExtension ** Default Interface **
*
*/
#ifndef RUNTIMECLASS_DX12Encoder_CDX12EncHMFT_DEFINED
#define RUNTIMECLASS_DX12Encoder_CDX12EncHMFT_DEFINED
extern const __declspec(selectany) _Null_terminated_ WCHAR RuntimeClass_DX12Encoder_CDX12EncHMFT[] = L"DX12Encoder.CDX12EncHMFT";
#endif
#else // !defined(__cplusplus)
/* Forward Declarations */
#pragma warning (push)
#pragma warning (disable:4668)
#pragma warning (disable:4001)
#pragma once
#pragma warning (pop)
#ifndef ____x_ABI_CWindows_CMedia_CIMediaExtension_FWD_DEFINED__
#define ____x_ABI_CWindows_CMedia_CIMediaExtension_FWD_DEFINED__
typedef interface __x_ABI_CWindows_CMedia_CIMediaExtension __x_ABI_CWindows_CMedia_CIMediaExtension;
#endif // ____x_ABI_CWindows_CMedia_CIMediaExtension_FWD_DEFINED__
/*
*
* Class DX12Encoder.CDX12EncHMFT
*
* Class implements the following interfaces:
* Windows.Media.IMediaExtension ** Default Interface **
*
*/
#ifndef RUNTIMECLASS_DX12Encoder_CDX12EncHMFT_DEFINED
#define RUNTIMECLASS_DX12Encoder_CDX12EncHMFT_DEFINED
extern const __declspec(selectany) _Null_terminated_ WCHAR RuntimeClass_DX12Encoder_CDX12EncHMFT[] = L"DX12Encoder.CDX12EncHMFT";
#endif
#endif // defined(__cplusplus)
#pragma pop_macro("MIDL_CONST_ID")
#endif // __dx12enchmft_p_h__
#endif // __dx12enchmft_h__
@@ -0,0 +1,35 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
import "Windows.Media.idl";
#include <sdkddkver.h>
namespace DX12Encoder
{
[version(NTDDI_WIN8)]
runtimeclass CDX12EncHMFT
{
[default] interface Windows.Media.IMediaExtension;
}
}
@@ -0,0 +1,106 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
/* this ALWAYS GENERATED file contains the definitions for the interfaces */
/* File created by MIDL compiler version 8.01.0628 */
/* at Mon Jan 18 19:14:07 2038
*/
/* Compiler settings for C:\Users\BRIANK~1\AppData\Local\Temp\dx12enchmft.idl-71af067c:
Oicf, W1, Zp8, env=Win64 (32b run), target_arch=AMD64 8.01.0628
protocol : dce , ms_ext, c_ext, robust
error checks: allocation ref bounds_check enum stub_data
VC __declspec() decoration level:
__declspec(uuid()), __declspec(selectany), __declspec(novtable)
DECLSPEC_UUID(), MIDL_INTERFACE()
*/
/* @@MIDL_FILE_HEADING( ) */
#pragma warning( disable: 4049 ) /* more than 64k source lines */
/* verify that the <rpcndr.h> version is high enough to compile this file*/
#ifndef __REQUIRED_RPCNDR_H_VERSION__
#define __REQUIRED_RPCNDR_H_VERSION__ 475
#endif
#include "rpc.h"
#include "rpcndr.h"
#ifndef __RPCNDR_H_VERSION__
#error this stub requires an updated version of <rpcndr.h>
#endif /* __RPCNDR_H_VERSION__ */
#ifndef __dx12enchmft_p_h__
#define __dx12enchmft_p_h__
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif
#ifndef DECLSPEC_XFGVIRT
#if defined(_CONTROL_FLOW_GUARD_XFG)
#define DECLSPEC_XFGVIRT(base, func) __declspec(xfg_virtual(base, func))
#else
#define DECLSPEC_XFGVIRT(base, func)
#endif
#endif
/* Forward Declarations */
/* header files for imported files */
#include "Windows.Media.h"
#ifdef __cplusplus
extern "C"{
#endif
/* interface __MIDL_itf_dx12enchmft_0000_0000 */
/* [local] */
#pragma warning (push)
#pragma warning (disable:4668)
#pragma warning (disable:4001)
#pragma once
#pragma warning (pop)
extern RPC_IF_HANDLE __MIDL_itf_dx12enchmft_0000_0000_v0_0_c_ifspec;
extern RPC_IF_HANDLE __MIDL_itf_dx12enchmft_0000_0000_v0_0_s_ifspec;
/* Additional Prototypes for ALL interfaces */
/* end of Additional Prototypes */
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,299 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <Unknwn.h>
#include "util/u_inlines.h"
#include "vl/vl_winsys.h"
#include "macros.h"
#include "mfpipeinterop.h"
#include "reference_frames_tracker.h"
typedef class DX12EncodeContext
{
public:
void *pAsyncCookie = nullptr;
reference_frames_tracker_dpb_async_token *pAsyncDPBToken = nullptr;
struct pipe_fence_handle *pAsyncFence = NULL;
ComPtr<ID3D12Fence> spAsyncFence;
std::vector<struct pipe_resource *> pOutputBitRes;
std::vector<struct pipe_fence_handle *> pSliceFences;
struct pipe_fence_handle *pLastSliceFence;
D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM_NOTIFICATION_MODE sliceNotificationMode =
D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM_NOTIFICATION_MODE_FULL_FRAME;
pipe_resource *pPipeResourceQPMapStats = nullptr;
pipe_resource *pPipeResourceSATDMapStats = nullptr;
pipe_resource *pPipeResourceRCBitAllocMapStats = nullptr;
pipe_resource *pPipeResourcePSNRStats = nullptr;
bool pipeResourceReconstructedPictureCopyMode = false;
pipe_resource *pPipeResourceReconstructedPicture = nullptr;
UINT PipeResourceReconstructedPictureSubresource = 0;
pipe_fence_handle *pPipeFenceReconstructedPictureCompletionFence = NULL;
ComPtr<ID3D12Fence> spReconstructedPictureCompletionFence;
UINT64 ReconstructedPictureCompletionFenceValue = 0;
// Keep all the media and sync objects until encode is done
// and then signal EnqueueResourceRelease so the media
// producer (e.g decoder) can reuse the buffer in their pool
pipe_video_buffer *pPipeVideoBuffer = nullptr;
pipe_video_buffer *pDownscaledTwoPassPipeVideoBuffer = nullptr;
pipe_fence_handle *pDownscaledTwoPassPipeVideoBufferCompletionFence = nullptr;
ComPtr<IMFMediaBuffer> spMediaBuffer;
ComPtr<IMFD3D12SynchronizationObjectCommands> spSyncObjectCommands;
ID3D12CommandQueue *pSyncObjectQueue = nullptr; // weakref
UINT textureWidth = 0; // width of input sample
UINT textureHeight = 0; // height of input sample
LONGLONG inputSampleTime = 0;
LONGLONG inputSampleDuration = 0;
BOOL bROI = FALSE;
ROI_AREA video_roi_area = {};
UINT longTermReferenceFrameInfo = 0x0000FFFF; // corresponds to MFT attribute MFSampleExtension_LongTermReferenceFrameInfo
struct vl_screen *pVlScreen = nullptr; // weakref
struct pipe_video_codec encoderSettings = {};
union
{
struct pipe_picture_desc base;
struct pipe_h264_enc_picture_desc h264enc;
struct pipe_h265_enc_picture_desc h265enc;
struct pipe_av1_enc_picture_desc av1enc;
} encoderPicInfo = {};
bool IsSliceAutoModeEnabled()
{
return ( ( m_Codec == D3D12_VIDEO_ENCODER_CODEC_H264 ) &&
( encoderPicInfo.h264enc.slice_mode == PIPE_VIDEO_SLICE_MODE_AUTO ) ) ||
( ( m_Codec == D3D12_VIDEO_ENCODER_CODEC_HEVC ) &&
( encoderPicInfo.h265enc.slice_mode == PIPE_VIDEO_SLICE_MODE_AUTO ) );
}
pipe_video_buffer *get_current_dpb_pic_buffer()
{
pipe_video_buffer *vid_buf = nullptr;
switch( m_Codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
if( encoderPicInfo.h264enc.not_referenced )
return nullptr;
vid_buf = encoderPicInfo.h264enc.dpb[encoderPicInfo.h264enc.dpb_curr_pic].buffer;
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
if( encoderPicInfo.h265enc.not_referenced )
return nullptr;
vid_buf = encoderPicInfo.h265enc.dpb[encoderPicInfo.h265enc.dpb_curr_pic].buffer;
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
if( encoderPicInfo.av1enc.refresh_frame_flags == 0 )
return nullptr;
vid_buf = encoderPicInfo.av1enc.dpb[encoderPicInfo.av1enc.dpb_curr_pic].buffer;
break;
}
return vid_buf;
}
pipe_resource *get_current_dpb_pic_resource()
{
pipe_video_buffer *vid_buf = get_current_dpb_pic_buffer();
if( vid_buf )
{
struct pipe_resource *buf_resources[VL_NUM_COMPONENTS];
memset( buf_resources, 0, sizeof( buf_resources ) );
vid_buf->get_resources( vid_buf, &buf_resources[0] );
assert( buf_resources[0] );
return buf_resources[0];
}
return nullptr;
}
const D3D12_VIDEO_ENCODER_CODEC m_Codec = D3D12_VIDEO_ENCODER_CODEC_H264;
UINT32 GetPictureType()
{
UINT32 result = 0;
switch( m_Codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
result = ConvertPictureTypeToAVEncH264PictureType( encoderPicInfo.h264enc.picture_type );
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
result = ConvertPictureTypeToAVEncH264PictureType( encoderPicInfo.h265enc.picture_type );
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
// TODO: ConvertPictureTypeToAVEncAV1PictureType(pDX12EncodeContext->encoderPicInfo.av1enc.picture_type);
result = (UINT32) eAVEncAV1PictureType_Key;
break;
}
return result;
}
BOOL IsPicTypeCleanPoint()
{
BOOL result = FALSE;
switch( m_Codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
if( ( encoderPicInfo.h264enc.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I ) ||
( encoderPicInfo.h264enc.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR ) )
result = TRUE;
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
if( ( encoderPicInfo.h265enc.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I ) ||
( encoderPicInfo.h265enc.picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR ) )
result = TRUE;
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
if( encoderPicInfo.av1enc.frame_type == PIPE_AV1_ENC_FRAME_TYPE_KEY )
result = TRUE;
break;
}
return result;
}
UINT32 GetFrameRateNumerator()
{
UINT32 result = 0;
switch( m_Codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
result = encoderPicInfo.h264enc.rate_ctrl[0].frame_rate_num;
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
result = encoderPicInfo.h265enc.rc[0].frame_rate_num;
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
result = encoderPicInfo.av1enc.rc[0].frame_rate_num;
break;
}
return result;
}
void SetPipeQPMapBufferInfo( void *pQPMap, const uint32_t QPMapSize )
{
switch( m_Codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
encoderPicInfo.h264enc.input_qpmap_info.input_qpmap_cpu = static_cast<int8_t *>( pQPMap );
encoderPicInfo.h264enc.input_qpmap_info.qp_map_values_count = QPMapSize / sizeof( int8_t );
encoderPicInfo.h264enc.input_qpmap_info.input_qp_mode = PIPE_ENC_QPMAP_INPUT_MODE_CPU_BUFFER_8BIT;
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
encoderPicInfo.h265enc.input_qpmap_info.input_qpmap_cpu = static_cast<int8_t *>( pQPMap );
encoderPicInfo.h265enc.input_qpmap_info.qp_map_values_count = QPMapSize / sizeof( int8_t );
encoderPicInfo.h265enc.input_qpmap_info.input_qp_mode = PIPE_ENC_QPMAP_INPUT_MODE_CPU_BUFFER_8BIT;
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
encoderPicInfo.av1enc.input_qpmap_info.input_qpmap_cpu = static_cast<int16_t *>( pQPMap );
encoderPicInfo.av1enc.input_qpmap_info.qp_map_values_count = QPMapSize / sizeof( int16_t );
encoderPicInfo.av1enc.input_qpmap_info.input_qp_mode = PIPE_ENC_QPMAP_INPUT_MODE_CPU_BUFFER_16BIT;
break;
}
}
UINT32 GetFrameRateDenominator()
{
UINT32 result = 0;
switch( m_Codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
result = encoderPicInfo.h264enc.rate_ctrl[0].frame_rate_den;
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
result = encoderPicInfo.h265enc.rc[0].frame_rate_den;
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
result = encoderPicInfo.av1enc.rc[0].frame_rate_den;
break;
}
return result;
}
DX12EncodeContext( D3D12_VIDEO_ENCODER_CODEC codec ) : m_Codec( codec ) { };
~DX12EncodeContext()
{
if( spSyncObjectCommands )
spSyncObjectCommands->EnqueueResourceRelease( pSyncObjectQueue );
switch( m_Codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
util_dynarray_foreach ( &encoderPicInfo.h264enc.raw_headers, struct pipe_enc_raw_header, header )
delete header->buffer;
util_dynarray_fini( &encoderPicInfo.h264enc.raw_headers );
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
util_dynarray_foreach ( &encoderPicInfo.h265enc.raw_headers, struct pipe_enc_raw_header, header )
delete header->buffer;
util_dynarray_fini( &encoderPicInfo.h265enc.raw_headers );
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
util_dynarray_foreach ( &encoderPicInfo.av1enc.raw_headers, struct pipe_enc_raw_header, header )
delete header->buffer;
util_dynarray_fini( &encoderPicInfo.av1enc.raw_headers );
break;
}
for( uint32_t slice_idx = 0; slice_idx < static_cast<uint32_t>( pOutputBitRes.size() ); slice_idx++ )
pipe_resource_reference( &pOutputBitRes[slice_idx], nullptr );
if( pPipeResourceQPMapStats )
{
pipe_resource_reference( &pPipeResourceQPMapStats, nullptr );
}
if( pPipeResourceSATDMapStats )
{
pipe_resource_reference( &pPipeResourceSATDMapStats, nullptr );
}
if( pPipeResourceRCBitAllocMapStats )
{
pipe_resource_reference( &pPipeResourceRCBitAllocMapStats, nullptr );
}
if( pipeResourceReconstructedPictureCopyMode )
{
if( pPipeResourceReconstructedPicture )
{
pipe_resource_reference( &pPipeResourceReconstructedPicture, nullptr );
}
}
if( pPipeVideoBuffer )
pPipeVideoBuffer->destroy( pPipeVideoBuffer );
if( pDownscaledTwoPassPipeVideoBuffer )
pDownscaledTwoPassPipeVideoBuffer->destroy( pDownscaledTwoPassPipeVideoBuffer );
if( pPipeResourcePSNRStats )
pVlScreen->pscreen->resource_destroy( pVlScreen->pscreen, pPipeResourcePSNRStats );
if( pDownscaledTwoPassPipeVideoBufferCompletionFence )
pVlScreen->pscreen->fence_reference( pVlScreen->pscreen, &pDownscaledTwoPassPipeVideoBufferCompletionFence, NULL );
if( pPipeFenceReconstructedPictureCompletionFence )
pVlScreen->pscreen->fence_reference( pVlScreen->pscreen, &pPipeFenceReconstructedPictureCompletionFence, NULL );
}
} *LPDX12EncodeContext;
@@ -0,0 +1,143 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_suballoc_mediabuffer.h"
#include <mferror.h>
#include "frontend/winsys_handle.h"
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "util/u_inlines.h"
#include "wpptrace.h"
#include "d3d12_suballoc_mediabuffer.tmh"
CD3D12BitstreamMFBuffer::CD3D12BitstreamMFBuffer(
void *logId, pipe_context *pPipeContext, pipe_resource *pOutputBitRes, DWORD length, DWORD offset )
: m_logId( logId ),
m_cRef( 1 ),
m_dwLength( length ),
m_dwOffset( offset ),
m_pMappedData( nullptr ),
m_pScreen( pPipeContext->screen ),
m_pOutputBitRes( nullptr )
{
debug_printf( "[dx12 hmft 0x%p] CD3D12BitstreamMFBuffer created for length %u, offset %u\n", m_logId, length, offset );
pipe_resource_reference( &m_pOutputBitRes, pOutputBitRes );
struct winsys_handle whandle = { .type = WINSYS_HANDLE_TYPE_D3D12_RES };
if( pPipeContext->screen->resource_get_handle( pPipeContext->screen, nullptr, pOutputBitRes, &whandle, 0u ) )
{
m_spResource = static_cast<ID3D12Resource *>( whandle.com_obj );
}
}
CD3D12BitstreamMFBuffer::~CD3D12BitstreamMFBuffer()
{
// Decrement reference count on the pipe_resource (will destroy if reference count reaches 0)
if( m_pOutputBitRes )
{
pipe_resource_reference( &m_pOutputBitRes, nullptr );
}
}
STDMETHODIMP
CD3D12BitstreamMFBuffer::QueryInterface( REFIID riid, void **ppv )
{
if( riid == IID_IUnknown || riid == IID_IMFMediaBuffer )
{
*ppv = this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_( ULONG ) CD3D12BitstreamMFBuffer::AddRef()
{
return InterlockedIncrement( &m_cRef );
}
STDMETHODIMP_( ULONG ) CD3D12BitstreamMFBuffer::Release()
{
ULONG cRef = InterlockedDecrement( &m_cRef );
if( !cRef )
delete this;
return cRef;
}
STDMETHODIMP
CD3D12BitstreamMFBuffer::Lock( BYTE **ppbBuffer, DWORD *pcbMaxLength, DWORD *pcbCurrentLength )
{
if( !ppbBuffer )
return E_POINTER;
if( m_pMappedData )
return MF_E_INVALIDREQUEST;
D3D12_RANGE range = { m_dwOffset, m_dwOffset + m_dwLength };
HRESULT hr = m_spResource->Map( 0, &range, (void **) &m_pMappedData );
if( SUCCEEDED( hr ) )
{
*ppbBuffer = m_pMappedData + m_dwOffset;
if( pcbMaxLength )
*pcbMaxLength = m_dwLength;
if( pcbCurrentLength )
*pcbCurrentLength = m_dwLength;
}
return hr;
}
STDMETHODIMP
CD3D12BitstreamMFBuffer::Unlock()
{
if( !m_pMappedData )
return MF_E_INVALIDREQUEST;
D3D12_RANGE range = { 0, 0 };
m_spResource->Unmap( 0, &range );
m_pMappedData = nullptr;
return S_OK;
}
STDMETHODIMP
CD3D12BitstreamMFBuffer::GetCurrentLength( DWORD *pcbCurrentLength )
{
if( !pcbCurrentLength )
return E_POINTER;
*pcbCurrentLength = m_dwLength;
return S_OK;
}
STDMETHODIMP
CD3D12BitstreamMFBuffer::SetCurrentLength( DWORD cbCurrentLength )
{
m_dwLength = cbCurrentLength;
return S_OK;
}
STDMETHODIMP
CD3D12BitstreamMFBuffer::GetMaxLength( DWORD *pcbMaxLength )
{
if( !pcbMaxLength )
return E_POINTER;
*pcbMaxLength = m_dwLength;
return S_OK;
}
@@ -0,0 +1,62 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <Unknwn.h>
#include <mfobjects.h>
#include <directx/d3d12.h>
#include <wrl/client.h>
#include "pipe_headers.h"
using Microsoft::WRL::ComPtr;
// Custom IMFMediaBuffer implementation for zero-copy D3D12 buffer access
class CD3D12BitstreamMFBuffer : public IMFMediaBuffer
{
private:
const void *m_logId = {};
ULONG m_cRef;
ComPtr<ID3D12Resource> m_spResource;
DWORD m_dwLength;
DWORD m_dwOffset;
BYTE *m_pMappedData;
pipe_screen *m_pScreen;
pipe_resource *m_pOutputBitRes;
public:
CD3D12BitstreamMFBuffer( void *logId, pipe_context *pPipeContext, pipe_resource *pOutputBitRes, DWORD length, DWORD offset );
~CD3D12BitstreamMFBuffer();
// IUnknown
STDMETHODIMP QueryInterface( REFIID riid, void **ppv );
STDMETHODIMP_( ULONG ) AddRef();
STDMETHODIMP_( ULONG ) Release();
// IMFMediaBuffer
STDMETHODIMP Lock( BYTE **ppbBuffer, DWORD *pcbMaxLength, DWORD *pcbCurrentLength );
STDMETHODIMP Unlock();
STDMETHODIMP GetCurrentLength( DWORD *pcbCurrentLength );
STDMETHODIMP SetCurrentLength( DWORD cbCurrentLength );
STDMETHODIMP GetMaxLength( DWORD *pcbMaxLength );
};
@@ -0,0 +1,79 @@
# DX12 Video Encode Media Foundation Transform (Microsoft Corporation (C) 2025)
## Overview
This folder contains the implementation of an async media foundation transform (MFT) that uses DX12 video encode API via the backend D3D12 pipe objects.
## Files
| Files | Description |
| ----- | ---- |
| codecapi.cpp | implements ICodecAPI interface |
| dpb_buffer_manager.cpp | utility for dbp buffer creation and deletion |
| encode.cpp | contains codec agnostic encode related code |
| encoder_capabilities.cpp | utility for querying hardware capability from pipe |
| encode_av1.cpp | encode specific to av1 (currently stub only) |
| encode_h264.cpp | encode specific to h264 |
| encode_hevc.cpp | encode specific to hevc |
| hmft_entrypoints.cpp | entry point to hmft |
| mfbufferhelp.cpp | utility for mf buffer |
| mfd3dmanager.cpp | utility for managing d3d device |
| mfmediaeventgenerator.cpp | implements the IMFMediaEventGenerator interface |
| mfpipeinterop.cpp | utility for various type translation function between MF and pipe |
| mfrealtimeclientex.cpp | implements the IMFRealTimeClientEx interface|
| mfshutdown.cpp | implements the IMFShutdown interface |
| mftransform.cpp | implements the IMFTransform interface |
| reference_frames_tracker_av1.cpp | managing dbp and gop state for av1 (currently stub only)|
| reference_frames_tracker_h264.cpp | managing dbp and gop state for h264 |
| reference_frames_tracker_hevc.cpp | managing dbp and gop state for hevc |
| videobufferlock.cpp | utility for video buffer lock |
| wpptrace.cpp | wpp trace |
| wppconfig/ | folder containing wpp trace config |
| IDL/ | folder containing the IDL files for the MFT|
| test/ | folder containing the test code for the MFT|
Other files related to the MFT:
| Files | Description |
| ----- | ---- |
| src/gallium/targets/mediafoundation | dllmain and resourc files for MFT, builds the dll |
## Build
Current implementation is designed to build three differt codec (AV1, H264, HEVC) with the same code (note AV1 is stub right now).
You can set up the build to build a single codec without comingling of other codec's code or you can build several (include all) codecs together that has comingle code.
The comingle code currently comes from .\gallium\drivers\d3d12 folder.
To select one codec, you can do:
```
-Dvideo-codecs=h264enc -Dmediafoundation-codecs=h264enc
```
To select all codecs, you can do
```
-Dvideo-codecs=all -Dmediafoundation-codecs=all
```
Below is an example setup command that builds one codec
```
meson setup build/ --pkg-config-path="C:\lib\pkgconfig" -Dgallium-d3d12-graphics=disabled -Dintel-elk=false -Dmicrosoft-clc=disabled -Dllvm=disabled -Dvalgrind=disabled -Dlmsensors=disabled -Dzlib=disabled -Dzstd=disabled -Dxmlconfig=disabled -Dgles1=disabled -Dgles2=disabled -Degl=disabled -Dgbm=disabled -Dglx-direct=false -Denable-glcpp-tests=false -Dopengl=false -Dgallium-drivers=d3d12 -Dgallium-va=disabled -Dgallium-mediafoundation=enabled -Dc_args="/guard:cf /we4146 /we4308 /we4509 /we4510 /we4532 /we4533 /we4610 /we4700 /we4789 /wd4703" -Dc_link_args="/guard:cf /profile /DYNAMICBASE" -Dcpp_args="/guard:cf /we4146 /we4308 /we4509 /we4510 /we4532 /we4533 /we4610 /we4700 /we4789 /wd4703" -Dcpp_link_args="/guard:cf /profile /DYNAMICBASE" --default-library=static -Db_vscrt=mt -Dc_std=c17 -Dcpp_std=c++17 -Dmicrosoft-clc=disabled -Ddebug=false --buildtype=release -Dwarning_level=2 -Dvideo-codecs=h264enc -Dmediafoundation-codecs=h264enc -Dmediafoundation-store-dll=false -Dgallium-mediafoundation-test=true
```
To build the COM based HEVC codec, use the above command but replace all instances of h264enc with h265enc to setup the build. Similarly for the pending AV1 codec, replace h264enc with av1enc.
For debug builds, change the debug/buildtype to true, e.g.
```
-Ddebug=true --buildtype=true
```
For building the unit test, add the following option to the meson setup.
```
-Dgallium-mediafoundation-test=true
```
To build, run the following command from the mesa folder.
```
ninja -C build/ install
```
@@ -0,0 +1,122 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "dpb_buffer_manager.h"
#include "frontend/winsys_handle.h"
#include "gallium/drivers/d3d12/d3d12_interop_public.h"
#include "vl/vl_video_buffer.h"
#include "wpptrace.h"
#include "dpb_buffer_manager.tmh"
// retrieve a buffer from the pool
struct pipe_video_buffer *
dpb_buffer_manager::get_fresh_dpb_buffer()
{
for( auto &entry : m_pool )
{
if( !entry.used )
{
entry.used = true;
return entry.buffer;
}
}
MFE_ERROR( "[dx12 hmft 0x%p] failed to find a free buffer", m_logId );
assert( false ); // Did not find an unused buffer
return NULL;
}
// release a buffer back to the pool
void
dpb_buffer_manager::release_dpb_buffer( struct pipe_video_buffer *target )
{
for( auto &entry : m_pool )
{
if( entry.buffer == target )
{
entry.used = false;
break;
}
}
}
dpb_buffer_manager::dpb_buffer_manager( void *logId,
struct pipe_video_codec *codec,
unsigned width,
unsigned height,
enum pipe_format buffer_format,
unsigned pool_size,
HRESULT &hr )
: m_logId( logId ), m_codec( codec ), m_pool( pool_size, { NULL, false } )
{
m_template.width = width;
m_template.height = height;
m_template.buffer_format = buffer_format;
if( codec->context->screen->get_video_param( codec->context->screen,
codec->profile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_READABLE_RECONSTRUCTED_PICTURE ) != 0 )
{
m_template.bind = PIPE_BIND_SHARED | // Indicate we want shared resource capabilities
PIPE_BIND_RENDER_TARGET; // This is also required for opening shared resources in D3D11
}
for( auto &entry : m_pool )
{
entry.buffer = m_codec->create_dpb_buffer( m_codec, NULL, &m_template );
if( !entry.buffer )
{
MFE_ERROR( "[dx12 hmft 0x%p] create_dpb_buffer failed", m_logId );
assert( false );
hr = E_FAIL;
break;
}
}
if( FAILED( hr ) )
{
for( auto &entry : m_pool )
{
if( entry.buffer )
{
entry.buffer->destroy( entry.buffer );
}
}
}
}
dpb_buffer_manager::~dpb_buffer_manager()
{
for( auto &entry : m_pool )
{
if( entry.buffer )
{
entry.buffer->destroy( entry.buffer );
}
}
}
@@ -0,0 +1,60 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <vector>
#include "hmft_entrypoints.h"
class dpb_buffer_manager
{
public:
dpb_buffer_manager( void *logId,
struct pipe_video_codec *codec,
unsigned width,
unsigned height,
enum pipe_format buffer_format,
unsigned pool_size,
HRESULT &hr );
~dpb_buffer_manager();
// retrieve a buffer from the pool
struct pipe_video_buffer *get_fresh_dpb_buffer();
// release a buffer back to the pool
void release_dpb_buffer( struct pipe_video_buffer *target );
private:
const void *m_logId = {};
struct pipe_video_codec *m_codec = NULL;
struct pipe_video_buffer m_template = {};
struct dpb_buffer_manager_pool_entry
{
struct pipe_video_buffer *buffer;
bool used;
};
std::vector<struct dpb_buffer_manager_pool_entry> m_pool;
};
@@ -0,0 +1,702 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "hmft_entrypoints.h"
#include "mfbufferhelp.h"
#include "mfpipeinterop.h"
#include "wpptrace.h"
#include "encode.tmh"
// internal function to prepare the data needed to pass to DX12 encoder via DX12EncoderContext
// this include converting the input sample to a DX12 accepted sample. Note that codec specific
// handling is forward to PrepareForEncodeHelper
HRESULT
CDX12EncHMFT::PrepareForEncode( IMFSample *pSample, LPDX12EncodeContext *ppDX12EncodeContext )
{
HRESULT hr = S_OK;
struct pipe_fence_handle *pPipeEncoderInputFenceHandle = nullptr;
UINT64 pipeEncoderInputFenceHandleValue = 0u;
UINT unDiscontinuity = 0;
LPDX12EncodeContext pDX12EncodeContext;
UINT uiSubresourceIndex = 0;
UINT textureWidth = 0u;
UINT textureHeight = 0u;
bool bReceivedDirtyRectBlob = false;
uint32_t dirtyRectFrameNum = UINT32_MAX;
bool bReceivedMoveRegionBlob = false;
uint32_t moveRegionFrameNum = UINT32_MAX;
LONGLONG inputSampleTime = 0;
LONGLONG inputSampleDuration = 0;
ComPtr<IMFDXGIBuffer> spDXGIBuffer;
HANDLE hTexture = NULL;
winsys_handle winsysHandle = {};
// Check for Discontinuity
(void) pSample->GetUINT32( MFSampleExtension_Discontinuity, &unDiscontinuity );
if( unDiscontinuity )
{
MFE_INFO( "[dx12 hmft 0x%p] Discontinuity signaled on input sample", this );
m_bForceKeyFrame = TRUE;
}
CHECKNULL_GOTO( pDX12EncodeContext = new DX12EncodeContext( m_Codec ), E_OUTOFMEMORY, done );
CHECKNULL_GOTO( pDX12EncodeContext->pAsyncDPBToken = new reference_frames_tracker_dpb_async_token(), E_OUTOFMEMORY, done );
CHECKHR_GOTO( pSample->GetBufferByIndex( 0, &pDX12EncodeContext->spMediaBuffer ), done );
CHECKHR_GOTO( pSample->GetSampleTime( &inputSampleTime ), done );
CHECKHR_GOTO( pSample->GetSampleDuration( &inputSampleDuration ), done );
pDX12EncodeContext->inputSampleTime = inputSampleTime;
pDX12EncodeContext->inputSampleDuration = inputSampleDuration;
// If we can't get a DXGIBuffer out of this incoming buffer, then its a software-based buffer
if( FAILED( pDX12EncodeContext->spMediaBuffer.As( &spDXGIBuffer ) ) )
{
ComPtr<IMFSample> spSample;
ComPtr<IMFMediaBuffer> spBuffer;
// create sample allocator for SW input sample on demand to save video memory.
if( !m_spVideoSampleAllocator )
{
CHECKHR_GOTO( MFCreateVideoSampleAllocatorEx( IID_PPV_ARGS( &m_spVideoSampleAllocator ) ), done );
CHECKHR_GOTO( ConfigureSampleAllocator(), done );
}
// Allocate a video buffer
CHECKHR_GOTO( m_spVideoSampleAllocator->AllocateSample( &spSample ), done );
CHECKHR_GOTO( MFCopySample( spSample.Get(), pSample, m_spInputType.Get() ), done );
CHECKHR_GOTO( spSample->GetBufferByIndex( 0, &pDX12EncodeContext->spMediaBuffer ), done );
CHECKHR_GOTO( pDX12EncodeContext->spMediaBuffer.As( &spDXGIBuffer ), done );
debug_printf( "[dx12 hmft 0x%p] Software input sample\n", this );
}
CHECKHR_GOTO( spDXGIBuffer->GetSubresourceIndex( &uiSubresourceIndex ), done );
if( m_spDevice11 )
{
// D3D11 input sample path
ComPtr<IDXGIResource1> spDXGIResource1;
ComPtr<ID3D11Texture2D> spTexture;
ComPtr<ID3D11DeviceContext3> spDeviceContext3;
ComPtr<ID3D11DeviceContext4> spDeviceContext4;
D3D11_TEXTURE2D_DESC d3d11textureDescSrc;
D3D11_TEXTURE2D_DESC d3d11textureDescDst;
D3D11_TEXTURE2D_DESC desc = {};
CHECKHR_GOTO( spDXGIBuffer->GetResource( IID_PPV_ARGS( &spTexture ) ), done );
spTexture->GetDesc( &desc );
textureWidth = desc.Width;
textureHeight = desc.Height;
//
// Attempt to create a shared handle from the DX11 texture that can
// be opened as an ID3D12Resource to avoid a copy from DX11 -> DX12
// and place the opened video buffer from the shared resource in
// pDX12EncodeContext->pPipeVideoBuffer
// video_buffer_from_handle expects data to be on first subresource (e.g no texture array)
//
if( uiSubresourceIndex == 0 )
{
CHECKHR_GOTO( spTexture.As( &spDXGIResource1 ), done );
if( SUCCEEDED( spDXGIResource1->CreateSharedHandle( nullptr, DXGI_SHARED_RESOURCE_READ, nullptr, &hTexture ) ) )
{
// Open the pipe video buffer from the hTexture of the source DX11 texture directly
// as an ID3D12Resource, wrapped in pDX12EncodeContext->pPipeVideoBuffer
winsysHandle.handle = hTexture;
winsysHandle.type = WINSYS_HANDLE_TYPE_FD;
pDX12EncodeContext->pPipeVideoBuffer =
m_pPipeContext->video_buffer_from_handle( m_pPipeContext, NULL, &winsysHandle, 0 );
}
}
// On successful opening of the DX11 shared texture as an ID3D12Resource, wrapped in pDX12EncodeContext->pPipeVideoBuffer
// signal readiness to the consumer of the texture's fence
//
// Otherwise, if the interop without a copy into pDX12EncodeContext->pPipeVideoBuffer failed, fallback to doing the copy
// and placing the copy destination texture in pDX12EncodeContext->pPipeVideoBuffer
//
if( pDX12EncodeContext->pPipeVideoBuffer != nullptr )
{
m_spDevice11->GetImmediateContext3( &spDeviceContext3 );
CHECKHR_GOTO( spDeviceContext3.As( &spDeviceContext4 ), done );
// This will signal the staging fence the d3d12 mesa backend is consuming
spDeviceContext4->Signal( m_spStagingFence11.Get(), m_CurrentSyncFenceValue );
debug_printf( "[dx12 hmft 0x%p] DX11 *shared* input sample\n", this );
}
else
{
spTexture->GetDesc( &d3d11textureDescSrc );
// We need to create a shareable texture and copy into it
ComPtr<ID3D11Texture2D> spSharedTexture;
D3D11_BOX d3d11Box = { 0 };
d3d11textureDescDst = d3d11textureDescSrc;
d3d11textureDescDst.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
d3d11textureDescDst.BindFlags = D3D11_BIND_SHADER_RESOURCE;
d3d11textureDescDst.ArraySize = 1;
d3d11textureDescDst.Width = textureWidth;
d3d11textureDescDst.Height = textureHeight;
CHECKHR_GOTO( m_spDevice11->CreateTexture2D( &d3d11textureDescDst, nullptr, &spSharedTexture ), done );
// Open the pipe video buffer from the hTexture of the copy destination texture
CHECKHR_GOTO( spSharedTexture.As( &spDXGIResource1 ), done );
CHECKHR_GOTO( spDXGIResource1->CreateSharedHandle( nullptr, DXGI_SHARED_RESOURCE_READ, nullptr, &hTexture ), done );
debug_printf( "[dx12 hmft 0x%p] DX11 input sample\n", this );
winsysHandle.handle = hTexture;
winsysHandle.type = WINSYS_HANDLE_TYPE_FD;
CHECKNULL_GOTO( pDX12EncodeContext->pPipeVideoBuffer =
m_pPipeContext->video_buffer_from_handle( m_pPipeContext, NULL, &winsysHandle, 0 ),
MF_E_UNEXPECTED,
done );
// On successful opening of shared texture, submit the copy and signal readiness to the consumer of the texture
m_spDevice11->GetImmediateContext3( &spDeviceContext3 );
d3d11Box.right = d3d11textureDescSrc.Width;
d3d11Box.bottom = d3d11textureDescSrc.Height;
d3d11Box.back = 1;
spDeviceContext3
->CopySubresourceRegion( spSharedTexture.Get(), 0, 0, 0, 0, spTexture.Get(), uiSubresourceIndex, &d3d11Box );
// This will signal the staging fence the d3d12 mesa backend is consuming
// Since we're signaling from the D3D11 context on a shared fence, the signal
// will happen after the d3d11 context copy is done.
CHECKHR_GOTO( spDeviceContext3.As( &spDeviceContext4 ), done );
spDeviceContext4->Signal( m_spStagingFence11.Get(), m_CurrentSyncFenceValue );
}
}
else
{
// D3D12 input sample path
ComPtr<ID3D12Resource> spResource;
CHECKHR_GOTO( spDXGIBuffer->GetResource( IID_PPV_ARGS( &spResource ) ), done );
const D3D12_RESOURCE_DESC desc = spResource->GetDesc();
textureWidth = static_cast<UINT>( desc.Width );
textureHeight = static_cast<UINT>( desc.Height );
CHECKHR_GOTO(
spDXGIBuffer->GetUnknown( MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS( &pDX12EncodeContext->spSyncObjectCommands ) ),
done );
CHECKHR_GOTO( pDX12EncodeContext->spSyncObjectCommands->EnqueueResourceReadyWait( m_spStagingQueue.Get() ), done );
// This will signal the staging fence the d3d12 mesa backend is consuming
// Since we have a Wait() on spStagingQueue added by EnqueueResourceReadyWait, this will only happen after MF
// triggered completion on the input
m_spStagingQueue->Signal( m_spStagingFence12.Get(), m_CurrentSyncFenceValue );
winsysHandle.com_obj = spResource.Get();
winsysHandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
CHECKBOOL_GOTO( uiSubresourceIndex == 0,
MF_E_UNEXPECTED,
done ); // video_buffer_from_handle expects data to be on first subresource (e.g no texture array)
CHECKNULL_GOTO(
pDX12EncodeContext->pPipeVideoBuffer = m_pPipeContext->video_buffer_from_handle( m_pPipeContext, NULL, &winsysHandle, 0 ),
MF_E_UNEXPECTED,
done );
debug_printf( "[dx12 hmft 0x%p] DX12 input sample\n", this );
}
// Assign the staging queue to the encode context for use during buffer attachment
// even when the input is not DX12; we use it to queue the output buffer readiness
// from DX12 encoder output (completion) fences
pDX12EncodeContext->pSyncObjectQueue = m_spStagingQueue.Get();
assert( pDX12EncodeContext->pSyncObjectQueue );
//
// If two pass is disabled, we just need to set the input fence and input fence value
// to the input texture fence/value.
//
// Otherwise, when two pass is enabled, we need to downscale the input texture
// for which we need to sync the readiness of the input texture against
// the vpblit input fence, and then sync the encoder readiness fence (e.g pPicInfo->base.in_fence)
// against the vpblit output fence
//
if( !m_pPipeVideoCodec->two_pass.enable || ( m_pPipeVideoCodec->two_pass.pow2_downscale_factor == 0 ) )
{
pPipeEncoderInputFenceHandle = m_pPipeFenceHandle;
pipeEncoderInputFenceHandleValue = m_CurrentSyncFenceValue;
}
else
{ // ENCODE_WITH_TWO_PASS code block
// TODO: In case the app sends the downscaled input remove this
//
// Use VPBlit to downscale the input texture to generate the 1st pass
// downscaled input texture
//
struct pipe_video_buffer templ = {};
templ.buffer_format = pDX12EncodeContext->pPipeVideoBuffer->buffer_format;
templ.width = static_cast<uint32_t>(
std::ceil( pDX12EncodeContext->pPipeVideoBuffer->width / ( 1 << m_pPipeVideoCodec->two_pass.pow2_downscale_factor ) ) );
templ.height = static_cast<uint32_t>(
std::ceil( pDX12EncodeContext->pPipeVideoBuffer->height / ( 1 << m_pPipeVideoCodec->two_pass.pow2_downscale_factor ) ) );
pDX12EncodeContext->pDownscaledTwoPassPipeVideoBuffer = m_pPipeContext->create_video_buffer( m_pPipeContext, &templ );
struct pipe_vpp_desc vpblit_params = {};
vpblit_params.base.in_fence = m_pPipeFenceHandle; // input surface fence (driver input)
vpblit_params.base.in_fence_value = pipeEncoderInputFenceHandleValue; // input surface fence value (driver input)
vpblit_params.base.out_fence = &pPipeEncoderInputFenceHandle; // Output surface fence (driver output)
pipeEncoderInputFenceHandleValue = 0u; // pPipeEncoderInputFenceHandle is PIPE_FD_TYPE_NATIVE_SYNC so doesn't need the value
vpblit_params.base.input_format = pDX12EncodeContext->pPipeVideoBuffer->buffer_format;
vpblit_params.base.output_format = pDX12EncodeContext->pDownscaledTwoPassPipeVideoBuffer->buffer_format;
vpblit_params.src_region.x0 = 0u;
vpblit_params.src_region.y0 = 0u;
vpblit_params.src_region.x1 = pDX12EncodeContext->pPipeVideoBuffer->width;
vpblit_params.src_region.y1 = pDX12EncodeContext->pPipeVideoBuffer->height;
vpblit_params.dst_region.x0 = 0u;
vpblit_params.dst_region.y0 = 0u;
vpblit_params.dst_region.x1 = pDX12EncodeContext->pDownscaledTwoPassPipeVideoBuffer->width;
vpblit_params.dst_region.y1 = pDX12EncodeContext->pDownscaledTwoPassPipeVideoBuffer->height;
m_pPipeVideoBlitter->begin_frame( m_pPipeVideoBlitter,
pDX12EncodeContext->pDownscaledTwoPassPipeVideoBuffer,
&vpblit_params.base );
CHECKBOOL_GOTO(
( m_pPipeVideoBlitter->process_frame( m_pPipeVideoBlitter, pDX12EncodeContext->pPipeVideoBuffer, &vpblit_params ) == 0 ),
MF_E_UNEXPECTED,
done );
CHECKBOOL_GOTO( ( m_pPipeVideoBlitter->end_frame( m_pPipeVideoBlitter,
pDX12EncodeContext->pDownscaledTwoPassPipeVideoBuffer,
&vpblit_params.base ) == 0 ),
MF_E_UNEXPECTED,
done );
m_pPipeVideoBlitter->flush( m_pPipeVideoBlitter );
assert( pPipeEncoderInputFenceHandle ); // Driver must have returned the completion fence
pDX12EncodeContext->pDownscaledTwoPassPipeVideoBufferCompletionFence =
pPipeEncoderInputFenceHandle; // For destruction of the fence later
}
{
// Get HW Support Surface Alignment to check against input sample
const uint32_t surfaceWidthAlignment = 1 << m_EncoderCapabilities.m_HWSupportSurfaceAlignment.bits.log2_width_alignment;
const uint32_t surfaceHeightAlignment = 1 << m_EncoderCapabilities.m_HWSupportSurfaceAlignment.bits.log2_height_alignment;
// validate texture dimensions with surface alignment here for now, will add handling for non-aligned textures later
if( textureWidth % surfaceWidthAlignment != 0 || textureHeight % surfaceHeightAlignment != 0 )
{
assert( false );
}
}
pDX12EncodeContext->textureWidth = textureWidth;
pDX12EncodeContext->textureHeight = textureHeight;
if( m_uiDirtyRectEnabled )
{
UINT32 cBlob = 0;
pSample->GetBlobSize( MFSampleExtension_DirtyRects, &cBlob );
if( cBlob >= sizeof( DIRTYRECT_INFO ) )
{
if( m_pDirtyRectBlob.size() < cBlob )
{
m_pDirtyRectBlob.resize( cBlob );
}
if( S_OK == pSample->GetBlob( MFSampleExtension_DirtyRects, m_pDirtyRectBlob.data(), cBlob, &cBlob ) )
{
DIRTYRECT_INFO *pDirtyRectInfo = (DIRTYRECT_INFO *) m_pDirtyRectBlob.data();
dirtyRectFrameNum = pDirtyRectInfo->FrameNumber;
bReceivedDirtyRectBlob = true;
}
}
}
// Try to get MFSampleExtension_MoveRegions blob only when the HW supports it.
if( m_EncoderCapabilities.m_HWSupportMoveRects.bits.supports_precision_full_pixel &&
m_EncoderCapabilities.m_HWSupportMoveRects.bits.max_motion_hints > 0 )
{
UINT32 cMoveRegionBlob = 0;
pSample->GetBlobSize( MFSampleExtension_MoveRegions, &cMoveRegionBlob );
if( cMoveRegionBlob >= sizeof( MOVEREGION_INFO ) )
{
if( m_pMoveRegionBlob.size() < cMoveRegionBlob )
{
m_pMoveRegionBlob.resize( cMoveRegionBlob );
}
if( S_OK ==
pSample->GetBlob( MFSampleExtension_MoveRegions, m_pMoveRegionBlob.data(), cMoveRegionBlob, &cMoveRegionBlob ) )
{
MOVEREGION_INFO *pMoveRegionInfo = (MOVEREGION_INFO *) m_pMoveRegionBlob.data();
moveRegionFrameNum = pMoveRegionInfo->FrameNumber;
bReceivedMoveRegionBlob = true;
}
}
}
if( m_pGOPTracker == nullptr )
{
CHECKHR_GOTO( CreateGOPTracker( textureWidth, textureHeight ), done );
}
{
bool markLTR = false;
bool useLTR = false;
uint32_t markLTRindex = 0;
uint32_t useLTRbitmap = 0;
if( m_uiMaxLongTermReferences > 0 )
{
if( m_bMarkLTRFrameSet )
{
markLTR = true;
markLTRindex = m_uiMarkLTRFrame;
assert( m_uiMarkLTRFrame < m_uiMaxLongTermReferences ); // TODO: add check at CodecAPI level
m_bMarkLTRFrameSet = FALSE;
}
if( m_bUseLTRFrameSet )
{
useLTR = true;
useLTRbitmap = m_uiUseLTRFrame;
m_bUseLTRFrameSet = FALSE;
}
}
CHECKHR_GOTO( m_pGOPTracker->begin_frame( pDX12EncodeContext->pAsyncDPBToken,
m_bForceKeyFrame,
markLTR,
markLTRindex,
useLTR,
useLTRbitmap,
m_bLayerCountSet,
m_uiLayerCount,
bReceivedDirtyRectBlob,
dirtyRectFrameNum ),
done );
if( m_bForceKeyFrame )
{
m_bForceKeyFrame = FALSE;
}
}
{
//
// Create resources for output GPU frame stats
//
if( m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput.bits.supported && m_uiVideoSatdMapBlockSize > 0 )
{
if( !m_spSatdStatsBufferPool )
{
uint32_t block_size = ( 1 << m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput.bits.log2_values_block_size );
pipe_format format = (enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsSATDMapOutput.bits.pipe_pixel_format;
uint32_t width0 = static_cast<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
uint16_t height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( block_size ) ) );
CHECKHR_GOTO( stats_buffer_manager::Create( this,
m_spDevice.Get(),
MFSampleExtension_VideoEncodeSatdMap,
width0,
height0,
format,
1,
MFT_STAT_POOL_MIN_SIZE,
m_spSatdStatsBufferPool.GetAddressOf() ),
done );
}
pDX12EncodeContext->pPipeResourceSATDMapStats = m_spSatdStatsBufferPool->get_new_tracked_buffer( m_pVlScreen );
CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceSATDMapStats, E_OUTOFMEMORY, done );
}
if( m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput.bits.supported && m_uiVideoOutputBitsUsedMapBlockSize > 0 )
{
if( !m_spBitsUsedStatsBufferPool )
{
uint32_t block_size =
( 1 << m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput.bits.log2_values_block_size );
pipe_format format =
(enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsRCBitAllocationMapOutput.bits.pipe_pixel_format;
uint32_t width0 = static_cast<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
uint16_t height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( block_size ) ) );
CHECKHR_GOTO( stats_buffer_manager::Create( this,
m_spDevice.Get(),
MFSampleExtension_VideoEncodeBitsUsedMap,
width0,
height0,
format,
1,
MFT_STAT_POOL_MIN_SIZE,
m_spBitsUsedStatsBufferPool.GetAddressOf() ),
done );
}
pDX12EncodeContext->pPipeResourceRCBitAllocMapStats = m_spBitsUsedStatsBufferPool->get_new_tracked_buffer( m_pVlScreen );
CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceRCBitAllocMapStats, E_OUTOFMEMORY, done );
}
if( m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.supported && m_uiVideoOutputQPMapBlockSize > 0 )
{
if( !m_spQPMapStatsBufferPool )
{
uint32_t block_size = ( 1 << m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.log2_values_block_size );
pipe_format format = (enum pipe_format) m_EncoderCapabilities.m_HWSupportStatsQPMapOutput.bits.pipe_pixel_format;
uint32_t width0 = static_cast<uint32_t>( std::ceil( m_uiOutputWidth / static_cast<float>( block_size ) ) );
uint16_t height0 = static_cast<uint16_t>( std::ceil( m_uiOutputHeight / static_cast<float>( block_size ) ) );
CHECKHR_GOTO( stats_buffer_manager::Create( this,
m_spDevice.Get(),
MFSampleExtension_VideoEncodeQPMap,
width0,
height0,
format,
1,
MFT_STAT_POOL_MIN_SIZE,
m_spQPMapStatsBufferPool.GetAddressOf() ),
done );
}
pDX12EncodeContext->pPipeResourceQPMapStats = m_spQPMapStatsBufferPool->get_new_tracked_buffer( m_pVlScreen );
CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceQPMapStats, E_OUTOFMEMORY, done );
}
if( m_EncoderCapabilities.m_PSNRStatsSupport.bits.supports_y_channel && m_bVideoEnableFramePsnrYuv )
{
struct pipe_resource buffer_templ = {};
buffer_templ.width0 = 3 * sizeof( float ); // Up to 3 float components Y, U, V
buffer_templ.target = PIPE_BUFFER;
// PIPE_USAGE_STAGING allocates resource in L0 (System Memory) heap
// and avoid a bunch of roundtrips for uploading/reading back the bitstream headers
// The GPU writes once the slice data (if dGPU over the PCIe bus) and all the other
// uploads (e.g bitstream headers from CPU) and readbacks to output MFSamples
// happen without moving data between L0/L1 pools
buffer_templ.usage = PIPE_USAGE_STAGING;
buffer_templ.format = PIPE_FORMAT_R8_UINT;
buffer_templ.height0 = 1;
buffer_templ.depth0 = 1;
buffer_templ.array_size = 1;
CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourcePSNRStats =
m_pVlScreen->pscreen->resource_create( m_pVlScreen->pscreen, &buffer_templ ),
E_OUTOFMEMORY,
done );
}
}
// Encode region of interest
// When m_bVideoROIEnabled, app can (or not) set MFSampleExtension_ROIRectangle on separate frames optionally
if( m_bVideoROIEnabled )
{
UINT32 uiROIBlobOutSize = 0;
pSample->GetBlob( MFSampleExtension_ROIRectangle,
(UINT8 *) &pDX12EncodeContext->video_roi_area,
sizeof( ROI_AREA ),
&uiROIBlobOutSize );
if( uiROIBlobOutSize > 0 )
{
// Check the Blob size matches the struct size we expect
CHECKBOOL_GOTO( uiROIBlobOutSize == sizeof( ROI_AREA ), MF_E_UNEXPECTED, done );
// When requested QPDelta == 0, just don't enable roi since it won't have any effect
if( pDX12EncodeContext->video_roi_area.QPDelta != 0 )
{
// Check for hardware support for delta QP
CHECKBOOL_GOTO( m_EncoderCapabilities.m_HWSupportsVideoEncodeROI.bits.roi_rc_qp_delta_support == 1,
MF_E_UNEXPECTED,
done );
pDX12EncodeContext->bROI = TRUE;
}
}
}
pDX12EncodeContext->pVlScreen = m_pVlScreen; // weakref
// Call the helper for encoder specific work
pDX12EncodeContext->encoderPicInfo.base.in_fence = pPipeEncoderInputFenceHandle;
pDX12EncodeContext->encoderPicInfo.base.in_fence_value = pipeEncoderInputFenceHandleValue;
CHECKHR_GOTO( PrepareForEncodeHelper( pDX12EncodeContext,
bReceivedDirtyRectBlob,
dirtyRectFrameNum,
bReceivedMoveRegionBlob,
moveRegionFrameNum ),
done );
// Needs to be run after PrepareForEncodeHelper to know if current frame is used as reference
// Only allocate reconstructed picture copy buffer if feature is enabled and supported
if( ( m_VideoReconstructedPictureMode == RECON_PIC_OUTPUT_MODE_BLIT_COPY ) &&
m_EncoderCapabilities.m_bHWSupportReadableReconstructedPicture )
{
if( !m_spReconstructedPictureBufferPool )
{
CHECKHR_GOTO( stats_buffer_manager::Create( this,
m_spDevice.Get(),
MFSampleExtension_VideoEncodeD3D12ReconstructedPicture,
pDX12EncodeContext->pPipeVideoBuffer->width,
static_cast<uint16_t>( pDX12EncodeContext->pPipeVideoBuffer->height ),
pDX12EncodeContext->pPipeVideoBuffer->buffer_format,
1,
MFT_STAT_POOL_MIN_SIZE,
m_spReconstructedPictureBufferPool.GetAddressOf() ),
done );
}
// Only allocate the reconstructed picture copy buffer if the current frame is used as reference
if( pDX12EncodeContext->get_current_dpb_pic_resource() != nullptr )
{
pDX12EncodeContext->pipeResourceReconstructedPictureCopyMode = true;
pDX12EncodeContext->pPipeResourceReconstructedPicture =
m_spReconstructedPictureBufferPool->get_new_tracked_buffer( m_pVlScreen );
pDX12EncodeContext->PipeResourceReconstructedPictureSubresource = 0;
CHECKNULL_GOTO( pDX12EncodeContext->pPipeResourceReconstructedPicture, E_OUTOFMEMORY, done );
}
}
{
struct pipe_resource templ = {};
// Prefer using sliced buffers + fence notifications when supported to reduce latency if
// user requested multiple slices
// Otherwise fallback to full frame encoding fence notification using a single output buffer
uint32_t num_output_buffers = 1u;
#if MFT_CODEC_H264ENC
num_output_buffers = std::max( 1u, pDX12EncodeContext->encoderPicInfo.h264enc.num_slice_descriptors );
#elif MFT_CODEC_H265ENC
num_output_buffers = std::max( 1u, pDX12EncodeContext->encoderPicInfo.h265enc.num_slice_descriptors );
#elif MFT_CODEC_AV1ENC
num_output_buffers =
std::max( 1u, pDX12EncodeContext->encoderPicInfo.av1enc.tile_rows * pDX12EncodeContext->encoderPicInfo.av1enc.tile_cols );
#endif
if( m_bSliceGenerationModeSet && pDX12EncodeContext->IsSliceAutoModeEnabled() )
{
num_output_buffers = std::max( 128u, m_EncoderCapabilities.m_uiMaxHWSupportedMaxSlices );
}
// Minimum per-slice buffer size to prevent excessively small allocations.
// This is especially important in PIPE_SLICE_MODE_AUTO where num_output_buffers
// can be set to the maximum possible slices, leading to very small per-slice
// buffer sizes that may be insufficient for actual bitstream data.
const uint32_t min_slice_buffer_size = 256 * 1024; // 256KB
pDX12EncodeContext->sliceNotificationMode = D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM_NOTIFICATION_MODE_FULL_FRAME;
if( m_bSliceGenerationModeSet && ( m_uiSliceGenerationMode > 0 ) &&
( num_output_buffers > 1 ) /* IHV driver requires > 1 slices */ )
{
pDX12EncodeContext->sliceNotificationMode = D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM_NOTIFICATION_MODE_SUBREGIONS;
if( m_EncoderCapabilities.m_HWSupportSlicedFences.bits.multiple_buffers_required )
{
// Buffer byte size for sliced buffers + notifications with multiple individual buffers per slice
// Try a rough estimation of per slice bitstream size as: frame_size / num slices
// Be careful with the allocation size of slice buffers, when the number of slices is high
// and we run in LowLatency = 0, we can start thrashing when trying to MakeResident lots
// of big allocations in short amounts of time (num slices x num in flight frames)
templ.width0 = std::max( ( m_uiMaxOutputBitstreamSize / num_output_buffers ), min_slice_buffer_size );
}
else
{
// Buffer byte size for sliced buffers + notifications with a single buffer (suballocated by driver for each slice)
templ.width0 = m_uiMaxOutputBitstreamSize;
}
}
else
{
// Buffer byte size for full frame bitstream (when num_output_buffers == 1)
templ.width0 = m_uiMaxOutputBitstreamSize;
}
templ.target = PIPE_BUFFER;
// PIPE_USAGE_STAGING allocates resource in L0 (System Memory) heap
// and avoid a bunch of roundtrips for uploading/reading back the bitstream headers
// The GPU writes once the slice data (if dGPU over the PCIe bus) and all the other
// uploads (e.g bitstream headers from CPU) and readbacks to output MFSamples
// happen without moving data between L0/L1 pools
templ.usage = PIPE_USAGE_STAGING;
templ.format = PIPE_FORMAT_R8_UINT;
templ.height0 = 1;
templ.depth0 = 1;
templ.array_size = 1;
pDX12EncodeContext->pOutputBitRes.resize( num_output_buffers, NULL );
pDX12EncodeContext->pSliceFences.resize( num_output_buffers, NULL );
pDX12EncodeContext->pLastSliceFence = NULL;
for( uint32_t slice_idx = 0; slice_idx < num_output_buffers; slice_idx++ )
{
if( ( slice_idx > 0 ) && !m_EncoderCapabilities.m_HWSupportSlicedFences.bits.multiple_buffers_required )
{
// sliced buffers + notifications with a single buffer (suballocated by driver for each slice)
// Increment reference count since we're sharing the same resource across multiple indices
// and the context destructor will release each index separately
pipe_resource_reference( &pDX12EncodeContext->pOutputBitRes[slice_idx], pDX12EncodeContext->pOutputBitRes[0] );
}
else
{
// sliced buffers + notifications with multiple individual buffers per slice
// or, full frame bitstream (when num_output_buffers == 1)
CHECKNULL_GOTO(
pDX12EncodeContext->pOutputBitRes[slice_idx] = m_pVlScreen->pscreen->resource_create( m_pVlScreen->pscreen, &templ ),
E_OUTOFMEMORY,
done );
}
}
}
m_CurrentSyncFenceValue++; // increment the fence value for the next sync fence
done:
if( SUCCEEDED( hr ) )
{
*ppDX12EncodeContext = pDX12EncodeContext;
pDX12EncodeContext = nullptr;
}
else
{
MFE_ERROR( "[dx12 hmft 0x%p] PrepareForEncode - hr=0x%x", this, hr );
}
SAFE_DELETE( pDX12EncodeContext );
SAFE_CLOSEHANDLE( hTexture );
return hr;
}
// utility function to validate the user passed in dirty rects
HRESULT
CDX12EncHMFT::ValidateDirtyRects( const LPDX12EncodeContext pDX12EncodeContext, const DIRTYRECT_INFO *pDirtyRectInfo )
{
HRESULT hr = S_OK;
const UINT uiNumDirtyRects = pDirtyRectInfo->NumDirtyRects;
const LONG textureWidth = static_cast<LONG>( pDX12EncodeContext->textureWidth );
const LONG textureHeight = static_cast<LONG>( pDX12EncodeContext->textureHeight );
for( UINT i = 0; i < uiNumDirtyRects; i++ )
{
if( pDirtyRectInfo->DirtyRects[i].left < 0 || pDirtyRectInfo->DirtyRects[i].top < 0 ||
pDirtyRectInfo->DirtyRects[i].right < pDirtyRectInfo->DirtyRects[i].left ||
pDirtyRectInfo->DirtyRects[i].bottom < pDirtyRectInfo->DirtyRects[i].top ||
pDirtyRectInfo->DirtyRects[i].right > textureWidth || pDirtyRectInfo->DirtyRects[i].bottom > textureHeight )
{
debug_printf( "MFT: invalid dirty rect %d (%d, %d, %d, %d) received\n",
i,
pDirtyRectInfo->DirtyRects[i].left,
pDirtyRectInfo->DirtyRects[i].top,
pDirtyRectInfo->DirtyRects[i].right,
pDirtyRectInfo->DirtyRects[i].bottom );
CHECKHR_GOTO( E_INVALIDARG, done );
}
}
done:
if( FAILED( hr ) )
{
MFE_ERROR( "[dx12 hmft 0x%p] ValidateDirtyRects - hr=0x%x", this, hr );
}
return hr;
}
@@ -0,0 +1,150 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#if MFT_CODEC_AV1ENC
#include "hmft_entrypoints.h"
#include "mfbufferhelp.h"
#include "mfpipeinterop.h"
extern DWORD
CalculateQualityFromQP( DWORD QP );
HRESULT
CDX12EncHMFT::UpdateAV1EncPictureDesc( pipe_av1_enc_picture_desc *pPicInfo )
{
HRESULT hr = S_OK;
// done:
return hr;
}
HRESULT
CDX12EncHMFT::PrepareForEncodeHelper( LPDX12EncodeContext pDX12EncodeContext,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum,
bool moveRegionFrameNumSet,
uint32_t moveRegionFrameNum )
{
HRESULT hr = S_OK;
// done:
return hr;
}
HRESULT
CDX12EncHMFT::GetCodecPrivateData( LPBYTE pSPSPPSData, DWORD dwSPSPPSDataLen, LPDWORD lpdwSPSPPSDataLen )
{
HRESULT hr = S_OK;
// done:
return hr;
}
static HRESULT
ConvertLevelToAVEncAV1VLevel( UINT32 uiLevel, eAVEncAV1VLevel &level )
{
HRESULT hr = S_OK;
level = eAVEncAV1VLevel5;
switch( uiLevel )
{
case(UINT32) -1: // -1 means auto
level = eAVEncAV1VLevel5;
break;
case 0:
level = eAVEncAV1VLevel2;
break;
case 1:
level = eAVEncAV1VLevel2_1;
break;
case 4:
level = eAVEncAV1VLevel3;
break;
case 5:
level = eAVEncAV1VLevel3_1;
break;
case 8:
level = eAVEncAV1VLevel4;
break;
case 9:
level = eAVEncAV1VLevel4_1;
break;
case 12:
level = eAVEncAV1VLevel5;
break;
case 13:
level = eAVEncAV1VLevel5_1;
break;
case 14:
level = eAVEncAV1VLevel5_2;
break;
case 15:
level = eAVEncAV1VLevel5_3;
break;
case 16:
level = eAVEncAV1VLevel6;
break;
case 17:
level = eAVEncAV1VLevel6_1;
break;
case 18:
level = eAVEncAV1VLevel6_2;
break;
case 19:
level = eAVEncAV1VLevel6_3;
break;
default:
hr = MF_E_INVALIDMEDIATYPE;
break;
}
return hr;
}
HRESULT
CDX12EncHMFT::CheckMediaTypeLevel(
IMFMediaType *pmt, int width, int height, const encoder_capabilities &encoderCapabilities, eAVEncAV1VLevel *pLevel ) const
{
HRESULT hr = S_OK;
UINT32 uiLevel = (UINT32) -1;
uiLevel = MFGetAttributeUINT32( pmt, MF_MT_VIDEO_LEVEL, uiLevel );
enum eAVEncAV1VLevel AVEncLevel;
CHECKHR_GOTO( ConvertLevelToAVEncAV1VLevel( uiLevel, AVEncLevel ), done );
if( pLevel )
{
*pLevel = AVEncLevel;
}
done:
return hr;
}
UINT32
CDX12EncHMFT::GetMaxReferences( unsigned int width, unsigned int height )
{
UINT32 uiMaxReferences = PIPE_AV1_REFS_PER_FRAME;
return uiMaxReferences;
}
HRESULT
CDX12EncHMFT::CreateGOPTracker( uint32_t textureWidth, uint32_t textureHeight )
{
HRESULT hr = E_NOTIMPL;
return hr;
}
#endif
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,198 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <utility>
#include "gallium/drivers/d3d12/d3d12_interop_public.h"
#include <encoder_capabilities.h>
#include "wpptrace.h"
#include "encoder_capabilities.tmh"
// Initializes encoder capabilities by querying hardware-specific parameters from pipe given the video profile.
HRESULT
encoder_capabilities::initialize( pipe_screen *pScreen, pipe_video_profile videoProfile )
{
HRESULT hr = S_OK;
m_uiMaxWidth = pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_MAX_WIDTH );
m_uiMaxHeight = pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_MAX_HEIGHT );
m_uiMinWidth = pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_MIN_WIDTH );
m_uiMinHeight = pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_MIN_HEIGHT );
m_uiMaxTemporalLayers =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_MAX_TEMPORAL_LAYERS );
// On some systems this is coming back as zero? Set it to 1 slice per frame in that case
m_uiMaxHWSupportedMaxSlices = std::max(
1,
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME ) );
UINT uiMaxHWSupportedL0L1References =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME );
m_uiMaxHWSupportedL0References = ( uiMaxHWSupportedL0L1References & 0xffff ); // lower 16 bits
m_uiMaxHWSupportedL1References = ( ( uiMaxHWSupportedL0L1References >> 16 ) & 0xffff ); // upper 16 bits
m_uiMaxHWSupportedLongTermReferences = pScreen->get_video_param( pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_MAX_LONG_TERM_REFERENCES_PER_FRAME );
m_uiMaxHWSupportedDPBCapacity =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_MAX_DPB_CAPACITY );
m_uiMaxHWSupportedQualityVsSpeedLevel =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL );
m_bHWSupportsMaxFrameSize =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_SUPPORTS_MAX_FRAME_SIZE );
m_bHWSupportsQualityVBRRateControlMode =
( pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_RATE_CONTROL_QVBR ) ==
1 );
m_HWSupportsIntraRefreshModes =
(enum pipe_video_enc_intra_refresh_mode)
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_INTRA_REFRESH );
m_HWSupportedMetadataFlags =
(enum pipe_video_feedback_metadata_type) pScreen->get_video_param( pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_SUPPORTS_FEEDBACK_METADATA );
m_HWSupportedDisableDBKH264ModeFlags = (enum pipe_video_h264_enc_dbk_filter_mode_flags) pScreen->get_video_param(
pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_H264_DISABLE_DBK_FILTER_MODES_SUPPORTED );
if( m_HWSupportsIntraRefreshModes )
{
m_uiMaxHWSupportedIntraRefreshSize = pScreen->get_video_param( pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_INTRA_REFRESH_MAX_DURATION );
}
m_bHWSupportsH264CABACEncode =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_H264_SUPPORTS_CABAC_ENCODE );
m_HWSupportsVideoEncodeROI.value = static_cast<uint32_t>(
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_ROI ) );
m_HWSupportH265BlockSizes.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_HEVC_BLOCK_SIZES );
m_HWSupportH265RangeExtension.value = pScreen->get_video_param( pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_HEVC_RANGE_EXTENSION_SUPPORT );
m_HWSupportH265RangeExtensionFlags.value = pScreen->get_video_param( pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_HEVC_RANGE_EXTENSION_FLAGS_SUPPORT );
m_HWSupportSurfaceAlignment.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_SURFACE_ALIGNMENT );
m_HWSupportDirtyRects.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_DIRTY_RECTS );
m_HWSupportMoveRects.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_MOVE_RECTS );
m_HWSupportStatsQPMapOutput.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_GPU_STATS_QP_MAP );
m_HWSupportStatsSATDMapOutput.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_GPU_STATS_SATD_MAP );
m_HWSupportStatsRCBitAllocationMapOutput.value = pScreen->get_video_param( pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_GPU_STATS_RATE_CONTROL_BITS_MAP );
m_HWSupportSlicedFences.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_SLICED_NOTIFICATIONS );
m_HWSupportDirtyGPUMaps.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_DIRTY_MAPS );
m_HWSupportQPGPUMaps.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_QP_MAPS );
m_HWSupportMotionGPUMaps.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_MOTION_VECTOR_MAPS );
uint32_t supportedSliceStructures =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE );
/* App-controlled slice/tile partitioning: any mode where the application picks the
* partitioning (including a single subregion via FULL_FRAME), as opposed to AUTO where the
* driver decides. Covers all PIPE_VIDEO_CAP_SLICE_STRUCTURE_* bits except AUTO. */
constexpr uint32_t appControlledPartitioningMask =
PIPE_VIDEO_CAP_SLICE_STRUCTURE_POWER_OF_TWO_ROWS |
PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_ROWS |
PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS |
PIPE_VIDEO_CAP_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS |
PIPE_VIDEO_CAP_SLICE_STRUCTURE_ARBITRARY_ROWS |
PIPE_VIDEO_CAP_SLICE_STRUCTURE_MAX_SLICE_SIZE;
m_bHWSupportsAppControlledSlicePartitioning = ( ( supportedSliceStructures & appControlledPartitioningMask ) != 0 );
m_bHWSupportSliceModeMB = ( ( supportedSliceStructures & PIPE_VIDEO_CAP_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS ) != 0 );
m_bHWSupportSliceModeBits = ( ( supportedSliceStructures & PIPE_VIDEO_CAP_SLICE_STRUCTURE_MAX_SLICE_SIZE ) != 0 );
m_bHWSupportSliceModeMBRow = ( ( supportedSliceStructures & PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS ) != 0 );
m_bHWSupportSliceModeAuto = ( ( supportedSliceStructures & PIPE_VIDEO_CAP_SLICE_STRUCTURE_AUTO ) != 0 );
m_TwoPassSupport.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_TWO_PASS );
m_PSNRStatsSupport.value =
pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_GPU_STATS_PSNR );
d3d12_interop_device_info1 screen_interop_info = {};
bool successQuery =
pScreen->interop_query_device_info( pScreen, sizeof( d3d12_interop_device_info1 ), &screen_interop_info ) != 0;
m_bHWSupportsQueuePriorityManagement = successQuery && screen_interop_info.set_context_queue_priority_manager != NULL;
m_HWSupportSpatialAdaptiveQuantization.value = pScreen->get_video_param( pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_SPATIAL_ADAPTIVE_QUANTIZATION );
m_bHWSupportReadableReconstructedPicture = pScreen->get_video_param( pScreen,
videoProfile,
PIPE_VIDEO_ENTRYPOINT_ENCODE,
PIPE_VIDEO_CAP_ENC_READABLE_RECONSTRUCTED_PICTURE ) != 0;
if( !m_bHWSupportsAppControlledSlicePartitioning && !m_bHWSupportSliceModeAuto )
{
MFE_ERROR( "[dx12 hmft 0x%p] HW supports neither app-controlled slice partitioning nor AUTO slice mode (check agility sdk)\n", m_logId );
hr = E_NOTIMPL;
}
return hr;
}
@@ -0,0 +1,151 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#define UNICODE
#include <string>
#include <wtypes.h>
#include "pipe_headers.h"
class encoder_capabilities
{
public:
encoder_capabilities( void *logId ) : m_logId { logId } { };
~encoder_capabilities() { };
HRESULT initialize( pipe_screen *pScreen, pipe_video_profile profile );
// Cached underlying backend pipe caps (avoid querying on each frame)
// PIPE_VIDEO_CAP_MAX_WIDTH
UINT m_uiMaxWidth = 0;
// PIPE_VIDEO_CAP_MAX_HEIGHT
UINT m_uiMaxHeight = 0;
// PIPE_VIDEO_CAP_MIN_WIDTH
UINT m_uiMinWidth = 0;
// PIPE_VIDEO_CAP_MIN_HEIGHT
UINT m_uiMinHeight = 0;
// PIPE_VIDEO_CAP_MAX_TEMPORAL_LAYERS
UINT m_uiMaxTemporalLayers = 0;
// PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME
UINT m_uiMaxHWSupportedMaxSlices = 0;
// PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME
UINT m_uiMaxHWSupportedL0References = 0;
UINT m_uiMaxHWSupportedL1References = 0;
// PIPE_VIDEO_CAP_ENC_MAX_LONG_TERM_REFERENCES_PER_FRAME
UINT m_uiMaxHWSupportedLongTermReferences = 0;
// PIPE_VIDEO_CAP_ENC_MAX_DPB_CAPACITY
UINT m_uiMaxHWSupportedDPBCapacity = 0;
// PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL
UINT m_uiMaxHWSupportedQualityVsSpeedLevel = 0;
// PIPE_VIDEO_CAP_ENC_SUPPORTS_MAX_FRAME_SIZE
BOOL m_bHWSupportsMaxFrameSize = FALSE;
// PIPE_VIDEO_CAP_ENC_RATE_CONTROL_QVBR
BOOL m_bHWSupportsQualityVBRRateControlMode = FALSE;
// PIPE_VIDEO_CAP_ENC_INTRA_REFRESH
enum pipe_video_enc_intra_refresh_mode m_HWSupportsIntraRefreshModes = PIPE_VIDEO_ENC_INTRA_REFRESH_NONE;
// PIPE_VIDEO_CAP_ENC_SUPPORTS_FEEDBACK_METADATA
enum pipe_video_feedback_metadata_type m_HWSupportedMetadataFlags = PIPE_VIDEO_FEEDBACK_METADATA_TYPE_BITSTREAM_SIZE;
// PIPE_VIDEO_CAP_ENC_H264_DISABLE_DBK_FILTER_MODES_SUPPORTED
enum pipe_video_h264_enc_dbk_filter_mode_flags m_HWSupportedDisableDBKH264ModeFlags = {};
// PIPE_VIDEO_CAP_ENC_INTRA_REFRESH_MAX_DURATION
UINT m_uiMaxHWSupportedIntraRefreshSize = 0;
// PIPE_VIDEO_CAP_ENC_H264_SUPPORTS_CABAC_ENCODE
UINT m_bHWSupportsH264CABACEncode = 0;
// PIPE_VIDEO_CAP_ENC_ROI
union pipe_enc_cap_roi m_HWSupportsVideoEncodeROI = {};
// PIPE_VIDEO_CAP_ENC_HEVC_BLOCK_SIZES
union pipe_h265_enc_cap_block_sizes m_HWSupportH265BlockSizes = {};
union pipe_h265_enc_cap_range_extension m_HWSupportH265RangeExtension = {};
union pipe_h265_enc_cap_range_extension_flags m_HWSupportH265RangeExtensionFlags = {};
// PIPE_VIDEO_CAP_ENC_SURFACE_ALIGNMENT
union pipe_enc_cap_surface_alignment m_HWSupportSurfaceAlignment = {};
// CPU dirty rects array
union pipe_enc_cap_dirty_info m_HWSupportDirtyRects = {};
union pipe_enc_cap_move_rect m_HWSupportMoveRects = {};
union pipe_enc_cap_gpu_stats_map m_HWSupportStatsQPMapOutput = {};
union pipe_enc_cap_gpu_stats_map m_HWSupportStatsSATDMapOutput = {};
union pipe_enc_cap_gpu_stats_map m_HWSupportStatsRCBitAllocationMapOutput = {};
union pipe_enc_cap_sliced_notifications m_HWSupportSlicedFences = {};
// GPU dirty map texture
union pipe_enc_cap_dirty_info m_HWSupportDirtyGPUMaps = {};
// GPU QPMap texture input
union pipe_enc_cap_qpmap m_HWSupportQPGPUMaps = {};
// GPU Motion vectors texture input
union pipe_enc_cap_motion_vector_map m_HWSupportMotionGPUMaps = {};
// Supported slice mode
bool m_bHWSupportsAppControlledSlicePartitioning = false;
bool m_bHWSupportSliceModeMB = false;
bool m_bHWSupportSliceModeBits = false;
bool m_bHWSupportSliceModeMBRow = false;
bool m_bHWSupportSliceModeAuto = false;
// Two pass encode
union pipe_enc_cap_two_pass m_TwoPassSupport = {};
// PSNR frame stats
union pipe_enc_cap_gpu_stats_psnr m_PSNRStatsSupport = {};
// Driver supports queue priority management
bool m_bHWSupportsQueuePriorityManagement = false;
// Spatial Adaptive Quantization
union pipe_enc_cap_spatial_adaptive_quantization m_HWSupportSpatialAdaptiveQuantization = {};
// PIPE_VIDEO_CAP_ENC_READABLE_RECONSTRUCTED_PICTURE
bool m_bHWSupportReadableReconstructedPicture = false;
private:
const void *m_logId = {};
};
@@ -0,0 +1,128 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "hmft_entrypoints.h"
/*
- This file should implement all the necessary public HMFT interface functions and export them using
- PUBLIC keyword in the method definition on this file
- Adding the DLL export entry in:
- mesa\src\gallium\targets\mediafoundation\mediafoundation.def.in
- mesa\src\gallium\targets\mediafoundation\mediafoundation.sym
- The actual implementation of the methods defined here should be delegated
to implementations in other C files in the same directory, but keeping
all the entrypoints/stubs in this file would help organize the DLL public interface
*/
CDX12EncHMFT::CDX12EncHMFT() : CMFD3DManager( this )
{ }
CDX12EncHMFT::~CDX12EncHMFT()
{
Shutdown();
CMFD3DManager::Shutdown();
}
HRESULT
CDX12EncHMFT::Initialize()
{
HRESULT hr = S_OK;
CHECKHR_GOTO( CMFD3DManager::Initialize( m_Codec ), done );
done:
return hr;
}
#if MFT_CODEC_H264ENC
MFT_REGISTER_TYPE_INFO rgOutputInfo = { MFMediaType_Video, MFVideoFormat_H264 };
#elif MFT_CODEC_H265ENC
MFT_REGISTER_TYPE_INFO rgOutputInfo = { MFMediaType_Video, MFVideoFormat_HEVC };
#elif MFT_CODEC_AV1ENC
MFT_REGISTER_TYPE_INFO rgOutputInfo = { MFMediaType_Video, MFVideoFormat_AV1 };
#endif
MFT_REGISTER_TYPE_INFO rgInputInfo[NUM_INPUT_TYPES] = { { MFMediaType_Video, MFVideoFormat_NV12 },
{ MFMediaType_Video, MFVideoFormat_P010 },
{ MFMediaType_Video, MFVideoFormat_AYUV } };
// Internal function to initialize available input/output types and their associated MF attributes
HRESULT
CDX12EncHMFT::RuntimeClassInitialize()
{
HRESULT hr = S_OK;
ComPtr<IMFMediaType> spVideoType = NULL;
static_assert( MFT_CODEC_H264ENC ^ MFT_CODEC_H265ENC ^ MFT_CODEC_AV1ENC,
"MFT_CODEC_H264ENC or MFT_CODEC_H265ENC or MFT_CODEC_AV1ENC must be defined but only one at a time" );
// Start by configuring for 4:2:0 NV12 as the only possible input type.
// Once the SetOutputType() happens with a profile, we'll reconfigure the available input type
// accordingly. For example, specifying an output profile that indicates 4:4:4 would mean we
// expose an input-type of AYUV.
CHECKHR_GOTO( MFCreateMediaType( &spVideoType ), done );
CHECKHR_GOTO( spVideoType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Video ), done );
CHECKHR_GOTO( spVideoType->SetGUID( MF_MT_SUBTYPE, MFVideoFormat_NV12 ), done );
m_spAvailableInputType.Attach( spVideoType.Detach() );
CHECKHR_GOTO( MFCreateMediaType( &spVideoType ), done );
CHECKHR_GOTO( spVideoType->SetGUID( MF_MT_MAJOR_TYPE, rgOutputInfo.guidMajorType ), done );
CHECKHR_GOTO( spVideoType->SetGUID( MF_MT_SUBTYPE, rgOutputInfo.guidSubtype ), done );
CHECKHR_GOTO( spVideoType->SetUINT32( MF_MT_IN_BAND_PARAMETER_SET, TRUE ), done );
CHECKHR_GOTO( spVideoType->SetUINT32( MF_NALU_LENGTH_SET, 1 ), done );
m_spAvailableOutputType.Attach( spVideoType.Detach() );
CHECKHR_GOTO( MFCreateAttributes( &m_spMFAttributes, 7 ), done );
CHECKHR_GOTO( m_spMFAttributes->SetUINT32( MFT_ENCODER_SUPPORTS_CONFIG_EVENT, TRUE ), done );
// These are required to indicate we are an Async MFT (like all HMFTs are)
CHECKHR_GOTO( m_spMFAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE ), done );
CHECKHR_GOTO( m_spMFAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ), done );
// This is required to indicate we can handle an IMFDXGIDeviceManager (which is either 11 or 12)
// NOTE: Ignore the poor naming of MF_SA_***D3D11***_AWARE here
CHECKHR_GOTO( m_spMFAttributes->SetUINT32( MF_SA_D3D11_AWARE, TRUE ), done );
CHECKHR_GOTO( m_spMFAttributes->SetUINT32( MF_SA_D3D12_AWARE, TRUE ), done );
CHECKHR_GOTO( m_spMFAttributes->SetString( MFT_ENUM_HARDWARE_VENDOR_ID_Attribute, L"VEN_1414" ), done );
CHECKHR_GOTO( m_spMFAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, g_pMFTFriendlyName ), done );
CHECKHR_GOTO( m_spMFAttributes->SetString( MFT_FRIENDLY_NAME_Attribute, g_pMFTFriendlyName ), done );
// Set up IMFMediaEventQueue
CHECKHR_GOTO( MFCreateEventQueue( &m_spEventQueue ), done );
CHECKHR_GOTO( Initialize(), done );
done:
return hr;
}
// factory function
HRESULT
CDX12EncHMFT::CreateInstance( __deref_out CDX12EncHMFT **ppDX12EncHMFT )
{
HRESULT hr = S_OK;
ComPtr<CDX12EncHMFT> spDX12EncHMFT = Microsoft::WRL::Make<CDX12EncHMFT>();
CHECKNULL_GOTO( ppDX12EncHMFT, E_INVALIDARG, done );
CHECKNULL_GOTO( spDX12EncHMFT, E_OUTOFMEMORY, done );
CHECKHR_GOTO( spDX12EncHMFT->RuntimeClassInitialize(), done );
*ppDX12EncHMFT = spDX12EncHMFT.Detach();
done:
return hr;
}
@@ -0,0 +1,726 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#define UNICODE
#include "util/u_video.h"
#include "vl/vl_winsys.h"
#include "pipe_headers.h"
#include <directx/d3d12.h>
#include <directx/d3d12video.h>
#include "idl/dx12enchmft.h"
#include <Unknwn.h>
#include <agents.h>
#include <codecapi.h>
#include <combaseapi.h>
#include <concrt.h>
#include <d3d9types.h>
#include <initguid.h>
#include <mfapi.h>
#include <mfd3d12.h> // For IMFD3D12SynchronizationObjectCommands
#include <mferror.h>
#include <mfidl.h> // For IMFRealTimeClientEx, IMFShutdown
#include <mfobjects.h> // For IMFActivate, IMFObjectInformation, IMFMediaEventGenerator
#include <mftransform.h> // For IMFTransform
#include <mutex>
#include <strmif.h> // For ICodecAPI
#include <wrl.h>
#include <wrl/client.h>
#include <wrl/implements.h>
#include "macros.h"
#include "mfd3dmanager.h"
#include <d3d11_1.h>
#include <d3d11_3.h>
#include <d3d11_4.h>
#include <dxgi1_2.h>
#include "context.h"
#include "encoder_capabilities.h"
#include "reference_frames_tracker.h"
using namespace concurrency;
using namespace Microsoft::WRL;
using Microsoft::WRL::ComPtr;
#define ENCODE_WITH_TWO_PASS_LOWEST_RES 1
#define NUM_INPUT_TYPES 3
extern MFT_REGISTER_TYPE_INFO rgOutputInfo;
extern MFT_REGISTER_TYPE_INFO rgInputInfo[NUM_INPUT_TYPES];
extern const wchar_t *g_pMFTFriendlyName;
#ifndef FOURCC_H264
#define FOURCC_H264 MAKEFOURCC( 'H', '2', '6', '4' )
#endif
#ifndef FOURCC_H265
#define FOURCC_H265 MAKEFOURCC( 'H', '2', '6', '5' )
#endif
#ifndef FOURCC_HEVC
#define FOURCC_HEVC MAKEFOURCC( 'H', 'E', 'V', 'C' )
#endif
#ifndef FOURCC_avc1
#define FOURCC_avc1 MAKEFOURCC( 'a', 'v', 'c', '1' )
#endif
#ifndef FOURCC_AV01
#define FOURCC_AV01 MAKEFOURCC( 'A', 'V', '0', '1' )
#endif
#ifndef FOURCC_NV12
#define FOURCC_NV12 MAKEFOURCC( 'N', 'V', '1', '2' )
#endif
#ifndef FOURCC_P010
#define FOURCC_P010 MAKEFOURCC( 'P', '0', '1', '0' )
#endif
#ifndef FOURCC_AYUV
#define FOURCC_AYUV MAKEFOURCC( 'A', 'Y', 'U', 'V' )
#endif
#ifndef FOURCC_Y210
#define FOURCC_Y210 MAKEFOURCC( 'Y', '2', '1', '0' )
#endif
#ifndef FOURCC_Y410
#define FOURCC_Y410 MAKEFOURCC( 'Y', '4', '1', '0' )
#endif
#ifndef FOURCC_YUY2
#define FOURCC_YUY2 MAKEFOURCC( 'Y', 'U', 'Y', '2' )
#endif
#ifdef SUPPORT_BFRAMES
#define HMFT_MAX_BFRAMES 1
#else
#define HMFT_MAX_BFRAMES 0
#endif
#define HMFT_MIN_WIDTH 34
#define HMFT_MIN_HEIGHT 34
#define HMFT_MIN_BITS_PER_SLICE 256
#define AVC_MAX_QP 51
#define AVC_DEFAULT_QP 26
#define HMFT_MAX_TEMPORAL_LAYERS 2
constexpr const eAVEncH265VProfile eAVEncH265VProfile_Main_422_8 = (eAVEncH265VProfile) 23;
typedef enum tVideoFormat
{
VIDFMT_COMPONENT = 0,
VIDFMT_PAL,
VIDFMT_NTSC,
VIDFMT_SECAM,
VIDFMT_MAC,
VIDFMT_UNSPECIFIED,
VIDFMT_MAX
} VideoFormat;
typedef enum tColorPrimary
{
COLORPRIM_BT709_5 = 0,
COLORPRIM_UNSPECIFIED,
COLORPRIM_BT470_6M,
COLORPRIM_BT470_6BG,
COLORPRIM_SMPTE_170M,
COLORPRIM_SMPTE_240M,
COLORPRIM_FILM,
COLORPRIM_MAX
} ColorPrimary;
typedef enum tColorTransfer
{
COLORXFER_BT709_5 = 0,
COLORXFER_UNSPECIFIED,
COLORXFER_BT470_6M,
COLORXFER_BT470_6BG,
COLORXFER_SMPTE_170M,
COLORXFER_SMPTE_240M,
COLORXFER_LINEAR,
COLORXFER_LOG100,
COLORXFER_LOG316,
COLORXFER_IEC,
COLORXFER_BT1361,
COLORXFER_MAX
} ColorTransfer;
typedef enum tColorMatrix
{
COLORMATRIX_GBR = 0,
COLORMATRIX_BT709_5,
COLORMATRIX_UNSPECIFIED,
COLORMATRIX_FCC47,
COLORMATRIX_BT470_6BG,
COLORMATRIX_SMPTE170M,
COLORMATRIX_SMPTE240M,
COLORMATRIX_YCgCo,
COLORMATRIX_MAX
} ColorMatrix;
typedef struct tSampleAspectRatio
{
unsigned short usWidth;
unsigned short usHeight;
} SampleAspectRatio;
typedef struct tVideoSignalType
{
VideoFormat eVideoFormat;
BOOL bVideoFullRangeFlag;
BOOL bColorInfoPresent;
ColorPrimary eColorPrimary;
ColorTransfer eColorTransfer;
ColorMatrix eColorMatrix;
} VideoSignalType;
// VUI
typedef struct tVUInfo
{
BOOL bEnableSAR;
SampleAspectRatio stSARInfo;
BOOL bEnableVST;
VideoSignalType stVidSigType;
} VUInfo;
// Slice control modes supported by the encoder.
typedef enum tSliceControlMode
{
SLICE_CONTROL_MODE_MB = 0,
SLICE_CONTROL_MODE_BITS = 1,
SLICE_CONTROL_MODE_MB_ROW = 2,
SLICE_CONTROL_MODE_MAX
} SliceControlMode;
// DirtyRect modes supported by the encoder.
typedef enum tDirtyRectMode
{
DIRTY_RECT_MODE_OFF = 0,
DIRTY_RECT_MODE_USE_FRAME_NUM = 1,
DIRTY_RECT_MODE_IGNORE_FRAME_NUM = 2,
DIRTY_RECT_MODE_MAX
} DirtyRectMode;
// Gradual intra refresh modes supported by the encoder.
typedef enum IntraRefreshMode
{
HMFT_INTRA_REFRESH_MODE_NONE = 0,
HMFT_INTRA_REFRESH_MODE_PERIODIC = 1,
HMFT_INTRA_REFRESH_MODE_CONTINUAL = 2,
HMFT_INTRA_REFRESH_MODE_MAX
} IntraRefreshMode;
#ifndef CODECAPI_AVEncVideoD3D12ReconstructedPictureOutputMode
// MFSampleExtension_VideoEncodeD3D12ReconstructedPicture {3E8A1B7F-5C92-4D6E-B834-F0A729E65C48}
// Type: IMFMediaBuffer
// The reconstructed picture data of an encoded video frame from a D3D12-based MFT (Experimental).
DEFINE_GUID( MFSampleExtension_VideoEncodeD3D12ReconstructedPicture,
0x3e8a1b7f,
0x5c92,
0x4d6e,
0xb8,
0x34,
0xf0,
0xa7,
0x29,
0xe6,
0x5c,
0x48 );
enum eAVEncVideoD3D12ReconstructedPictureOutputMode
{
eAVEncVideoEncodeD3D12ReconstructedPictureMode_None = 0, // Does not return a D3D12 reconstructed buffer.
eAVEncVideoEncodeD3D12ReconstructedPictureMode_Copy =
1, // Returns a copy of the D3D12 reconstructed buffer used by the encoder.
eAVEncVideoEncodeD3D12ReconstructedPictureMode_Shared =
2 // Returns the D3D12 reconstructed buffer written by the encoder without a copy.
};
// AVEncVideoD3D12ReconstructedPictureOutputMode (VT_UI4) (Experimental, Testing only)
// This property controls the output of D3D12 reconstructed picture data from a D3D12-based encoder.
// ulVal must be a value from the eAVEncVideoD3D12ReconstructedPictureOutputMode enumeration.
DEFINE_CODECAPI_GUID( AVEncVideoD3D12ReconstructedPictureOutputMode,
"4A7B2E8F-1D93-4C6A-B548-91E2F8C5A7D3",
0x4a7b2e8f,
0x1d93,
0x4c6a,
0xb5,
0x48,
0x91,
0xe2,
0xf8,
0xc5,
0xa7,
0xd3 )
#define CODECAPI_AVEncVideoD3D12ReconstructedPictureOutputMode \
DEFINE_CODECAPI_GUIDNAMED( AVEncVideoD3D12ReconstructedPictureOutputMode )
#endif
#ifndef CODECAPI_AVEncVideoRateControlFramePreAnalysis
// AVEncVideoRateControlFramePreAnalysis (VT_BOOL) (Experimental, Testing only)
// Indicates whether to enable or disable rate control frame preanalysis
// VARIANT_FALSE: disable; VARIANT_TRUE: enable
DEFINE_CODECAPI_GUID( AVEncVideoRateControlFramePreAnalysis,
"CF229C1D-FA9A-4BBA-9E08-269F3CF5D621",
0xcf229c1d,
0xfa9a,
0x4bba,
0x9e,
0x8,
0x26,
0x9f,
0x3c,
0xf5,
0xd6,
0x21 )
#define CODECAPI_AVEncVideoRateControlFramePreAnalysis DEFINE_CODECAPI_GUIDNAMED( AVEncVideoRateControlFramePreAnalysis )
#endif
#ifndef CODECAPI_AVEncVideoRateControlFramePreAnalysisExternalReconDownscale
// CODECAPI_AVEncVideoRateControlFramePreAnalysisExternalReconDownscale (VT_BOOL) (Experimental, Testing only)
// Indicates whether to enable or disable external recon downscale in rate control frame preanalysis
// VARIANT_FALSE: disable; VARIANT_TRUE: enable
DEFINE_CODECAPI_GUID( AVEncVideoRateControlFramePreAnalysisExternalReconDownscale,
"C53DEFA4-138A-4310-864F-4516661C56E7",
0xc53defa4,
0x138a,
0x4310,
0x86,
0x4f,
0x45,
0x16,
0x66,
0x1c,
0x56,
0xe7 )
#define CODECAPI_AVEncVideoRateControlFramePreAnalysisExternalReconDownscale \
DEFINE_CODECAPI_GUIDNAMED( AVEncVideoRateControlFramePreAnalysisExternalReconDownscale )
#endif
#if MFT_CODEC_H264ENC
#define HMFT_GUID "8994db7c-288a-4c62-a136-a3c3c2a208a8"
#elif MFT_CODEC_H265ENC
#define HMFT_GUID "e7ffb8eb-fa0b-4fb0-acdf-1202f663cde5"
#elif MFT_CODEC_AV1ENC
#define HMFT_GUID "1a6f3150-b121-4ce9-9497-50fedb3dcb70"
#endif
#define MFT_INPUT_QUEUE_DEPTH 8
// For low latency mode we should only need 2 if we have guarantee that the output sample is returned quickly. However,
// when using mp4 sink via SinkWriter, it buffers the input sample so we will hit no resource sample and error out, choosing 11 to
// be safe.
#define MFT_STAT_POOL_MIN_SIZE 11
class __declspec( uuid( HMFT_GUID ) ) CDX12EncHMFT : CMFD3DManager,
public RuntimeClass<RuntimeClassFlags<RuntimeClassType::WinRtClassicComMix>,
IMFTransform,
IMFRealTimeClientEx,
ICodecAPI,
IMFMediaEventGenerator,
IMFShutdown>
{
InspectableClass( RuntimeClass_DX12Encoder_CDX12EncHMFT, BaseTrust )
protected : enum {
EVENT_QUIT,
EVENT_INPUT,
MAX_EVENTS
};
static void WINAPI xThreadProc( void *pCtx );
HANDLE m_hThread = NULL;
DWORD m_dwThreadId = 0;
private:
~CDX12EncHMFT();
HRESULT InitializeEncoder( pipe_video_profile VideoProfile, UINT32 Width, UINT32 Height );
void CleanupEncoder();
HRESULT CreateGOPTracker( uint32_t textureWidth, uint32_t textureHeight );
event m_eventHaveInput;
// signal that the queue has data via m_eventHaveInput
concurrent_queue<LPDX12EncodeContext> m_EncodingQueue; // (MFT_INPUT_QUEUE_DEPTH)
concurrent_queue<IMFSample *> m_OutputQueue;
std::mutex m_OutputQueueLock;
HRESULT SetEncodingParameters( IMFAttributes *pMFAttributes );
HRESULT GetCodecPrivateData( LPBYTE pSPSPPSData, DWORD dwSPSPPSDataLen, LPDWORD lpdwSPSPPSDataLen );
// ProcessMessage Event Handlers
HRESULT OnDrain();
HRESULT OnFlush();
HRESULT ConfigureSampleAllocator();
HRESULT ConfigureBitstreamOutputSampleAttributes( IMFSample *pSample,
const LPDX12EncodeContext pDX12EncodeContext,
DWORD dwReceivedInput,
BOOL bIsLastSlice,
struct codec_unit_location_t *pCodecUnitMetadata,
unsigned CodecUnitMetadataCount );
HRESULT ConfigureAsyncStatsMetadataOutputSampleAttributes( IMFSample *pSample,
pipe_resource *pPipeResourcePSNRStats,
pipe_resource *pPipeResourceQPMapStats,
pipe_resource *pPipeResourceRCBitAllocMapStats,
pipe_resource *pPipeResourceSATDMapStats,
ComPtr<ID3D12Fence> &pResolveStatsCompletionFence,
UINT64 ResolveStatsCompletionFenceValue,
pipe_resource *pPipeResourceReconstructedPicture,
UINT PipeResourceReconstructedPictureSubresource,
ComPtr<ID3D12Fence> &spReconstructedPictureCompletionFence,
UINT64 ReconstructedPictureCompletionFenceValue,
ID3D12CommandQueue *pSyncObjectQueue );
bool GetSliceBitstreamMetadata( LPDX12EncodeContext pDX12EncodeContext,
uint32_t slice_idx,
std::vector<struct codec_unit_location_t> &codec_unit_metadata );
bool ProcessSliceBitstreamZeroCopy( LPDX12EncodeContext pDX12EncodeContext,
uint32_t slice_idx,
ComPtr<IMFMediaBuffer> &spMediaBuffer,
std::vector<struct codec_unit_location_t> &mfsample_codec_unit_metadata );
void FinalizeAndEmitOutputSample( LPDX12EncodeContext pDX12EncodeContext,
ComPtr<IMFMediaBuffer> &spMediaBuffer,
ComPtr<IMFSample> &spOutputSample,
struct codec_unit_location_t *pCodecUnitMetadata,
unsigned CodecUnitMetadataCount,
DWORD dwReceivedInput,
BOOL bIsLastSlice,
uint64_t ResolveStatsCompletionFenceValue );
HRESULT UpdateAvailableInputType();
HRESULT InternalCheckInputType( IMFMediaType *pType );
HRESULT InternalCheckOutputType( IMFMediaType *pType );
HRESULT CheckMediaType( IMFMediaType *pmt, bool bInputType );
#if MFT_CODEC_H264ENC
HRESULT CheckMediaTypeLevel(
IMFMediaType *pmt, int width, int height, const encoder_capabilities &encoderCapabilities, eAVEncH264VLevel *pLevel ) const;
#elif MFT_CODEC_H265ENC
HRESULT CheckMediaTypeLevel(
IMFMediaType *pmt, int width, int height, const encoder_capabilities &encoderCapabilities, eAVEncH265VLevel *pLevel ) const;
#elif MFT_CODEC_AV1ENC
HRESULT CheckMediaTypeLevel(
IMFMediaType *pmt, int width, int height, const encoder_capabilities &encoderCapabilities, eAVEncAV1VLevel *pLevel ) const;
#endif
HRESULT ValidateDirtyRects( const LPDX12EncodeContext pDX12EncodeContext, const DIRTYRECT_INFO *pDirtyRectInfo );
UINT32 GetMaxReferences( unsigned int width, unsigned int height );
HRESULT CheckShutdown();
// MFT Attributes
ComPtr<IMFAttributes> m_spMFAttributes;
// MFT event-queue
ComPtr<IMFMediaEventQueue> m_spEventQueue;
// input stream
ComPtr<IMFMediaType> m_spAvailableInputType;
ComPtr<IMFMediaType> m_spInputType;
DWORD m_dwInputTypeStride;
DWORD m_dwInputOffsetX;
DWORD m_dwInputOffsetY;
BOOL m_bEncodingStarted = FALSE;
GUID m_InputSubType;
VUInfo m_VUIInfo = {};
// output stream
ComPtr<IMFMediaType> m_spAvailableOutputType;
ComPtr<IMFMediaType> m_spOutputType;
UINT32 m_uiOutputWidth = 0;
UINT32 m_uiOutputHeight = 0;
UINT32 m_uiOutputBitrate = 0;
MFRatio m_FrameRate = { 30, 1 }; // default to 30fps
MFRatio m_PixelAspectRatio = { 1, 1 }; // default to 1:1
MFNominalRange m_eNominalRange = MFNominalRange_16_235;
BOOL m_bFrameCroppingFlag = FALSE;
UINT32 m_uiFrameCropRightOffset = 0;
UINT32 m_uiFrameCropBottomOffset = 0;
BOOL m_bForceKeyFrame = FALSE;
UINT32 m_uiRateControlMode = eAVEncCommonRateControlMode_CBR;
BOOL m_bRateControlModeSet = FALSE;
UINT32 m_uiMaxLongTermReferences = 0;
UINT32 m_uiTrustModeLongTermReferences = 0;
BOOL m_bLayerCountSet = FALSE;
UINT32 m_uiLayerCount = 1;
UINT32 m_uiSelectedLayer = 0;
UINT32 m_uiQualityVsSpeed = 33;
UINT32 m_uiMeanBitRate;
BOOL m_bMeanBitRateSet = FALSE;
UINT32 m_uiPeakBitRate = 0;
BOOL m_bPeakBitRateSet = FALSE;
UINT32 m_uiBufferSize = 0;
BOOL m_bBufferSizeSet = FALSE;
UINT32 m_uiBufferInLevel = 0;
BOOL m_bBufferInLevelSet = FALSE;
UINT32 m_uiGopSize = 30; // ~1s worth as a default
BOOL m_bGopSizeSet = FALSE;
UINT32 m_uiBFrameCount = 0;
UINT32 m_uiContentType = eAVEncVideoContentType_Unknown;
BOOL m_bContentTypeSet = FALSE;
UINT32 m_uiMinQP = 0;
BOOL m_bMinQPSet = FALSE;
UINT32 m_uiMaxQP = AVC_MAX_QP;
BOOL m_bMaxQPSet = FALSE;
UINT32 m_uiSPSID = 0;
BOOL m_bSPSIDSet = FALSE;
UINT32 m_uiPPSID = 0;
BOOL m_bPPSIDSet = FALSE;
UINT32 m_uiLTRBufferControl = 0;
BOOL m_bLTRBufferControlSet = FALSE;
UINT32 m_uiMarkLTRFrame;
BOOL m_bMarkLTRFrameSet = FALSE;
UINT32 m_uiUseLTRFrame;
BOOL m_bUseLTRFrameSet = FALSE;
UINT32 m_uiSliceControlMode = SLICE_CONTROL_MODE_MB;
BOOL m_bSliceControlModeSet = FALSE;
UINT32 m_uiSliceControlSize = 0;
BOOL m_bSliceControlSizeSet = FALSE;
BOOL m_bMaxNumRefFrameSet = FALSE;
#if MFT_CODEC_H264ENC
UINT32 m_uiMaxNumRefFrame = PIPE_H264_MAX_REFERENCES;
#elif MFT_CODEC_H265ENC
UINT32 m_uiMaxNumRefFrame = PIPE_H265_MAX_REFERENCES;
#elif MFT_CODEC_AV1ENC
UINT32 m_uiMaxNumRefFrame = PIPE_AV1_MAX_REFERENCES;
#endif
#if MFT_CODEC_H264ENC
eAVEncH264VProfile m_uiProfile = eAVEncH264VProfile_Main;
eAVEncH264VLevel m_uiLevel = eAVEncH264VLevel5;
const D3D12_VIDEO_ENCODER_CODEC m_Codec = D3D12_VIDEO_ENCODER_CODEC_H264;
enum pipe_video_profile m_outputPipeProfile = PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN;
#elif MFT_CODEC_H265ENC
eAVEncH265VProfile m_uiProfile = eAVEncH265VProfile_Main_420_8;
eAVEncH265VLevel m_uiLevel = eAVEncH265VLevel5;
const D3D12_VIDEO_ENCODER_CODEC m_Codec = D3D12_VIDEO_ENCODER_CODEC_HEVC;
enum pipe_video_profile m_outputPipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN;
#elif MFT_CODEC_AV1ENC
eAVEncAV1VProfile m_uiProfile = eAVEncAV1VProfile_Main_420_8;
eAVEncAV1VLevel m_uiLevel = eAVEncAV1VLevel5;
const D3D12_VIDEO_ENCODER_CODEC m_Codec = D3D12_VIDEO_ENCODER_CODEC_AV1;
enum pipe_video_profile m_outputPipeProfile = PIPE_VIDEO_PROFILE_AV1_MAIN;
#endif
UINT32 m_uiMeanAbsoluteDifference = 0;
UINT32 m_uiIntraRefreshMode = 0;
UINT32 m_uiIntraRefreshSize = 0;
eAVScenarioInfo m_eScenarioInfo = eAVScenarioInfo_Unknown;
UINT32 m_uiEnableInLoopBlockFilter = 0;
BOOL m_bVideoROIEnabled = FALSE;
UINT32 m_uiDirtyRectEnabled = 0;
UINT32 m_uiQuality[3] = { 65, 65, 65 }; // Default value for AVEncCommonQuality is 65
uint32_t m_uiEncodeFrameTypeIQP[3] = { AVC_DEFAULT_QP, AVC_DEFAULT_QP, AVC_DEFAULT_QP };
uint32_t m_uiEncodeFrameTypePQP[3] = { AVC_DEFAULT_QP, AVC_DEFAULT_QP, AVC_DEFAULT_QP };
uint32_t m_uiEncodeFrameTypeBQP[3] = { AVC_DEFAULT_QP, AVC_DEFAULT_QP, AVC_DEFAULT_QP };
BOOL m_bEncodeQPSet = FALSE;
BOOL m_bLowLatency = FALSE;
BOOL m_bCabacEnable = TRUE;
BOOL m_bVideoEnableFramePsnrYuv = FALSE;
BOOL m_bVideoEnableSpatialAdaptiveQuantization = FALSE;
UINT32 m_uiVideoOutputQPMapBlockSize = 0;
UINT32 m_uiVideoOutputBitsUsedMapBlockSize = 0;
UINT32 m_uiVideoSatdMapBlockSize = 0;
typedef enum RECON_PIC_OUTPUT_MODE
{
RECON_PIC_OUTPUT_MODE_DISABLED = 0,
RECON_PIC_OUTPUT_MODE_BLIT_COPY = 1,
RECON_PIC_OUTPUT_MODE_READ_ONLY_SHARED_RESOURCE = 2,
} RECON_PIC_OUTPUT_MODE;
RECON_PIC_OUTPUT_MODE m_VideoReconstructedPictureMode = RECON_PIC_OUTPUT_MODE_DISABLED;
UINT32 m_uiSliceGenerationMode = 0;
BOOL m_bSliceGenerationModeSet = FALSE;
BOOL m_bRateControlFramePreAnalysis = FALSE;
BOOL m_bRateControlFramePreAnalysisExternalReconDownscale = FALSE;
UINT m_uiMaxOutputBitstreamSize = 0u;
struct pipe_video_codec *m_pPipeVideoCodec = nullptr;
struct pipe_video_codec *m_pPipeVideoBlitter = nullptr;
reference_frames_tracker *m_pGOPTracker = nullptr;
enum pipe_format m_inputPipeFormat = PIPE_FORMAT_NV12;
// Fences used to synchronize different upstream textures
// types (e.g DX12, DX11, CPU buffer) with the pipe interface
ComPtr<ID3D11Fence> m_spStagingFence11;
ComPtr<ID3D12Fence> m_spStagingFence12;
struct pipe_fence_handle *m_pPipeFenceHandle = nullptr;
HANDLE m_hSharedFenceHandle = nullptr;
uint64_t m_CurrentSyncFenceValue = 1;
// Cached encoder capabilities
class encoder_capabilities m_EncoderCapabilities { this };
// state management
bool m_bShutdown = false;
bool m_bInitialized = false;
bool m_bStreaming = false;
bool m_bDraining = false;
bool m_bFlushing = false;
event m_eventInputDrained;
DWORD m_dwNeedInputCount = 0;
DWORD m_dwProcessInputCount = 0;
DWORD m_dwHaveOutputCount = 0;
DWORD m_dwProcessOutputCount = 0;
class std::mutex m_lock;
class std::mutex m_lockShutdown;
class std::mutex m_encoderLock;
bool m_bExitThread = false;
bool m_bUnlocked = false;
HRESULT IsUnlocked( void );
#if MFT_CODEC_H264ENC
HRESULT UpdateH264EncPictureDesc( pipe_h264_enc_picture_desc *pPicInfo, const uint32_t intra_period, const uint32_t ip_period );
#endif
#if MFT_CODEC_H265ENC
HRESULT UpdateH265EncPictureDesc( pipe_h265_enc_picture_desc *pPicInfo,
const uint32_t intra_period,
const uint32_t ip_period,
const uint8_t log2_max_pic_order_cnt_lsb_minus4,
const uint16_t pic_width_in_luma_samples,
const uint16_t pic_height_in_luma_samples );
#endif
#if MFT_CODEC_AV1ENC
HRESULT UpdateAV1EncPictureDesc( pipe_av1_enc_picture_desc *pPicInfo );
#endif
HRESULT PrepareForEncodeHelper( LPDX12EncodeContext pDX12EncodeContext,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum,
bool moveRegionFrameNumSet,
uint32_t moveRegionFrameNum );
HRESULT PrepareForEncode( IMFSample *pSample, LPDX12EncodeContext *ppDX12EncodeContext );
std::vector<BYTE> m_pDirtyRectBlob = std::vector<BYTE>( sizeof( DIRTYRECT_INFO ) );
std::vector<BYTE> m_pMoveRegionBlob = std::vector<BYTE>( sizeof( MOVEREGION_INFO ) );
public:
CDX12EncHMFT();
CDX12EncHMFT( LPUNKNOWN pUnk, HRESULT *phr );
STDMETHOD( RuntimeClassInitialize )();
HRESULT Initialize();
HRESULT OnInputTypeChanged();
HRESULT OnOutputTypeChanged();
public:
static HRESULT CreateInstance( __deref_out CDX12EncHMFT **ppDX12EncHMFT );
// ---------------------------------------------------------------------------------------------------------
// IMFTransform (https://learn.microsoft.com/en-us/windows/win32/api/mftransform/nn-mftransform-imftransform)
// ---------------------------------------------------------------------------------------------------------
STDMETHOD( GetAttributes )( IMFAttributes **ppAttributes );
STDMETHOD( GetOutputStreamAttributes )( DWORD dwOutputStreamID, IMFAttributes **ppAttributes );
STDMETHOD( GetOutputStreamInfo )( DWORD dwOutputStreamIndex, MFT_OUTPUT_STREAM_INFO *pStreamInfo );
STDMETHOD( GetInputStreamAttributes )( DWORD dwInputStreamID, IMFAttributes **ppAttributes );
STDMETHOD( GetInputStreamInfo )( DWORD dwInputStreamIndex, MFT_INPUT_STREAM_INFO *pStreamInfo );
STDMETHOD( GetStreamCount )( DWORD *pcInputStreams, DWORD *pcOutputStreams );
STDMETHOD( GetStreamIDs )( DWORD dwInputIDArraySize, DWORD *pdwInputIDs, DWORD dwOutputIDArraySize, DWORD *pdwOutputIDs );
STDMETHOD( GetStreamLimits )( DWORD *pdwInputMinimum, DWORD *pdwInputMaximum, DWORD *pdwOutputMinimum, DWORD *pdwOutputMaximum );
STDMETHOD( DeleteInputStream )( DWORD dwStreamIndex );
STDMETHOD( AddInputStreams )( DWORD cStreams, DWORD *adwStreamIDs );
STDMETHOD( GetInputAvailableType )( DWORD dwInputStreamIndex, DWORD dwTypeIndex, IMFMediaType **ppType );
STDMETHOD( GetOutputAvailableType )( DWORD dwOutputStreamIndex, DWORD dwTypeIndex, IMFMediaType **ppType );
STDMETHOD( SetInputType )( DWORD dwInputStreamIndex, IN IMFMediaType *pType, DWORD dwFlags );
STDMETHOD( SetOutputType )( DWORD dwOutputStreamIndex, IN IMFMediaType *pType, DWORD dwFlags );
STDMETHOD( GetInputCurrentType )( DWORD dwInputStreamIndex, IMFMediaType **ppType );
STDMETHOD( GetOutputCurrentType )( DWORD dwOutputStreamIndex, IMFMediaType **ppType );
STDMETHOD( SetOutputBounds )( LONGLONG hnsLowerBound, LONGLONG hnsUpperBound );
STDMETHOD( GetInputStatus )( DWORD dwInputStreamIndex, DWORD *pdwFlags );
STDMETHOD( GetOutputStatus )( DWORD *pdwFlags );
STDMETHOD( ProcessEvent )( DWORD dwInputStreamIndex, IMFMediaEvent *pEvent );
STDMETHOD( ProcessMessage )( MFT_MESSAGE_TYPE eMessage, ULONG_PTR ulParam );
STDMETHOD( ProcessInput )( DWORD dwInputStreamIndex, IMFSample *pSample, DWORD dwFlags );
STDMETHOD( ProcessOutput )( DWORD dwFlags, DWORD cOutputBufferCount, MFT_OUTPUT_DATA_BUFFER *pOutputSamples, DWORD *pdwStatus );
// --------------------------------------------------------------------------------------------------------------------------
// IMFMediaEventGenerator (https://learn.microsoft.com/en-us/windows/win32/api/mfobjects/nn-mfobjects-imfmediaeventgenerator)
// --------------------------------------------------------------------------------------------------------------------------
STDMETHOD( BeginGetEvent )( IMFAsyncCallback *pCallback, IUnknown *punkState );
STDMETHOD( EndGetEvent )( IMFAsyncResult *pResult, IMFMediaEvent **ppEvent );
STDMETHOD( GetEvent )( DWORD dwFlags, IMFMediaEvent **ppEvent );
STDMETHOD( QueueEvent )( MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT *pvValue );
// --------------------------------------------------------------------------------------------
// IMFShutdown (https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nn-mfidl-imfshutdown)
// --------------------------------------------------------------------------------------------
STDMETHOD( GetShutdownStatus )( MFSHUTDOWN_STATUS *pStatus );
STDMETHOD( Shutdown )( void );
// --------------------------------------------------------------------------------------------
// ICodecAPI (https://learn.microsoft.com/en-us/windows/win32/api/strmif/nn-strmif-icodecapi)
// --------------------------------------------------------------------------------------------
STDMETHOD( IsSupported )( const GUID *Api );
STDMETHOD( IsModifiable )( const GUID *Api );
STDMETHOD( GetParameterRange )( const GUID *Api, VARIANT *ValueMin, VARIANT *ValueMax, VARIANT *SteppingDelta );
STDMETHOD( GetParameterValues )( const GUID *Api, VARIANT **Values, ULONG *ValuesCount );
STDMETHOD( GetValue )( const GUID *Api, VARIANT *Value );
STDMETHOD( SetValue )( const GUID *Api, VARIANT *Value );
STDMETHOD( GetDefaultValue )( const GUID *Api, VARIANT *Value );
STDMETHOD( RegisterForEvent )( const GUID *Api, LONG_PTR userData );
STDMETHOD( UnregisterForEvent )( const GUID *Api );
STDMETHOD( SetAllDefaults )( void );
STDMETHOD( SetValueWithNotify )( const GUID *Api, VARIANT *Value, GUID **ChangedParam, ULONG *ChangedParamCount );
STDMETHOD( SetAllDefaultsWithNotify )( GUID **ChangedParam, ULONG *ChangedParamCount );
STDMETHOD( GetAllSettings )( IStream *pStream );
STDMETHOD( SetAllSettings )( IStream *pStream );
STDMETHOD( SetAllSettingsWithNotify )( IStream *pStream, GUID **ChangedParam, ULONG *ChangedParamCount );
// ------------------------------------------------------------------------------------------------------------
// IMFRealTimeClientEx (https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nn-mfidl-imfrealtimeclientex)
// ------------------------------------------------------------------------------------------------------------
STDMETHOD( RegisterThreadsEx )( DWORD *pdwTaskIndex, LPCWSTR wszClassName, LONG lBasePriority );
STDMETHOD( UnregisterThreads )( void );
STDMETHOD( SetWorkQueueEx )( DWORD dwMultithreadedWorkQueueId, LONG lWorkItemBasePriority );
};
ActivatableClass( CDX12EncHMFT );
CoCreatableClass( CDX12EncHMFT );
@@ -0,0 +1,52 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#define CHECKHR_GOTO( hresult, label ) \
{ \
hr = hresult; \
if( FAILED( hr ) ) \
{ \
debug_printf( "\nerror in %s, line=%u in %s hr=0x%08x\n", __FUNCTION__, __LINE__, __FILE__, hr ); \
goto label; \
} \
}
#define CHECKBOOL_GOTO( exp, err, label ) \
if( !( exp ) ) \
{ \
CHECKHR_GOTO( err, label ); \
}
#define CHECKNULL_GOTO( exp, err, label ) CHECKBOOL_GOTO( ( exp ), err, label )
#define SAFE_RELEASE( x ) \
if( ( x ) ) \
( x )->Release();
#define SAFE_DELETE( x ) \
if( ( x ) ) \
{ \
delete ( x ); \
( x ) = nullptr; \
}
#define SAFE_CLOSEHANDLE( x ) \
if( ( x ) ) \
{ \
CloseHandle( ( x ) ); \
( x ) = nullptr; \
}
@@ -0,0 +1,163 @@
# Copyright © Microsoft Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice (including the next
# paragraph) shall be included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
fs = import('fs')
mf_cpp_args = cc.get_supported_arguments([
'/we4267',
'/we4996',
'/we4146',
'/we4244',
'/we4389',
'/we4838',
'/we4302',
'/we4018',
'/we4056',
'/we4305',
'/we4351',
'/we4756',
'/we4800',
'/we4291',
'/we4624',
'/we4309',
'/we5105',
'/we4020',
'/we4024',
'/we4189',
])
if get_option('mediafoundation-store-dll')
mf_cpp_args += '-DBUILD_FOR_MSDK' # Can use #if BUILD_FOR_MSDK in .cpp code
endif
# InputQPSettings::step was renamed to ::steps in BR (Bromine) SDK
# Probe which field name the installed SDK exposes.
_inputqp_has_steps = cc.compiles(
'''
#include <windows.h>
#include <mfapi.h>
void test() { InputQPSettings s; (void)s.steps; }
''',
name : 'InputQPSettings::steps present',
)
if _inputqp_has_steps
message('InputQPSettings: using field "steps"')
mf_cpp_args += '-DINPUTQPSETTINGS_HAS_STEPS'
else
_inputqp_has_step = cc.compiles(
'''
#include <windows.h>
#include <mfapi.h>
void test() { InputQPSettings s; (void)s.step; }
''',
name : 'InputQPSettings::step present',
)
if _inputqp_has_step
message('InputQPSettings: using field "step"')
else
error('InputQPSettings has neither "steps" nor "step" — unsupported Windows SDK version')
endif
endif
mediafoundation_files = files(
'codecapi.cpp',
'encode.cpp',
'encode_av1.cpp',
'encode_h264.cpp',
'encode_hevc.cpp',
'encoder_capabilities.cpp',
'hmft_entrypoints.cpp',
'mfbufferhelp.cpp',
'mfd3dmanager.cpp',
'mfmediaeventgenerator.cpp',
'mfpipeinterop.cpp',
'mfrealtimeclientex.cpp',
'mfshutdown.cpp',
'mftransform.cpp',
'dpb_buffer_manager.cpp',
'reference_frames_tracker_av1.cpp',
'reference_frames_tracker_h264.cpp',
'reference_frames_tracker_hevc.cpp',
'stats_buffer_manager.cpp',
'd3d12_suballoc_mediabuffer.cpp',
'videobufferlock.cpp',
'wpptrace.cpp',
)
mediafoundation_wpp_args = ''
foreach f : mediafoundation_files
mediafoundation_wpp_args += fs.relative_to(f, 'a:\\').replace('/', '\\') + '\r\n'
endforeach
mediafoundation_wpp_rsp = configure_file(
input : meson.current_source_dir() + '/wppconfig/wpp_args.rsp.template',
output : 'mediafoundation_wpp_args.rsp',
configuration : {'WPP_ARGS' : mediafoundation_wpp_args}
)
mft_codecs = get_option('mediafoundation-codecs')
all_mft_codecs = ['h264enc', 'h265enc', 'av1enc']
if mft_codecs.contains('all')
mft_codecs = all_mft_codecs
endif
foreach c : mft_codecs
if not _codecs.contains(c)
error('@0@ present in mediafoundation-codecs must also be present in video-codecs.'.format(c))
endif
endforeach
mf_codecs_cpp_args = {}
foreach mf_codec_target : all_mft_codecs
cpp_args = mf_cpp_args
foreach c : all_mft_codecs
cpp_args += '-DMFT_CODEC_@0@=@1@'.format(c.to_upper(), (c == mf_codec_target).to_int())
endforeach
mf_codecs_cpp_args += {mf_codec_target : cpp_args}
endforeach
mediafoundation_wpp_preprocess = custom_target(
'mediafoundation_wpp_preprocess',
capture : true,
build_by_default : true,
build_always_stale : true,
input : mediafoundation_files,
output : 'mediafoundation_wpp_preprocess.dummy.h',
command : ['tracewpp', '-cfgdir:@CURRENT_SOURCE_DIR@/wppconfig/rev1', '-scan:@CURRENT_SOURCE_DIR@/wpptrace.h', '-odir:@OUTDIR@', '@' + fs.relative_to(mediafoundation_wpp_rsp, 'a:\\')]
)
mediafoundation_st = {}
foreach codec : mft_codecs
lib = static_library(
'mediafoundation_st_' + codec,
mediafoundation_files,
mediafoundation_wpp_preprocess,
gnu_symbol_visibility : 'hidden',
cpp_args : mf_codecs_cpp_args[codec],
override_options: ['cpp_std=c++20'],
include_directories : [inc_include, inc_src, inc_gallium, inc_gallium_aux],
dependencies : [idep_mesautil, dep_dxheaders],
)
mediafoundation_st += {codec : lib}
endforeach
if with_gallium_mediafoundation_test
subdir('test')
endif
@@ -0,0 +1,350 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "hmft_entrypoints.h"
#include "videobufferlock.h"
// utility functions to retrieve plane information from IMFMediaType
HRESULT
MFTypeToBitmapInfo(
IMFMediaType *pType, UINT32 *pcbActualBytesPerLine, UINT32 *punLines, UINT32 *pcbSBytesPerLine, UINT32 *punSLines )
{
HRESULT hr = S_OK;
LONG lMinPitch;
UINT32 unWidth, unHeight;
UINT32 cbImageSize, cbActualBytesPerLine, unLines;
GUID format;
CHECKHR_GOTO( pType->GetGUID( MF_MT_SUBTYPE, &format ), done );
CHECKHR_GOTO( MFGetAttributeSize( pType, MF_MT_FRAME_SIZE, &unWidth, &unHeight ), done );
CHECKHR_GOTO( MFCalculateImageSize( format, unWidth, unHeight, &cbImageSize ), done );
CHECKHR_GOTO( MFGetStrideForBitmapInfoHeader( format.Data1, unWidth, &lMinPitch ), done );
cbActualBytesPerLine = abs( lMinPitch );
// dual half-planar formats
if( format == MFVideoFormat_YV12 || format == MFVideoFormat_IYUV || format == MFVideoFormat_I420 )
{
unLines = cbImageSize / ( cbActualBytesPerLine + cbActualBytesPerLine / 2 );
if( nullptr != pcbSBytesPerLine )
*pcbSBytesPerLine = cbActualBytesPerLine / 2;
// processing 2 half planes with half lines, should process double lines
if( nullptr != punSLines )
*punSLines = unLines;
}
else
{
unLines = cbImageSize / cbActualBytesPerLine;
if( nullptr != pcbSBytesPerLine )
*pcbSBytesPerLine = 0;
if( nullptr != punSLines )
*punSLines = 0;
}
if( nullptr != pcbActualBytesPerLine )
*pcbActualBytesPerLine = cbActualBytesPerLine;
if( nullptr != punLines )
*punLines = unLines;
done:
return hr;
}
// utility function to retrieve default image size from IMFMediaType
HRESULT
MFTypeToImageSize( IMFMediaType *pType, UINT32 *pcbSize )
{
HRESULT hr = S_OK;
UINT32 unWidth, unHeight;
UINT32 cbImageSize;
GUID format;
CHECKHR_GOTO( pType->GetGUID( MF_MT_SUBTYPE, &format ), done );
CHECKHR_GOTO( MFGetAttributeSize( pType, MF_MT_FRAME_SIZE, &unWidth, &unHeight ), done );
CHECKHR_GOTO( MFCalculateImageSize( format, unWidth, unHeight, &cbImageSize ), done );
*pcbSize = cbImageSize;
done:
return hr;
}
// utility function to retrieve D3D11 texture from IMFMediaBuffer
HRESULT
MFBufferToDXType( _In_ IMFMediaBuffer *pBuffer, _Outptr_ ID3D11Texture2D **ppTexture, _Out_ UINT *uiViewIndex )
{
HRESULT hr = S_OK;
ComPtr<IMFDXGIBuffer> spDXGIBuffer;
hr = pBuffer->QueryInterface( __uuidof( IMFDXGIBuffer ), (LPVOID *) ( &spDXGIBuffer ) );
if( SUCCEEDED( hr ) )
{
hr = spDXGIBuffer->GetResource( __uuidof( ID3D11Texture2D ), (LPVOID *) ppTexture );
}
if( SUCCEEDED( hr ) && uiViewIndex != nullptr )
{
hr = spDXGIBuffer->GetSubresourceIndex( uiViewIndex );
}
return hr;
}
// utility function to retrieve D3D12 texture from IMFMediaBuffer
HRESULT
MFBufferToDXType( _In_ IMFMediaBuffer *pBuffer, _Outptr_ ID3D12Resource **ppTexture, _Out_ UINT *uiViewIndex )
{
HRESULT hr = S_OK;
ComPtr<IMFDXGIBuffer> spDXGIBuffer;
hr = pBuffer->QueryInterface( __uuidof( IMFDXGIBuffer ), (LPVOID *) ( &spDXGIBuffer ) );
if( SUCCEEDED( hr ) )
{
hr = spDXGIBuffer->GetResource( __uuidof( ID3D12Resource ), (LPVOID *) ppTexture );
}
if( SUCCEEDED( hr ) && uiViewIndex != nullptr )
{
hr = spDXGIBuffer->GetSubresourceIndex( uiViewIndex );
}
return hr;
}
// utility function to copy MFSample
HRESULT
MFCopySample( IMFSample *dest, IMFSample *src, IMFMediaType *pmt )
{
HRESULT hr = S_OK;
ComPtr<IMFMediaBuffer> pOutput, pInput;
ComPtr<ID3D11Texture2D> srcTexture, dstTexture;
ComPtr<ID3D11Device> pSrcDevice, pDstDevice;
ComPtr<ID3D11DeviceContext> pCtx;
UINT uiSrcIndex, uiDstIndex;
DWORD dwBufferCount;
UINT32 dwSize = 0;
BOOL bUsedDX = FALSE;
UINT32 cbActualBytesPerLine, unLines, cbSActualBytes, unSLines;
CHECKHR_GOTO( MFTypeToBitmapInfo( pmt, &cbActualBytesPerLine, &unLines, &cbSActualBytes, &unSLines ), done );
if( !dest || !src )
{
return E_POINTER;
}
(void) src->CopyAllItems( dest );
LONGLONG hnsTime;
hr = src->GetSampleTime( &hnsTime );
if( SUCCEEDED( hr ) )
{
hr = dest->SetSampleTime( hnsTime );
}
hr = S_OK;
LONGLONG hnsDuration;
hr = src->GetSampleDuration( &hnsDuration );
if( SUCCEEDED( hr ) )
{
hr = dest->SetSampleDuration( hnsDuration );
}
hr = S_OK;
hr = src->GetBufferCount( &dwBufferCount );
if( SUCCEEDED( hr ) )
for( DWORD x = 0; x < dwBufferCount; x++ )
{
hr = src->GetBufferByIndex( x, &pInput );
if( FAILED( hr ) )
{
break;
}
hr = dest->GetBufferByIndex( x, &pOutput );
if( FAILED( hr ) )
{
hr = MFCreateMediaBufferFromMediaType( pmt, hnsDuration, 0, 0, &pOutput );
if( FAILED( hr ) )
{
break;
}
hr = dest->AddBuffer( pOutput.Get() );
if( FAILED( hr ) )
{
break;
}
}
// Try to use DX if available
if( SUCCEEDED( MFBufferToDXType( pOutput.Get(), &srcTexture, &uiSrcIndex ) ) &&
SUCCEEDED( MFBufferToDXType( pInput.Get(), &dstTexture, &uiDstIndex ) ) )
{
srcTexture->GetDevice( &pSrcDevice );
dstTexture->GetDevice( &pDstDevice );
if( pSrcDevice != pDstDevice )
{
// TODO: if both are shared we can keyed mutex them across
}
else
{
pSrcDevice->GetImmediateContext( &pCtx );
pCtx->CopySubresourceRegion( dstTexture.Get(), uiDstIndex, 0, 0, 0, srcTexture.Get(), uiSrcIndex, NULL );
bUsedDX = TRUE;
}
hr = MFTypeToImageSize( pmt, &dwSize );
if( FAILED( hr ) )
{
break;
}
}
if( !bUsedDX )
{
VideoBufferLock inputLock( pInput.Get(), pmt );
VideoBufferLock outputLock( pOutput.Get(), pmt );
hr = inputLock.lock( MF2DBuffer_LockFlags_Read );
if( FAILED( hr ) )
{
break;
}
hr = outputLock.lock( MF2DBuffer_LockFlags_Write );
if( FAILED( hr ) )
{
break;
}
hr = MFCopyImage( outputLock.data(),
outputLock.stride(),
inputLock.data(),
inputLock.stride(),
cbActualBytesPerLine,
unLines );
if( FAILED( hr ) )
{
break;
}
if( unSLines )
{
hr = MFCopyImage( outputLock.data(),
outputLock.stride(),
inputLock.data(),
inputLock.stride(),
cbSActualBytes,
unSLines );
}
dwSize = inputLock.size();
}
hr = pOutput->SetCurrentLength( dwSize );
if( FAILED( hr ) )
{
break;
}
}
done:
return hr;
}
//
// MFAttachPipeResourceAsSampleExtension
//
// Description:
// Converts a Gallium pipe_resource into a D3D12 resource and wraps it as an IMFMediaBuffer,
// then attaches it as a sample extension on an IMFSample using the specified GUID.
//
// Parameters:
// pPipeContext - Pointer to the Gallium pipe context.
// pPipeRes - Pointer to the pipe_resource to be wrapped.
// pSyncObjectQueue - Pointer to the sync object command queue.
// guidExtension - The GUID of the Media Foundation sample extension to attach the buffer as.
// pSample - The output IMFSample to attach the media buffer to.
//
// Returns:
// S_OK if the operation was successful.
// E_INVALIDARG if any required pointer is null.
// E_FAIL if resource_get_handle fails.
// E_POINTER if the returned COM object is null.
// Other HRESULT failure codes from MFCreateDXGISurfaceBuffer or SetUnknown.
//
HRESULT
MFAttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
struct pipe_resource *pPipeRes,
UINT PipeResourceReconstructedPictureSubresource,
ID3D12CommandQueue *pSyncObjectQueue,
REFGUID guidExtension,
IMFSample *pSample )
{
if( !pPipeContext || !pPipeRes || !pSample || !pSyncObjectQueue )
{
return E_INVALIDARG;
}
struct winsys_handle whandle = {};
whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
if( !pPipeContext->screen->resource_get_handle( pPipeContext->screen, pPipeContext, pPipeRes, &whandle, 0u ) )
{
return E_FAIL;
}
if( !whandle.com_obj )
{
return E_POINTER;
}
ID3D12Resource *pD3D12Res = static_cast<ID3D12Resource *>( whandle.com_obj );
ComPtr<IMFMediaBuffer> spMediaBuffer;
HRESULT hr = MFCreateDXGISurfaceBuffer( __uuidof( ID3D12Resource ),
pD3D12Res,
PipeResourceReconstructedPictureSubresource,
FALSE,
&spMediaBuffer );
if( FAILED( hr ) )
{
return hr;
}
// Tell MF that this buffer is ready to use.
ComPtr<IMFD3D12SynchronizationObjectCommands> spOutputSync; // needed to call Lock() for IMFMediaBuffer.
ComPtr<IMFDXGIBuffer> spDxgiBuffer;
hr = spMediaBuffer->QueryInterface( IID_PPV_ARGS( &spDxgiBuffer ) );
if( SUCCEEDED( hr ) )
{
hr = spDxgiBuffer->GetUnknown( MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS( &spOutputSync ) );
if( SUCCEEDED( hr ) )
{
hr = spOutputSync->EnqueueResourceReady( pSyncObjectQueue );
if( FAILED( hr ) )
return hr;
}
else
{
return hr;
}
}
else
{
return hr;
}
return pSample->SetUnknown( guidExtension, spMediaBuffer.Get() );
}
@@ -0,0 +1,57 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <d3d12.h>
#include <mfidl.h>
// Given a media type report plane information
// pType - type to get info for
// pcbActualBytesPerLine - line byte count for first plane
// punLines - line count for first plane
// pcbSBytesPerLine - line byte count for second plane (may be null)
// punSLines - line count for second plane (may be null)
HRESULT
MFTypeToBitmapInfo( IMFMediaType *pType,
UINT32 *pcbActualBytesPerLine,
UINT32 *punLines,
UINT32 *pcbSBytesPerLine = nullptr,
UINT32 *punSLines = nullptr );
// Gets the default size of an image for pmt
HRESULT
MFTypeToImageSize( IMFMediaType *pType, UINT32 *pcbSize );
// Copy a sample from src to dst for the given media type (copies buffer contents)
HRESULT
MFCopySample( IMFSample *dest, IMFSample *src, IMFMediaType *pmt );
// Converts a Gallium pipe_resource into a D3D12 resource and wraps it as an IMFMediaBuffer,
// then attaches it as a sample extension on an IMFSample using the specified GUID.
HRESULT
MFAttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
struct pipe_resource *pPipeRes,
UINT PipeResourceReconstructedPictureSubresource,
ID3D12CommandQueue *pSyncObjectQueue,
REFGUID guidExtension,
IMFSample *pSample );
@@ -0,0 +1,448 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include "mfd3dmanager.h"
#include <algorithm>
#include <iterator>
#include <map>
#include <vector>
#include "wpptrace.h"
#include "mfd3dmanager.tmh"
CMFD3DManager::CMFD3DManager( void *logId ) : m_logId( logId )
{ }
CMFD3DManager::~CMFD3DManager()
{
Shutdown();
}
// #define ENABLE_D3D12_DEBUG_LAYER
HRESULT
CMFD3DManager::Initialize( D3D12_VIDEO_ENCODER_CODEC codec )
{
#ifdef ENABLE_D3D12_DEBUG_LAYER
ComPtr<ID3D12Debug> spDebugController;
if( SUCCEEDED( D3D12GetDebugInterface( IID_PPV_ARGS( &spDebugController ) ) ) )
{
spDebugController->EnableDebugLayer();
}
#endif
m_codec = codec;
return S_OK;
}
HRESULT
CMFD3DManager::Shutdown( bool bReleaseDeviceManager )
{
HRESULT hr = S_OK;
m_spDevice = nullptr;
m_spVideoDevice = nullptr;
m_spDevice11 = nullptr;
m_spStagingQueue = nullptr;
if( m_spVideoSampleAllocator )
{
m_spVideoSampleAllocator->UninitializeSampleAllocator();
m_spVideoSampleAllocator = nullptr;
}
if( m_spSatdStatsBufferPool )
{
m_spSatdStatsBufferPool.Reset();
}
if( m_spBitsUsedStatsBufferPool )
{
m_spBitsUsedStatsBufferPool.Reset();
}
if( m_spQPMapStatsBufferPool )
{
m_spQPMapStatsBufferPool.Reset();
}
if( m_spReconstructedPictureBufferPool )
{
m_spReconstructedPictureBufferPool.Reset();
}
// Release scheduler registrations before closing the device handle
m_ContextPriorityMgr.m_registeredQueues.clear();
m_ContextPriorityMgr.m_spSchedulerClient.Reset();
m_ContextPriorityMgr.m_hDevice = NULL;
if( m_spDeviceManager != nullptr )
{
if( m_hDevice != NULL )
{
m_spDeviceManager->CloseDeviceHandle( m_hDevice );
m_hDevice = NULL;
}
if( bReleaseDeviceManager )
m_spDeviceManager = nullptr;
}
if( m_pPipeContext )
{
m_pPipeContext->destroy( m_pPipeContext );
m_pPipeContext = nullptr;
}
if( m_pVlScreen )
{
m_pVlScreen->destroy( this->m_pVlScreen );
m_pVlScreen = nullptr;
m_deviceVendorId = {};
m_deviceDeviceId = {};
m_deviceDriverVersion = {};
m_gpuFeatureFlags = {};
}
if( m_pWinsys )
{
m_pWinsys->destroy( this->m_pWinsys );
m_pWinsys = nullptr;
}
if( m_ContextPriorityMgr.base.register_work_queue )
{
mtx_destroy( &m_ContextPriorityMgr.m_lock );
m_ContextPriorityMgr.base.register_work_queue = nullptr;
}
return hr;
}
static inline HRESULT
CreateD3D12DeviceWithMinimumSupportedFeatureLevel( IUnknown *pAdapter, ComPtr<ID3D12Device> &spDevice )
{
static const D3D_FEATURE_LEVEL levels[] = {
#if ( D3D12_SDK_VERSION >= 611 )
D3D_FEATURE_LEVEL_1_0_GENERIC,
#endif
D3D_FEATURE_LEVEL_1_0_CORE,
D3D_FEATURE_LEVEL_11_0,
};
for( uint32_t i = 0; i < ARRAYSIZE( levels ); i++ )
if( SUCCEEDED( D3D12CreateDevice( pAdapter, levels[i], IID_PPV_ARGS( spDevice.ReleaseAndGetAddressOf() ) ) ) )
return S_OK;
return E_FAIL;
}
HRESULT
CMFD3DManager::xReopenDeviceManager( bool bNewDevice )
{
HRESULT hr = S_OK;
D3D12_COMMAND_QUEUE_DESC commandQueueDesc = { D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE };
D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC capCodecData = { 0U, m_codec, false };
Shutdown( false );
CHECKHR_GOTO( m_spDeviceManager->OpenDeviceHandle( &m_hDevice ), done );
if( FAILED( m_spDeviceManager->GetVideoService( m_hDevice, IID_ID3D12Device, &m_spDevice ) ) )
{
ComPtr<IDXGIDevice> spDXGIDevice;
ComPtr<IDXGIAdapter> spDXGIAdapter;
ComPtr<IUnknown> spAdapter;
ComPtr<ID3D11DeviceContext> spImmediaContext;
ComPtr<ID3D11Multithread> spMultithread;
CHECKHR_GOTO( m_spDeviceManager->GetVideoService( m_hDevice, IID_ID3D11Device, &m_spDevice11 ), done );
CHECKHR_GOTO( m_spDevice11.As( &spDXGIDevice ), done );
CHECKHR_GOTO( spDXGIDevice->GetAdapter( &spDXGIAdapter ), done );
CHECKHR_GOTO( spDXGIAdapter.As( &spAdapter ), done );
// Create a D3D12 device off of the same adapter this 11 device is on
CHECKHR_GOTO( CreateD3D12DeviceWithMinimumSupportedFeatureLevel( spAdapter.Get(), m_spDevice ), done );
// check if the D3D11 device is multithread protected and issue warning
m_spDevice11->GetImmediateContext( &spImmediaContext );
CHECKHR_GOTO( spImmediaContext.As( &spMultithread ), done );
if( !spMultithread->GetMultithreadProtected() )
{
MFE_WARNING( "[dx12 hmft 0x%p] D3D11 device was created without multithread protected\n", m_logId );
}
}
// Create a staging queue for MF to signal on input texture GPU completion
CHECKHR_GOTO( m_spDevice->CreateCommandQueue( &commandQueueDesc, IID_PPV_ARGS( &m_spStagingQueue ) ), done );
CHECKHR_GOTO( m_spDevice.As( &m_spVideoDevice ), done );
CHECKHR_GOTO( m_spVideoDevice->CheckFeatureSupport( D3D12_FEATURE_VIDEO_ENCODER_CODEC, &capCodecData, sizeof( capCodecData ) ),
done );
CHECKBOOL_GOTO( capCodecData.IsSupported, MF_E_UNSUPPORTED_D3D_TYPE, done );
done:
return hr;
}
enum
{
MFT_HW_VENDOR_AMD = 0x1002,
MFT_HW_VENDOR_INTEL = 0x8086,
MFT_HW_VENDOR_MICROSOFT = 0x1414,
MFT_HW_VENDOR_NVIDIA = 0x10de,
};
static const char *
VendorIDToString( uint32_t vendorId )
{
switch( vendorId )
{
case MFT_HW_VENDOR_MICROSOFT:
return "Microsoft";
case MFT_HW_VENDOR_AMD:
return "AMD";
case MFT_HW_VENDOR_NVIDIA:
return "NVIDIA";
case MFT_HW_VENDOR_INTEL:
return "Intel";
default:
return "Unknown";
}
}
inline UINT16
ExtractDriverVersionComponent( const size_t index, const LARGE_INTEGER &driverVersion )
{
return (UINT16) ( driverVersion.QuadPart >> ( index * 8 * 2 ) ) & 0xffff;
}
// retrieve device information such as vendor id, device id, driver version. we'll use this info later on
// to do block list and driver version dependent operations.
HRESULT
CMFD3DManager::GetDeviceInfo()
{
HRESULT hr = S_OK;
ComPtr<IDXGIFactory4> factory;
ComPtr<IDXGIAdapter2> adaptor;
DXGI_ADAPTER_DESC desc;
LARGE_INTEGER driverVersion;
LUID luid = m_spDevice->GetAdapterLuid();
CHECKHR_GOTO( CreateDXGIFactory( IID_PPV_ARGS( &factory ) ), done );
CHECKHR_GOTO( factory->EnumAdapterByLuid( luid, IID_PPV_ARGS( &adaptor ) ), done );
CHECKHR_GOTO( adaptor->GetDesc( &desc ), done );
CHECKHR_GOTO( adaptor->CheckInterfaceSupport( __uuidof( IDXGIDevice ), &driverVersion ), done );
m_deviceVendorId = desc.VendorId;
m_deviceDeviceId = desc.DeviceId;
m_deviceDriverVersion.part1 = ExtractDriverVersionComponent( 3, driverVersion );
m_deviceDriverVersion.part2 = ExtractDriverVersionComponent( 2, driverVersion );
m_deviceDriverVersion.part3 = ExtractDriverVersionComponent( 1, driverVersion );
m_deviceDriverVersion.part4 = ExtractDriverVersionComponent( 0, driverVersion );
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: device vendor = %s\n", m_logId, VendorIDToString( m_deviceVendorId ) );
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: device vendor id = %x\n", m_logId, m_deviceVendorId );
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: device device id = %x\n", m_logId, m_deviceDeviceId );
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: %S", m_logId, desc.Description );
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: device driver version = %d.%d.%d.%d\n",
m_logId,
m_deviceDriverVersion.part1,
m_deviceDriverVersion.part2,
m_deviceDriverVersion.part3,
m_deviceDriverVersion.part4 );
done:
return hr;
}
void
CMFD3DManager::UpdateGPUFeatureFlags()
{
if( m_deviceVendorId == MFT_HW_VENDOR_AMD )
{
m_gpuFeatureFlags.m_bDisableAsync = true;
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: GPUFeature m_bDisableAsync is set to true\n", m_logId );
}
/*
if( m_deviceVendorId == MFT_HW_VENDOR_NVIDIA )
{
if( m_deviceDriverVersion.part1 >= 32 && m_deviceDriverVersion.part2 >= 0 && m_deviceDriverVersion.part3 >= 15 &&
m_deviceDriverVersion.part4 >= 9002 )
{
m_gpuFeatureFlags.m_bH264SendUnwrappedPOC = true;
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: GPUFeature m_bH264SendUnwrappedPOC is set to true", m_logId );
}
}
*/
}
int
MFTRegisterWorkQueue( struct d3d12_context_queue_priority_manager *manager, ID3D12CommandQueue *queue )
{
mft_context_queue_priority_manager *mft_mgr = (mft_context_queue_priority_manager *) manager;
if( !queue )
{
return -1;
}
mtx_lock( &mft_mgr->m_lock );
if( mft_mgr->m_spSchedulerClient )
{
if( mft_mgr->m_registeredQueues.find( queue ) == mft_mgr->m_registeredQueues.end() )
{
HRESULT hr = S_OK;
ComPtr<IMFDXGISchedulerRegistration> spRegistration;
hr = mft_mgr->m_spSchedulerClient->RegisterObject( mft_mgr->m_hDevice, queue, &spRegistration );
if( FAILED( hr ) )
{
MFE_ERROR( "[dx12 hmft 0x%p] D3DManager: RegisterObject failed for Queue 0x%p", mft_mgr->m_logId, queue );
mtx_unlock( &mft_mgr->m_lock );
return -1;
}
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: RegisterObject succeeded for Queue 0x%p, spRegistration 0x%p",
mft_mgr->m_logId,
queue,
spRegistration.Get() );
mft_mgr->m_registeredQueues[queue] = spRegistration;
}
}
else
{
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: m_spSchedulerClient is not supported -> no opt", mft_mgr->m_logId );
}
mtx_unlock( &mft_mgr->m_lock );
return 0;
}
int
MFTUnregisterWorkQueue( struct d3d12_context_queue_priority_manager *manager, ID3D12CommandQueue *queue )
{
mft_context_queue_priority_manager *mft_mgr = (mft_context_queue_priority_manager *) manager;
if( !queue )
{
return -1;
}
mtx_lock( &mft_mgr->m_lock );
if( mft_mgr->m_spSchedulerClient )
{
auto item = mft_mgr->m_registeredQueues.find( queue );
if( item != mft_mgr->m_registeredQueues.end() )
{
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: Releases spRegistration for Queue 0x%p, spRegistration 0x%p",
mft_mgr->m_logId,
queue,
item->second.Get() );
#if MESA_DEBUG
{
uint32_t global_priority, local_priority;
mft_mgr->base.get_queue_priority( &mft_mgr->base, queue, &global_priority, &local_priority );
debug_printf( "[dx12 hmft 0x%p] D3DManager: ending queue = 0x%p, local_priority = %d, global_priority = %d\n",
mft_mgr->m_logId,
queue,
local_priority,
global_priority );
}
#endif
mft_mgr->m_registeredQueues.erase( item );
}
else
{
MFE_WARNING( "[dx12 hmft 0x%p] D3DManager: Queue 0x%p is unexpectedly not found in m_registeredQueues",
mft_mgr->m_logId,
queue );
}
}
else
{
MFE_INFO( "[dx12 hmft 0x%p] D3DManager: m_spSchedulerClient is not supported -> no opt", mft_mgr->m_logId );
}
mtx_unlock( &mft_mgr->m_lock );
return 0;
}
HRESULT
CMFD3DManager::xOnSetD3DManager( ULONG_PTR ulParam )
{
HRESULT hr = S_OK;
Shutdown();
if( ulParam == 0 )
{
return hr;
}
else
{
// We've been given an IUnknown, make sure it is an IMFDXGIDeviceManager
CHECKHR_GOTO( reinterpret_cast<IUnknown *>( ulParam )->QueryInterface( IID_PPV_ARGS( &m_spDeviceManager ) ), done );
}
CHECKHR_GOTO( xReopenDeviceManager( true ), done );
CHECKNULL_GOTO( m_pWinsys = null_sw_create(), MF_E_DXGI_DEVICE_NOT_INITIALIZED, done );
CHECKNULL_GOTO( m_pVlScreen = vl_win32_screen_create_from_d3d12_device( m_spDevice.Get(), m_pWinsys ),
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
CHECKNULL_GOTO( m_pPipeContext = pipe_create_multimedia_context( m_pVlScreen->pscreen, false ),
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
m_pVlScreen->pscreen->interop_query_device_info( m_pVlScreen->pscreen,
sizeof( d3d12_interop_device_info1 ),
&m_ScreenInteropInfo );
assert( m_ScreenInteropInfo.set_context_queue_priority_manager != NULL );
{
CHECKBOOL_GOTO( thrd_success == mtx_init( &m_ContextPriorityMgr.m_lock, mtx_plain ), MF_E_DXGI_DEVICE_NOT_INITIALIZED, done );
m_ContextPriorityMgr.m_logId = m_logId;
m_ContextPriorityMgr.base.register_work_queue = MFTRegisterWorkQueue;
m_ContextPriorityMgr.base.unregister_work_queue = MFTUnregisterWorkQueue;
// Query for scheduler client to register driver work queues with the MF scheduler
ComPtr<IMFDXGISchedulerClient> spScheduler;
if( SUCCEEDED( m_spDeviceManager->GetVideoService( m_hDevice, IID_PPV_ARGS( &spScheduler ) ) ) )
{
m_ContextPriorityMgr.m_spSchedulerClient = spScheduler;
m_ContextPriorityMgr.m_hDevice = m_hDevice;
}
CHECKBOOL_GOTO( m_ScreenInteropInfo.set_context_queue_priority_manager( m_pPipeContext, &m_ContextPriorityMgr.base ) == 0,
MF_E_DXGI_DEVICE_NOT_INITIALIZED,
done );
//
// Verify that the callbacks have been filled by the driver
//
CHECKNULL_GOTO( m_ContextPriorityMgr.base.context, MF_E_DXGI_DEVICE_NOT_INITIALIZED, done );
CHECKNULL_GOTO( m_ContextPriorityMgr.base.set_queue_priority, MF_E_DXGI_DEVICE_NOT_INITIALIZED, done );
CHECKNULL_GOTO( m_ContextPriorityMgr.base.get_queue_priority, MF_E_DXGI_DEVICE_NOT_INITIALIZED, done );
}
CHECKHR_GOTO( GetDeviceInfo(), done );
UpdateGPUFeatureFlags();
done:
if( FAILED( hr ) )
{
Shutdown();
}
return hr;
}
@@ -0,0 +1,186 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include "pipe_headers.h"
#include "gallium/include/frontend/sw_winsys.h"
#include "gallium/winsys/sw/null/null_sw_winsys.h"
#include "util/u_video.h"
#include "vl/vl_winsys.h"
// directx/xxx has the latest headers from DirectX-Headers dependency
// and must be included _before_ any Windows SDK headers (e.g d3d11.h, etc)
#include <d3d11.h>
#include <directx/d3d12.h>
#include <directx/d3d12video.h>
#include <d3d11_4.h>
#include <mfapi.h>
#include <mferror.h>
#include <mfidl.h> // for IMFVideoSampleAllocatorEx
#include <mutex>
#include <vector>
#include "gallium/drivers/d3d12/d3d12_interop_public.h"
#include <c11/threads.h>
#include <wrl/client.h>
#include <wrl/implements.h>
#include <unordered_map>
#include "macros.h"
#include "stats_buffer_manager.h"
// Use the Windows SDK dxcore include (e.g directx/dxcore uses DirectX-Headers)
#include <dxcore.h>
// Forward declare experimental MF DXGI Scheduler interfaces (not yet in all SDK versions)
#ifndef __IMFDXGISchedulerRegistration_INTERFACE_DEFINED__
#define __IMFDXGISchedulerRegistration_INTERFACE_DEFINED__
typedef enum MF_DXGI_SCHEDULING_PRIORITY
{
MF_DXGI_SCHEDULING_PRIORITY_IDLE = 0,
MF_DXGI_SCHEDULING_PRIORITY_DEFAULT = 0x1,
MF_DXGI_SCHEDULING_PRIORITY_HIGH = 0x2
} MF_DXGI_SCHEDULING_PRIORITY;
/* interface IMFDXGISchedulerRegistration */
/* [uuid][local][object] */
EXTERN_C const IID IID_IMFDXGISchedulerRegistration;
MIDL_INTERFACE( "396ACD9A-C9EF-41e5-8009-6735C0528875" )
IMFDXGISchedulerRegistration : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE GetPriority(
/* [annotation][out] */
_Out_ MF_DXGI_SCHEDULING_PRIORITY * priority ) = 0;
virtual HRESULT STDMETHODCALLTYPE SetPriority(
/* [in] */ MF_DXGI_SCHEDULING_PRIORITY priority ) = 0;
};
/* interface IMFDXGISchedulerClient */
/* [uuid][local][object] */
EXTERN_C const IID IID_IMFDXGISchedulerClient;
MIDL_INTERFACE( "DF681668-70EC-457B-9AA3-CAA60910A710" )
IMFDXGISchedulerClient : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE RegisterObject(
/* [annotation][in] */
_In_ HANDLE hDevice,
/* [annotation][in] */
_In_ IUnknown * pObject,
/* [annotation][out] */
_COM_Outptr_ IMFDXGISchedulerRegistration * *ppRegistration ) = 0;
};
#endif
// end: Forward declare experimental MF DXGI Scheduler interfaces (not yet in all SDK versions)
using namespace Microsoft::WRL;
using Microsoft::WRL::ComPtr;
using namespace std;
typedef union
{
struct
{
// Driver version format is part1.part2.part3.part4 (e.g 31.0.15.5019)
uint16_t part1 : 16;
uint16_t part2 : 16;
uint16_t part3 : 16;
uint16_t part4 : 16;
};
uint64_t version; // bits field
} MFAdapterDriverVersion;
struct mft_context_queue_priority_manager
{
struct d3d12_context_queue_priority_manager base;
std::unordered_map<ID3D12CommandQueue *, ComPtr<IMFDXGISchedulerRegistration>> m_registeredQueues;
ComPtr<IMFDXGISchedulerClient> m_spSchedulerClient;
HANDLE m_hDevice = NULL;
mtx_t m_lock;
const void *m_logId = {};
};
class CMFD3DManager
{
public:
CMFD3DManager( void *logId );
~CMFD3DManager();
HRESULT Initialize( D3D12_VIDEO_ENCODER_CODEC codec );
HRESULT Shutdown( bool bReleaseDeviceManager = true );
// Set D3D manager, use in ProcessMessage
HRESULT xOnSetD3DManager( ULONG_PTR ulParam );
protected:
HRESULT xReopenDeviceManager( bool bNewDevice );
HRESULT GetDeviceInfo();
void UpdateGPUFeatureFlags();
ComPtr<IMFDXGIDeviceManager> m_spDeviceManager;
ComPtr<ID3D11Device5> m_spDevice11;
ComPtr<ID3D12Device> m_spDevice;
ComPtr<ID3D12VideoDevice> m_spVideoDevice;
ComPtr<ID3D12CommandQueue> m_spStagingQueue;
ComPtr<IMFVideoSampleAllocatorEx> m_spVideoSampleAllocator; // Used for software input samples that need to be copied
ComPtr<stats_buffer_manager> m_spSatdStatsBufferPool;
ComPtr<stats_buffer_manager> m_spBitsUsedStatsBufferPool;
ComPtr<stats_buffer_manager> m_spQPMapStatsBufferPool;
ComPtr<stats_buffer_manager> m_spReconstructedPictureBufferPool;
UINT32 m_uiResetToken = 0;
HANDLE m_hDevice = NULL;
struct vl_screen *m_pVlScreen = nullptr;
struct sw_winsys *m_pWinsys = nullptr;
struct pipe_context *m_pPipeContext = nullptr;
struct d3d12_interop_device_info1 m_ScreenInteropInfo = {};
struct mft_context_queue_priority_manager m_ContextPriorityMgr = {};
uint32_t m_deviceVendorId {};
uint32_t m_deviceDeviceId {};
MFAdapterDriverVersion m_deviceDriverVersion {};
// MFT features that are dependent on GPU / version (ensure these are named to be false by default so we can easily reset this
// struct)
struct GPUFeatureFlags
{
bool m_bDisableAsync = false;
bool m_bH264SendUnwrappedPOC = true;
};
GPUFeatureFlags m_gpuFeatureFlags;
private:
D3D12_VIDEO_ENCODER_CODEC m_codec;
const void *m_logId = {};
};
@@ -0,0 +1,93 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "hmft_entrypoints.h"
// IMFMediaEventGenerator::BeginGetEvent
// https://learn.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfmediaeventgenerator-begingetevent
HRESULT
CDX12EncHMFT::BeginGetEvent( IMFAsyncCallback *pCallback, IUnknown *punkState )
{
HRESULT hr = S_OK;
std::lock_guard<std::mutex> lock( m_lock );
CHECKHR_GOTO( CheckShutdown(), done );
CHECKHR_GOTO( m_spEventQueue->BeginGetEvent( pCallback, punkState ), done );
done:
return hr;
}
// IMFMediaEventGenerator::EndGetEvent
// https://learn.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfmediaeventgenerator-endgetevent
HRESULT
CDX12EncHMFT::EndGetEvent( IMFAsyncResult *pResult, IMFMediaEvent **ppEvent )
{
HRESULT hr = S_OK;
MediaEventType met = MEUnknown;
std::lock_guard<std::mutex> lock( m_lock );
CHECKHR_GOTO( CheckShutdown(), done );
CHECKHR_GOTO( m_spEventQueue->EndGetEvent( pResult, ppEvent ), done );
( *ppEvent )->GetType( &met );
debug_printf( "[dx12 hmft 0x%p] EndGetEvent - SUCCESS, type = 0x%x\n", this, met );
return hr;
done:
debug_printf( "[dx12 hmft 0x%p] EndGetEvent - FAILED 0x%x\n", this, hr );
return hr;
}
// IMFMediaEventGenerator::GetEvent
// https://learn.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfmediaeventgenerator-getevent
HRESULT
CDX12EncHMFT::GetEvent( DWORD dwFlags, IMFMediaEvent **ppEvent )
{
HRESULT hr = S_OK;
CHECKHR_GOTO( CheckShutdown(), done );
CHECKHR_GOTO( m_spEventQueue->GetEvent( dwFlags, ppEvent ), done );
done:
return hr;
}
// IMFMediaEventGenerator::QueueEvent
// https://learn.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfmediaeventgenerator-queueevent
HRESULT
CDX12EncHMFT::QueueEvent( MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT *pvValue )
{
HRESULT hr = S_OK;
ComPtr<IMFMediaEvent> spEvent;
CHECKHR_GOTO( CheckShutdown(), done );
CHECKHR_GOTO( MFCreateMediaEvent( met, guidExtendedType, hrStatus, pvValue, &spEvent ), done );
switch( met )
{
case METransformDrainComplete:
spEvent->SetUINT32( MF_EVENT_MFT_INPUT_STREAM_ID, 0 );
break;
}
CHECKHR_GOTO( m_spEventQueue->QueueEvent( spEvent.Get() ), done );
done:
return hr;
}
@@ -0,0 +1,441 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "hmft_entrypoints.h"
#include "mfpipeinterop.h"
// utility to convert from pipe_video_profile to AVEncVProfile
uint32_t
ConvertPipeProfileToSpecProfile( pipe_video_profile profile )
{
switch( profile )
{
case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
return eAVEncH264VProfile_Base;
case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
return eAVEncH264VProfile_Main;
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
return eAVEncH264VProfile_High;
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
return eAVEncH264VProfile_High10;
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
return eAVEncH265VProfile_Main_420_8;
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
return eAVEncH265VProfile_Main_420_10;
case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
return eAVEncH265VProfile_Main_444_8;
default:
return 0;
}
}
// utility to convert from AVEncVProfile to pipe_video_profile
enum pipe_video_profile
ConvertAVEncVProfileToPipeVideoProfile( struct vl_screen *vlScreen, UINT32 profile, D3D12_VIDEO_ENCODER_CODEC codec )
{
enum pipe_video_profile pipeProfile = PIPE_VIDEO_PROFILE_UNKNOWN;
switch( codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
switch( (eAVEncH264VProfile) profile )
{
case eAVEncH264VProfile_Base: // %%%TODO - Revisit, up-promoting this isn't always valid
case eAVEncH264VProfile_ConstrainedBase:
pipeProfile = PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE;
break;
case eAVEncH264VProfile_Main:
pipeProfile = PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN;
break;
case eAVEncH264VProfile_Extended: // We shouldn't get this, SetOutputType() should've already failed
pipeProfile = PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED;
break;
case eAVEncH264VProfile_ConstrainedHigh: // strict subset, so promote to high
case eAVEncH264VProfile_High:
pipeProfile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;
break;
case eAVEncH264VProfile_High10:
pipeProfile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10;
break;
case eAVEncH264VProfile_422:
pipeProfile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH422;
break;
case eAVEncH264VProfile_444:
pipeProfile = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444;
break;
}
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
switch( (eAVEncH265VProfile) profile )
{
case eAVEncH265VProfile_Main_420_8:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN;
break;
case eAVEncH265VProfile_Main_420_10:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN_10;
break;
case eAVEncH265VProfile_Main_422_8:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN_422;
break;
case eAVEncH265VProfile_Main_422_10:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN10_422;
break;
case eAVEncH265VProfile_Main_444_8:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN_444;
break;
case eAVEncH265VProfile_Main_444_10:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN10_444;
break;
}
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
switch( (eAVEncAV1VProfile) profile )
{
case eAVEncAV1VProfile_Main_420_8:
pipeProfile = PIPE_VIDEO_PROFILE_AV1_MAIN;
break;
}
break;
}
if( !vlScreen->pscreen->get_video_param( vlScreen->pscreen, pipeProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_SUPPORTED ) )
{
return PIPE_VIDEO_PROFILE_UNKNOWN;
}
return pipeProfile;
}
// utility to convert from AVEncVProfile to pipe_video_chroma_format
enum pipe_video_chroma_format
ConvertAVEncVProfileToPipeVideoChromaFormat( UINT32 profile, D3D12_VIDEO_ENCODER_CODEC codec )
{
// default to 420
pipe_video_chroma_format chromaFormat = PIPE_VIDEO_CHROMA_FORMAT_420;
switch( codec )
{
case D3D12_VIDEO_ENCODER_CODEC_H264:
switch( profile )
{
case eAVEncH264VProfile_422:
chromaFormat = PIPE_VIDEO_CHROMA_FORMAT_422;
break;
case eAVEncH264VProfile_444:
chromaFormat = PIPE_VIDEO_CHROMA_FORMAT_444;
break;
}
break;
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
switch( profile )
{
case eAVEncH265VProfile_Main_422_10:
case eAVEncH265VProfile_Main_422_12:
chromaFormat = PIPE_VIDEO_CHROMA_FORMAT_422;
break;
case eAVEncH265VProfile_Main_444_8:
case eAVEncH265VProfile_Main_444_10:
case eAVEncH265VProfile_Main_444_12:
chromaFormat = PIPE_VIDEO_CHROMA_FORMAT_444;
break;
}
break;
case D3D12_VIDEO_ENCODER_CODEC_AV1:
switch( profile )
{
case eAVEncAV1VProfile_High_444_10:
case eAVEncAV1VProfile_High_444_8:
case eAVEncAV1VProfile_Professional_444_12:
chromaFormat = PIPE_VIDEO_CHROMA_FORMAT_444;
break;
case eAVEncAV1VProfile_Professional_422_8:
case eAVEncAV1VProfile_Professional_422_10:
case eAVEncAV1VProfile_Professional_422_12:
chromaFormat = PIPE_VIDEO_CHROMA_FORMAT_422;
break;
}
break;
}
return chromaFormat;
}
// utility to convert from pipe_h2645_enc_picture_type to eAVEncH264PictureType
// There is no eAVEncH265PictureType, so this is used for both
enum eAVEncH264PictureType
ConvertPictureTypeToAVEncH264PictureType( enum pipe_h2645_enc_picture_type picType )
{
switch( picType )
{
case PIPE_H2645_ENC_PICTURE_TYPE_P:
return eAVEncH264PictureType_P;
case PIPE_H2645_ENC_PICTURE_TYPE_B:
return eAVEncH264PictureType_B;
case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
case PIPE_H2645_ENC_PICTURE_TYPE_I:
default:
return eAVEncH264PictureType_IDR;
}
}
// utility to convert from eAVEncH264PictureType to pipe_h2645_enc_picture_type
enum pipe_video_profile
ConvertAVEncH265VProfileToPipeVideoProfile( struct vl_screen *vlScreen, eAVEncH265VProfile profile )
{
enum pipe_video_profile pipeProfile;
switch( profile )
{
case eAVEncH265VProfile_Main_420_8:
case eAVEncH265VProfile_MainIntra_420_8:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN;
break;
case eAVEncH265VProfile_Main_420_10:
case eAVEncH265VProfile_MainIntra_420_10:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN_10;
break;
case eAVEncH265VProfile_Main_444_8:
pipeProfile = PIPE_VIDEO_PROFILE_HEVC_MAIN_444;
default:
pipeProfile = PIPE_VIDEO_PROFILE_UNKNOWN;
break;
}
if( !vlScreen->pscreen->get_video_param( vlScreen->pscreen, pipeProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_SUPPORTED ) )
{
return PIPE_VIDEO_PROFILE_UNKNOWN;
}
return pipeProfile;
}
// utility to convert from eAVEncH265VProfile to pipe_video_chroma_format
enum pipe_video_chroma_format
ConvertAVEncH265VProfileToPipeVideoChromaFormat( eAVEncH265VProfile profile )
{
switch( profile )
{
case eAVEncH265VProfile_Main_422_10:
case eAVEncH265VProfile_Main_422_12:
case eAVEncH265VProfile_MainIntra_422_10:
case eAVEncH265VProfile_MainIntra_422_12:
return PIPE_VIDEO_CHROMA_FORMAT_422;
break;
case eAVEncH265VProfile_Main_444_8:
case eAVEncH265VProfile_Main_444_12:
case eAVEncH265VProfile_Main_444_10:
case eAVEncH265VProfile_MainIntra_444_8:
case eAVEncH265VProfile_MainIntra_444_10:
case eAVEncH265VProfile_MainIntra_444_12:
return PIPE_VIDEO_CHROMA_FORMAT_444;
break;
default:
return PIPE_VIDEO_CHROMA_FORMAT_420;
break;
}
}
// utility to convert from FourCC to pipe_format
enum pipe_format
ConvertFourCCToPipeFormat( DWORD dwFourCC )
{
if( dwFourCC == FOURCC_NV12 )
{
return PIPE_FORMAT_NV12;
}
else if( dwFourCC == FOURCC_P010 )
{
return PIPE_FORMAT_P010;
}
else if( dwFourCC == FOURCC_AYUV )
{
return PIPE_FORMAT_AYUV;
}
else if( dwFourCC == FOURCC_YUY2 )
{
return PIPE_FORMAT_YUYV;
}
return PIPE_FORMAT_NONE;
}
// utility to convert from pipe_format to image stride
UINT32
AdjustStrideForPipeFormatAndWidth( enum pipe_format pipeFormat, UINT32 width )
{
UINT32 stride = 0;
switch( pipeFormat )
{
case PIPE_FORMAT_NV12:
stride = width;
break;
case PIPE_FORMAT_P010:
stride = 2 * width;
break;
case PIPE_FORMAT_AYUV:
stride = width;
break;
}
return stride;
}
// utility to convert from pipe_format to chroma format idc
UINT32
GetChromaFormatIdc( enum pipe_format pipeFormat )
{
switch( pipeFormat )
{
case PIPE_FORMAT_NV12:
case PIPE_FORMAT_P010:
return 1;
case PIPE_FORMAT_YUYV:
case PIPE_FORMAT_Y210:
return 2;
case PIPE_FORMAT_AYUV:
case PIPE_FORMAT_Y410:
return 3;
default:
{
UNREACHABLE( "Unsupported pipe video format" );
}
break;
}
}
// utility to convert from pipe_video_profile to pipe_format
enum pipe_format
ConvertProfileToFormat( enum pipe_video_profile profile )
{
switch( profile )
{
case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
case PIPE_VIDEO_PROFILE_AV1_MAIN:
case PIPE_VIDEO_PROFILE_VP9_PROFILE0:
return PIPE_FORMAT_NV12;
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
case PIPE_VIDEO_PROFILE_VP9_PROFILE2:
return PIPE_FORMAT_P010;
case PIPE_VIDEO_PROFILE_HEVC_MAIN_422:
return PIPE_FORMAT_YUYV;
case PIPE_VIDEO_PROFILE_HEVC_MAIN10_422:
return PIPE_FORMAT_Y210;
case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
return PIPE_FORMAT_AYUV;
case PIPE_VIDEO_PROFILE_HEVC_MAIN10_444:
return PIPE_FORMAT_Y410;
default:
{
UNREACHABLE( "Unsupported pipe video profile" );
}
break;
}
}
// utility to convert from pipe_video_profile to MFVideoFormat subtype
GUID
ConvertProfileToSubtype( enum pipe_video_profile profile )
{
switch( profile )
{
case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
case PIPE_VIDEO_PROFILE_HEVC_MAIN:
case PIPE_VIDEO_PROFILE_AV1_MAIN:
return MFVideoFormat_NV12;
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
case PIPE_VIDEO_PROFILE_HEVC_MAIN_10:
return MFVideoFormat_P010;
case PIPE_VIDEO_PROFILE_HEVC_MAIN_422:
return MFVideoFormat_YUY2;
case PIPE_VIDEO_PROFILE_HEVC_MAIN10_422:
return MFVideoFormat_Y210;
case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH444:
case PIPE_VIDEO_PROFILE_HEVC_MAIN_444:
return MFVideoFormat_AYUV;
case PIPE_VIDEO_PROFILE_HEVC_MAIN10_444:
return MFVideoFormat_Y410;
default:
{
UNREACHABLE( "Unsupported pipe video profile" );
}
break;
}
}
// utility to convert from errno to HRESULT
HRESULT
ConvertErrnoRetToHR( int ret )
{
switch( ret )
{
case 0:
return S_OK;
case ENOMEM:
return MF_E_INSUFFICIENT_BUFFER;
case EINVAL:
return E_INVALIDARG;
default:
return E_FAIL;
}
}
// utility to convert from pipe_h2645_enc_picture_type to string description
const char *
ConvertPipeH2645FrameTypeToString( pipe_h2645_enc_picture_type picType )
{
switch( picType )
{
case PIPE_H2645_ENC_PICTURE_TYPE_P:
{
return "H264_P_FRAME";
}
break;
case PIPE_H2645_ENC_PICTURE_TYPE_B:
{
return "H264_B_FRAME";
}
break;
case PIPE_H2645_ENC_PICTURE_TYPE_I:
{
return "H264_I_FRAME";
}
break;
case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
{
return "H264_IDR_FRAME";
}
break;
default:
{
UNREACHABLE( "Unsupported pipe_h2645_enc_picture_type" );
}
break;
}
}
@@ -0,0 +1,60 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include "util/u_video.h"
#include "vl/vl_defines.h"
#include "vl/vl_video_buffer.h"
#include "vl/vl_winsys.h"
#include "pipe_headers.h"
#include <codecapi.h>
#include <mfobjects.h>
enum pipe_video_profile
ConvertAVEncVProfileToPipeVideoProfile( struct vl_screen *vlScreen, UINT32 profile, D3D12_VIDEO_ENCODER_CODEC codec );
enum pipe_video_chroma_format
ConvertAVEncVProfileToPipeVideoChromaFormat( UINT32 profile, D3D12_VIDEO_ENCODER_CODEC codec );
// H264
enum eAVEncH264PictureType
ConvertPictureTypeToAVEncH264PictureType( enum pipe_h2645_enc_picture_type picType );
uint32_t
ConvertPipeProfileToSpecProfile( pipe_video_profile profile );
enum pipe_format
ConvertFourCCToPipeFormat( DWORD dwFourCC );
UINT32
AdjustStrideForPipeFormatAndWidth( enum pipe_format pipeFormat, UINT32 width );
UINT32
GetChromaFormatIdc( enum pipe_format pipeFormat );
enum pipe_format
ConvertProfileToFormat( enum pipe_video_profile profile );
GUID ConvertProfileToSubtype( enum pipe_video_profile );
HRESULT
ConvertErrnoRetToHR( int ret );
const char *
ConvertPipeH2645FrameTypeToString( pipe_h2645_enc_picture_type picType );
@@ -0,0 +1,61 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "hmft_entrypoints.h"
#include "wpptrace.h"
#include "mfrealtimeclientex.tmh"
// IMFRealTimeClientEx::RegisterThreadsEx
// https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfrealtimeclientex-registerthreadsex
HRESULT
CDX12EncHMFT::RegisterThreadsEx( DWORD *pdwTaskIndex, LPCWSTR wszClassName, LONG lBasePriority )
{
std::lock_guard<std::mutex> lock( m_lock );
if( !pdwTaskIndex )
{
return E_POINTER;
}
if( *pdwTaskIndex == 0 )
{
return E_INVALIDARG;
}
return E_NOTIMPL;
}
// IMFRealTimeClientEx::UnregisterThreads
// https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfrealtimeclientex-unregisterthreads
HRESULT
CDX12EncHMFT::UnregisterThreads()
{
return E_NOTIMPL;
}
// IMFRealTimeClientEx::SetWorkQueueEx
// https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfrealtimeclientex-setworkqueueex
HRESULT
CDX12EncHMFT::SetWorkQueueEx( DWORD dwMultithreadedWorkQueueId, LONG lWorkItemBasePriority )
{
return E_NOTIMPL;
}
@@ -0,0 +1,72 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "hmft_entrypoints.h"
#include "wpptrace.h"
#include "mfshutdown.tmh"
HRESULT
CDX12EncHMFT::CheckShutdown( void )
{
if( m_bShutdown )
{
return MF_E_SHUTDOWN;
}
return S_OK;
}
// IMFShutdown::GetShutdownStatus
// https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfshutdown-getshutdownstatus
HRESULT
CDX12EncHMFT::GetShutdownStatus( MFSHUTDOWN_STATUS *pStatus )
{
HRESULT hr = S_OK;
CHECKNULL_GOTO( pStatus, E_POINTER, done );
CHECKBOOL_GOTO( CheckShutdown() == MF_E_SHUTDOWN, MF_E_INVALIDREQUEST, done );
*pStatus = MFSHUTDOWN_COMPLETED;
done:
MFE_INFO( "[dx12 hmft 0x%p] GetShutdownStatus - hr=0x%x", this, hr );
return hr;
}
// IMFShutdown::Shutdown
// https://learn.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl-imfshutdown-shutdown
HRESULT
CDX12EncHMFT::Shutdown( void )
{
HRESULT hr = S_OK;
std::lock_guard<std::mutex> lock( m_lockShutdown );
debug_printf( "[dx12 hmft 0x%p] Shutdown called\n", this );
if( !m_bShutdown )
{
m_bShutdown = true;
OnFlush();
CleanupEncoder();
}
MFE_INFO( "[dx12 hmft 0x%p] Shutdown - hr=0x%x", this, hr );
return hr;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,27 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include "pipe/p_video_codec.h"
#include "pipe/p_video_enums.h"
#include "pipe/p_video_state.h"
@@ -0,0 +1,90 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <vector>
#include "pipe_headers.h"
typedef enum frame_descriptor_reference_type
{
frame_descriptor_reference_type_none = 0,
frame_descriptor_reference_type_short_term = 1,
frame_descriptor_reference_type_long_term = 2,
} frame_descriptor_reference_type;
typedef struct reference_frames_tracker_frame_descriptor
{
} reference_frames_tracker_frame_descriptor;
class reference_frames_tracker_dpb_async_token
{
public:
std::vector<pipe_video_buffer *> dpb_buffers_to_release;
std::vector<pipe_video_buffer *> dpb_downscaled_buffers_to_release;
};
class reference_frames_tracker
{
public:
// pass control variables for current frame to reference tracker and compute reference frame states
virtual HRESULT begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t markLTRIndex,
bool useLTR,
uint32_t useLTRBitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum ) = 0;
// moves the GOP state to the next frame for next frame
virtual void advance_frame() = 0;
// release reference frame buffers
virtual void release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken ) = 0;
// returns frame descriptor
virtual const reference_frames_tracker_frame_descriptor *get_frame_descriptor() = 0;
virtual ~reference_frames_tracker()
{ }
};
typedef struct intra_refresh_slices_config
{
enum pipe_video_slice_mode slice_mode;
// Use with PIPE_VIDEO_SLICE_MODE_BLOCKS
unsigned num_slice_descriptors;
struct h264_slice_descriptor slices_descriptors[128];
// Use with PIPE_VIDEO_SLICE_MODE_MAX_SLICE_SLICE
unsigned max_slice_bytes;
} intra_refresh_slices_config;
class intra_refresh_tracker
{
public:
// start intra refresh tracker wave for the current frame
virtual bool start_ir_wave() = 0;
virtual ~intra_refresh_tracker()
{ }
};
@@ -0,0 +1,26 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#if MFT_CODEC_AV1ENC
#endif
@@ -0,0 +1,28 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#if MFT_CODEC_AV1ENC
#endif
@@ -0,0 +1,831 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#if MFT_CODEC_H264ENC
#include "reference_frames_tracker_h264.h"
#include <algorithm>
#include <cmath>
#include <iterator>
#include "hmft_entrypoints.h"
#include "wpptrace.h"
#include "reference_frames_tracker_h264.tmh"
reference_frames_tracker_h264::reference_frames_tracker_h264( void *logId,
struct pipe_video_codec *codec,
uint32_t textureWidth,
uint32_t textureHeight,
uint32_t gopLength,
uint32_t uiBPictureCount,
bool bLayerCountSet,
uint32_t layerCount,
bool bLowLatency,
uint32_t MaxL0References,
uint32_t MaxDPBCapacity,
uint32_t MaxLongTermReferences,
bool bSendUnwrappedPOC,
std::unique_ptr<dpb_buffer_manager> upTwoPassDPBManager,
HRESULT &hr )
: m_logId( logId ),
m_codec( codec ),
m_MaxL0References( MaxL0References ),
m_MaxDPBCapacity( MaxDPBCapacity ),
m_MaxLongTermReferences( MaxLongTermReferences ),
m_bSendUnwrappedPOC( bSendUnwrappedPOC ),
m_ALL_LTR_VALID_MASK( ( 1 << m_MaxLongTermReferences ) - 1 ),
m_DPBManager(
logId,
m_codec,
textureWidth,
textureHeight,
ConvertProfileToFormat( m_codec->profile ),
m_codec->max_references + 1 /*curr pic*/ +
( bLowLatency ? 0 : MFT_INPUT_QUEUE_DEPTH ), /*MFT process input queue depth for delayed in flight recon pic release*/
hr ),
m_upTwoPassDPBManager( std::move( upTwoPassDPBManager ) )
{
if( SUCCEEDED( hr ) )
{
assert( m_MaxL0References == 1 );
m_bLayerCountSet = bLayerCountSet;
m_uiLayerCount = layerCount;
m_ValidLTRBitmap = m_ALL_LTR_VALID_MASK;
m_gopLength = gopLength;
m_layer_count_set = bLayerCountSet;
m_layer_count = layerCount;
m_force_idr_on_gop_start = true;
assert( uiBPictureCount == 0 );
m_p_picture_period = uiBPictureCount + 1;
m_gop_state.idr_pic_id = 0;
const uint32_t maxFrameNumBitsMinus4 = 4; // legal range is 0 to 12, we will fix to 4 which corresponds to [0..255]
m_gop_state.log2_max_frame_num_minus4 = maxFrameNumBitsMinus4;
m_gop_state.log2_max_pic_order_cnt_lsb_minus4 = maxFrameNumBitsMinus4 + 1;
m_max_frame_num = 1 << ( maxFrameNumBitsMinus4 + 4 );
ResetGopStateToIDR();
m_frame_state_descriptor.gop_info = &m_gop_state;
}
}
// release reference frame buffers
void
reference_frames_tracker_h264::release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken )
{
if( pAsyncDPBToken )
{
for( unsigned i = 0; i < pAsyncDPBToken->dpb_buffers_to_release.size(); i++ )
m_DPBManager.release_dpb_buffer( pAsyncDPBToken->dpb_buffers_to_release[i] );
if( m_upTwoPassDPBManager )
{
for( unsigned i = 0; i < pAsyncDPBToken->dpb_downscaled_buffers_to_release.size(); i++ )
m_upTwoPassDPBManager->release_dpb_buffer( pAsyncDPBToken->dpb_downscaled_buffers_to_release[i] );
}
delete pAsyncDPBToken;
}
}
// pass control variables for current frame to reference tracker and compute reference frame states
HRESULT
reference_frames_tracker_h264::begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t markLTRIndex,
bool useLTR,
uint32_t useLTRBitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum )
{
HRESULT hr = S_OK;
struct pipe_video_buffer *curframe_dpb_buffer = nullptr;
struct pipe_video_buffer *curframe_dpb_downscaled_buffer = nullptr;
uint32_t ltrUsedBitMask = 0;
bool isLTR;
uint32_t longTermReferenceFrameInfo;
curframe_dpb_buffer = m_DPBManager.get_fresh_dpb_buffer();
CHECKNULL_GOTO( curframe_dpb_buffer, E_OUTOFMEMORY, done );
if( m_upTwoPassDPBManager )
{
curframe_dpb_downscaled_buffer = m_upTwoPassDPBManager->get_fresh_dpb_buffer();
CHECKNULL_GOTO( curframe_dpb_downscaled_buffer, E_OUTOFMEMORY, done );
}
if( markLTR )
{
if( m_pendingMarkLTR )
{
debug_printf( "MFT: Mark LTR dropped due to pending LTR\n" );
}
else
{
m_pendingMarkLTR = markLTR;
m_pendingMarkLTRIndex = markLTRIndex;
}
}
assert( m_bLayerCountSet == layerCountSet );
GOPStateBeginFrame( forceKey );
m_frame_state_descriptor.mmco_operations.clear();
m_frame_state_descriptor.l0_reference_list.clear();
m_frame_state_descriptor.ref_list0_mod_operations.clear();
if( m_frame_state_descriptor.gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR )
{
for( auto &i : m_PrevFramesInfos )
{
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( i.buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( i.downscaled_buffer );
}
m_PrevFramesInfos.clear();
m_checkValidSTR = false;
m_ValidSTRFrameNumNoWrap = UINT64_MAX;
m_ActiveLTRBitmap = 0;
m_ValidLTRBitmap = m_ALL_LTR_VALID_MASK;
if( m_MaxLongTermReferences > 0 )
{
m_bSendMaxLongTermReferences = true;
}
}
if( m_MaxLongTermReferences > 0 && m_frame_state_descriptor.gop_info->temporal_id == 0 )
{
// h264 auto marking
uint32_t numActiveLTRs = GetNumberOfActiveLTR();
if( !m_pendingMarkLTR && numActiveLTRs < m_MaxLongTermReferences )
{
int emptyIndex = FindEmptyLTRIndex();
assert( emptyIndex != -1 );
m_pendingMarkLTR = true;
m_pendingMarkLTRIndex = emptyIndex;
}
if( m_pendingMarkLTR )
{
assert( m_gop_state.temporal_id == 0 );
m_gop_state.reference_type = frame_descriptor_reference_type_long_term;
m_gop_state.ltr_index = m_pendingMarkLTRIndex;
m_pendingMarkLTR = false;
}
}
if( m_frame_state_descriptor.gop_info->temporal_id == 0 )
{
if( layerCount != m_uiLayerCount )
{
m_uiLayerCount = layerCount;
m_layer_count = m_uiLayerCount;
}
}
isLTR = ( m_frame_state_descriptor.gop_info->reference_type == frame_descriptor_reference_type_long_term );
if( m_frame_state_descriptor.gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_P )
{
ltrUsedBitMask = PrepareFrameRefLists( useLTR, useLTRBitmap );
}
longTermReferenceFrameInfo = ( ltrUsedBitMask << 16 ) | ( isLTR ? m_frame_state_descriptor.gop_info->ltr_index : 0xFFFF );
m_gop_state.long_term_reference_frame_info = longTermReferenceFrameInfo; // update GOP state
// fill dpb descriptor
m_frame_state_descriptor.dpb_snapshot.clear();
m_frame_state_descriptor.dirty_rect_frame_num.clear();
// Add prev frames DPB info
for( unsigned i = 0; i < m_PrevFramesInfos.size(); i++ )
{
m_frame_state_descriptor.dpb_snapshot.push_back( {
/*id*/ 0u,
/*frame_idx*/ m_PrevFramesInfos[i].is_ltr ? m_PrevFramesInfos[i].ltr_index : m_PrevFramesInfos[i].frame_num,
m_PrevFramesInfos[i].picture_order_count,
m_PrevFramesInfos[i].temporal_id,
m_PrevFramesInfos[i].is_ltr,
m_PrevFramesInfos[i].buffer,
m_PrevFramesInfos[i].downscaled_buffer,
} );
m_frame_state_descriptor.dirty_rect_frame_num.push_back( m_PrevFramesInfos[i].dirty_rect_frame_num );
}
if( m_frame_state_descriptor.gop_info->reference_type != frame_descriptor_reference_type_none )
{
// Add current frame DPB info
m_frame_state_descriptor.dpb_snapshot.push_back( {
/*id*/ 0u,
isLTR ? m_frame_state_descriptor.gop_info->ltr_index : m_frame_state_descriptor.gop_info->frame_num,
m_frame_state_descriptor.gop_info->picture_order_count,
m_frame_state_descriptor.gop_info->temporal_id,
isLTR,
curframe_dpb_buffer,
curframe_dpb_downscaled_buffer,
} );
m_frame_state_descriptor.dirty_rect_frame_num.push_back( dirtyRectFrameNum );
if( m_MaxLongTermReferences > 0 )
{
if( m_bSendMaxLongTermReferences && m_frame_state_descriptor.gop_info->frame_type != PIPE_H2645_ENC_PICTURE_TYPE_IDR )
{
emit_mmco_max_long_term_references();
m_bSendMaxLongTermReferences = false;
}
if( isLTR )
{
emit_mmc0_mark_current_frame_as_ltr( m_frame_state_descriptor.gop_info->ltr_index );
}
if( m_frame_state_descriptor.mmco_operations.size() != 0 )
{
emit_mmco_end_of_memory_management();
}
}
if( m_frame_state_descriptor.mmco_operations.size() == 0 )
{
// Save frame infos if used as reference for next frame
// Remove oldest short-term if DPB full
if( m_PrevFramesInfos.size() == m_MaxDPBCapacity )
{
auto entryToRemove = std::find_if( m_PrevFramesInfos.begin(), m_PrevFramesInfos.end(), [&]( const PrevFrameInfo &p ) {
return !p.is_ltr;
} );
assert( entryToRemove != m_PrevFramesInfos.end() );
if( entryToRemove == m_PrevFramesInfos.end() )
{
UNREACHABLE( "Unexpected zero STR" );
}
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( entryToRemove->buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( entryToRemove->downscaled_buffer );
m_PrevFramesInfos.erase( entryToRemove );
}
}
if( isLTR )
{
// if current LTR index is already used, we will remove the existing LTR picture.
if( IsLTRIndexInLTRBitmap( m_frame_state_descriptor.gop_info->ltr_index ) )
{
auto entryToRemove = m_PrevFramesInfos.begin();
for( ; entryToRemove != m_PrevFramesInfos.end(); ++entryToRemove )
{
if( entryToRemove->is_ltr && entryToRemove->ltr_index == m_frame_state_descriptor.gop_info->ltr_index )
{
break;
}
}
assert( entryToRemove != m_PrevFramesInfos.end() );
if( entryToRemove == m_PrevFramesInfos.end() )
{
UNREACHABLE( "Unexpected LTR replacement in Bitmap but not in PrevFramesInfos" );
}
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( entryToRemove->buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( entryToRemove->downscaled_buffer );
m_PrevFramesInfos.erase( entryToRemove );
}
MarkLTRIndex( m_frame_state_descriptor.gop_info->ltr_index );
}
m_PrevFramesInfos.push_back( { m_frame_state_descriptor.gop_info->picture_order_count,
m_frame_state_descriptor.gop_info->frame_num,
m_frame_state_descriptor.gop_info->frame_num_no_wrap,
isLTR,
m_frame_state_descriptor.gop_info->ltr_index,
m_frame_state_descriptor.gop_info->temporal_id,
dirtyRectFrameNum,
curframe_dpb_buffer,
curframe_dpb_downscaled_buffer } );
}
else
{
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( curframe_dpb_buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( curframe_dpb_downscaled_buffer );
}
done:
return hr;
}
// prepare the reference list for the current frame
uint32_t
reference_frames_tracker_h264::PrepareFrameRefLists( bool useLTR, uint32_t useLTRBitmap )
{
if( useLTR )
{
m_ValidLTRBitmap = useLTRBitmap & m_ALL_LTR_VALID_MASK;
m_checkValidSTR = true;
m_ValidSTRFrameNumNoWrap = m_frame_state_descriptor.gop_info->frame_num_no_wrap;
}
std::vector<RefSortList> ltrIndices;
std::vector<RefSortList> strIndices;
for( size_t i = 0; i < m_PrevFramesInfos.size(); ++i )
{
RefSortList item = { static_cast<uint8_t>( i ),
m_PrevFramesInfos[i].frame_num_no_wrap,
m_PrevFramesInfos[i].is_ltr,
m_PrevFramesInfos[i].ltr_index,
m_PrevFramesInfos[i].temporal_id };
if( m_PrevFramesInfos[i].is_ltr )
{
ltrIndices.push_back( item );
}
else
{
strIndices.push_back( item );
}
}
std::sort( strIndices.begin(), strIndices.end(), []( const RefSortList &a, const RefSortList &b ) {
return a.frame_num_no_wrap > b.frame_num_no_wrap;
} ); // sort STR descending
bool usedSTR = false;
if( !useLTR )
{
bool foundSuitableSTR = false;
size_t suitableSTRIndex = 0;
uint8_t current_tid = m_frame_state_descriptor.gop_info->temporal_id;
uint8_t target_tid = current_tid > 0 ? current_tid - 1 : 0;
for( size_t i = 0; i < strIndices.size(); ++i )
{
if( ( strIndices[i].temporal_id <= target_tid ) &&
!( m_checkValidSTR && strIndices[i].frame_num_no_wrap <= m_ValidSTRFrameNumNoWrap ) )
{
foundSuitableSTR = true;
suitableSTRIndex = i;
break;
}
}
if( foundSuitableSTR )
{
if( current_tid == 0 )
{
assert( strIndices[suitableSTRIndex].temporal_id == 0 );
}
else
{
assert( strIndices[suitableSTRIndex].temporal_id < current_tid );
}
if( suitableSTRIndex == 0 )
{
m_frame_state_descriptor.l0_reference_list.push_back( strIndices[suitableSTRIndex].pos );
}
else
{
uint64_t predFrameNumNoWrap = m_frame_state_descriptor.gop_info->frame_num_no_wrap;
m_frame_state_descriptor.l0_reference_list.push_back( strIndices[suitableSTRIndex].pos );
m_frame_state_descriptor.ref_list0_mod_operations.push_back(
{ 0u, static_cast<uint32_t>( predFrameNumNoWrap - strIndices[suitableSTRIndex].frame_num_no_wrap - 1 ), 0u } );
predFrameNumNoWrap = strIndices[suitableSTRIndex].frame_num_no_wrap;
}
usedSTR = true;
}
}
if( !usedSTR )
{
std::sort( ltrIndices.begin(), ltrIndices.end(), []( const RefSortList &a, const RefSortList &b ) {
return a.frame_num_no_wrap > b.frame_num_no_wrap;
} ); // sort LTR by frame_num descending
for( auto ltr_idx : ltrIndices )
{
if( IsLTRIndexInValidBitMap( ltr_idx.ltr_index ) )
{
m_frame_state_descriptor.l0_reference_list.push_back( ltr_idx.pos );
m_frame_state_descriptor.ref_list0_mod_operations.push_back( { 2u, 0u, ltr_idx.ltr_index } );
break;
}
}
}
if( m_frame_state_descriptor.ref_list0_mod_operations.size() > 0 )
{
// attach at the back the modification_of_pic_nums_idc = 3 = End modification_of_pic_nums_idc syntax element loop
m_frame_state_descriptor.ref_list0_mod_operations.push_back( { 3u, 0u, 0u } );
}
assert( m_frame_state_descriptor.l0_reference_list.size() == 1 );
assert( m_frame_state_descriptor.ref_list0_mod_operations.size() <= 2 );
uint32_t ltrUsedBitmask = 0;
for( size_t i = 0; i < m_frame_state_descriptor.l0_reference_list.size(); ++i )
{
int idx = m_frame_state_descriptor.l0_reference_list[i];
if( m_PrevFramesInfos[idx].is_ltr )
{
ltrUsedBitmask |= ( 1 << m_PrevFramesInfos[idx].ltr_index );
}
}
return ltrUsedBitmask;
}
const reference_frames_tracker_frame_descriptor *
reference_frames_tracker_h264::get_frame_descriptor()
{
return (const reference_frames_tracker_frame_descriptor *) &m_frame_state_descriptor;
}
// emit the mmco mark the current frame as ltr command
void
reference_frames_tracker_h264::emit_mmc0_mark_current_frame_as_ltr( uint32_t ref_frame_index )
{
m_frame_state_descriptor.mmco_operations.push_back( {
// uint8_t memory_management_control_operation;
// Mark the current picture as "used for long-term reference" and assign a long-term frame index to it
6u,
// uint8_t difference_of_pic_nums_minus1;
0u,
// uint8_t long_term_pic_num;
0u,
// uint8_t long_term_frame_idx;
static_cast<uint8_t>( ref_frame_index ),
// uint8_t max_long_term_frame_idx_plus1;
0u,
} );
}
// emit the mmco max long term references command
void
reference_frames_tracker_h264::emit_mmco_max_long_term_references()
{
// Set max_long_term_frame_idx_plus1 to m_MaxLongTermReferences
m_frame_state_descriptor.mmco_operations.push_back( {
// uint8_t memory_management_control_operation;
// Specify the maximum long-term frame index and mark all long-term reference pictures having long-term
// frame indices greater than the maximum value as "unused for reference"
4u,
// difference_of_pic_nums_minus1;
0u,
// uint8_t long_term_pic_num;
0u,
// uint8_t long_term_frame_idx;
0u,
// uint8_t max_long_term_frame_idx_plus1;
static_cast<uint8_t>( m_MaxLongTermReferences ),
} );
}
// emit the mmco end of memory management control command
void
reference_frames_tracker_h264::emit_mmco_end_of_memory_management()
{
m_frame_state_descriptor.mmco_operations.push_back( { 0u, 0u, 0u, 0u, 0u } );
}
// returns the the number active LTR
uint32_t
reference_frames_tracker_h264::GetNumberOfActiveLTR()
{
uint32_t activeLTR = 0;
for( uint32_t i = 0; i < m_MaxLongTermReferences; ++i )
{
if( m_ActiveLTRBitmap & ( 1 << i ) )
{
activeLTR++;
}
}
return activeLTR;
}
// find a free ltr index in the active LTR bitmap (for LTR auto marking)
int
reference_frames_tracker_h264::FindEmptyLTRIndex()
{
int emptyIndex = -1;
for( int i = 0; i < static_cast<int>( m_MaxLongTermReferences ); ++i )
{
if( ( m_ActiveLTRBitmap & ( 1 << i ) ) == 0 )
{
emptyIndex = i;
break;
}
}
return emptyIndex;
}
// mark the ltr index in the active LTR bitmap
void
reference_frames_tracker_h264::MarkLTRIndex( uint32_t index )
{
assert( index < m_MaxLongTermReferences );
m_ActiveLTRBitmap |= ( 1 << index );
m_ValidLTRBitmap |= ( 1 << index );
}
// return whether the LTR index is in the active LTR bitmap which contains the active LTR indices.
bool
reference_frames_tracker_h264::IsLTRIndexInLTRBitmap( uint32_t index )
{
assert( index < m_MaxLongTermReferences );
return m_ActiveLTRBitmap & ( 1 << index );
}
// return whether the LTR index is in the valid LTR bitmap which contains the valid LTR indices.
bool
reference_frames_tracker_h264::IsLTRIndexInValidBitMap( uint32_t index )
{
assert( index < m_MaxLongTermReferences );
return m_ValidLTRBitmap & ( 1 << index );
}
// returns the frame type for the current frame derived using the current frame position index.
void
reference_frames_tracker_h264::ResetGopStateToIDR()
{
m_current_gop_frame_position_index = 0;
m_gop_state.intra_period = m_gopLength;
m_gop_state.ip_period = m_p_picture_period;
m_gop_state.frame_type = PIPE_H2645_ENC_PICTURE_TYPE_IDR;
m_gop_state.frame_num = 0;
m_gop_state.frame_num_no_wrap = 0;
m_gop_state.current_reference_frame_count = 1;
m_gop_state.picture_order_count = 0;
m_gop_state.temporal_id = 0;
m_gop_state.pic_order_cnt_type = ( m_p_picture_period > 2 ) ? 0u : 2u;
m_gop_state.reference_type = frame_descriptor_reference_type_short_term;
m_gop_state.ltr_index = 0;
}
pipe_h2645_enc_picture_type
reference_frames_tracker_h264::GetNextFrameType()
{
if( m_current_gop_frame_position_index == 0 )
return m_force_idr_on_gop_start ? PIPE_H2645_ENC_PICTURE_TYPE_IDR : PIPE_H2645_ENC_PICTURE_TYPE_I;
else if( m_p_picture_period == 0 )
return PIPE_H2645_ENC_PICTURE_TYPE_I;
else
return ( m_current_gop_frame_position_index % m_p_picture_period == 0 ) ? PIPE_H2645_ENC_PICTURE_TYPE_P :
PIPE_H2645_ENC_PICTURE_TYPE_B;
}
// initializes the gop state for the current frame
void
reference_frames_tracker_h264::GOPStateBeginFrame( bool forceKey )
{
m_gop_state.frame_type = GetNextFrameType();
uint32_t temporal_id = 0;
if( m_layer_count_set )
{
assert( m_layer_count <= 2 );
temporal_id = ( m_current_gop_frame_position_index & ( m_layer_count - 1 ) );
}
m_gop_state.long_term_reference_frame_info = 0x0000FFFF; // [31...16] ltr bitmap, [15...0] ltr index or 0xFFFF for STR
if( forceKey || m_gop_state.frame_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR )
{
if( m_first_idr )
{
m_first_idr = false;
}
else
{
m_gop_state.idr_pic_id++;
}
ResetGopStateToIDR();
}
else
{
// perhaps should add some handling for the unreasonably long encode case.
assert( m_gop_state.current_reference_frame_count != UINT64_MAX );
m_gop_state.frame_num = ( m_gop_state.current_reference_frame_count ) % m_max_frame_num;
m_gop_state.frame_num_no_wrap = m_gop_state.current_reference_frame_count;
if( temporal_id == 0 )
{
m_gop_state.reference_type = frame_descriptor_reference_type_short_term;
m_gop_state.temporal_id = 0;
if( m_bSendUnwrappedPOC )
{
m_gop_state.picture_order_count = ( 2 * m_gop_state.frame_num_no_wrap );
}
else
{
m_gop_state.picture_order_count = ( 2 * m_gop_state.frame_num ) % ( 2 * m_max_frame_num );
}
m_gop_state.current_reference_frame_count++;
}
else
{
m_gop_state.reference_type = frame_descriptor_reference_type_none;
m_gop_state.temporal_id = 1;
if( m_bSendUnwrappedPOC )
{
m_gop_state.picture_order_count = ( 2 * m_gop_state.frame_num_no_wrap - 1 );
}
else
{
m_gop_state.picture_order_count = ( 2 * m_gop_state.frame_num - 1 ) % ( 2 * m_max_frame_num );
}
}
}
}
// moves the GOP state to the next frame for next frame
void
reference_frames_tracker_h264::advance_frame()
{
m_current_gop_frame_position_index = ( m_gopLength > 0 ) ? // Wrap around m_gop_length for non-infinite GOP
( ( m_current_gop_frame_position_index + 1 ) % m_gopLength ) :
( m_current_gop_frame_position_index + 1 );
}
//
// Intra Refresh Tracker
//
void
intra_refresh_tracker_row_h264::reset_ir_state_desc()
{
m_ir_state_desc.base = *( (reference_frames_tracker_frame_descriptor_h264 *) m_ref_pics_tracker->get_frame_descriptor() );
m_ir_state_desc.slices_config = m_non_ir_wave_slices_config;
m_ir_state_desc.current_ir_wave_frame_index = 0;
m_ir_state_desc.intra_refresh_params.mode = INTRA_REFRESH_MODE_NONE;
m_ir_state_desc.intra_refresh_params.need_sequence_header = false;
m_ir_state_desc.intra_refresh_params.offset = 0;
m_ir_state_desc.intra_refresh_params.region_size = 0;
}
intra_refresh_tracker_row_h264::intra_refresh_tracker_row_h264( reference_frames_tracker *ref_pic_tracker,
uint32_t ir_wave_duration,
intra_refresh_slices_config non_ir_wave_slices_config,
uint32_t total_frame_macroblocks,
bool continuous_refresh )
: m_ir_wave_duration( ir_wave_duration ),
m_ref_pics_tracker( ref_pic_tracker ),
m_non_ir_wave_slices_config( non_ir_wave_slices_config ),
m_ir_state_desc( {} ),
m_total_frame_macroblocks( total_frame_macroblocks ),
m_continuous_refresh( continuous_refresh )
{
reset_ir_state_desc();
}
intra_refresh_tracker_row_h264::~intra_refresh_tracker_row_h264()
{
if( m_ref_pics_tracker )
delete m_ref_pics_tracker;
}
// forward to underlying reference tracker
void
intra_refresh_tracker_row_h264::release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken )
{
m_ref_pics_tracker->release_reconpic( pAsyncDPBToken );
}
// start intra refresh wave and then forward to underlying reference tracker
HRESULT
intra_refresh_tracker_row_h264::begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t mark_ltr_index,
bool useLTR,
uint32_t use_ltr_bitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum )
{
HRESULT hr = S_OK;
if( m_ir_state_desc.intra_refresh_params.mode == INTRA_REFRESH_MODE_UNIT_ROWS )
{
if( ( ++m_ir_state_desc.current_ir_wave_frame_index ) < m_ir_wave_duration )
{
m_ir_state_desc.intra_refresh_params.need_sequence_header = false;
m_ir_state_desc.intra_refresh_params.offset += m_ir_state_desc.intra_refresh_params.region_size;
}
else
{
reset_ir_state_desc();
}
}
CHECKHR_GOTO( m_ref_pics_tracker->begin_frame( pAsyncDPBToken,
forceKey,
markLTR,
mark_ltr_index,
useLTR,
use_ltr_bitmap,
layerCountSet,
layerCount,
dirtyRectFrameNumSet,
dirtyRectFrameNum ),
done );
{
// If the underlying GOP tracker signaled an IDR (e.g a new GOP started) let's end any active IR wave
reference_frames_tracker_frame_descriptor_h264 *underlying_frame_desc =
(reference_frames_tracker_frame_descriptor_h264 *) m_ref_pics_tracker->get_frame_descriptor();
if( underlying_frame_desc->gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR )
{
reset_ir_state_desc();
}
else if( // For P, B frames, restart the continuous IR wave if not already active
( ( underlying_frame_desc->gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_P ) ||
( underlying_frame_desc->gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_B ) ) &&
( m_continuous_refresh && ( m_ir_state_desc.intra_refresh_params.mode == INTRA_REFRESH_MODE_NONE ) ) )
{
start_ir_wave();
}
}
done:
return hr;
}
// forward to underlying reference tracker
void
intra_refresh_tracker_row_h264::advance_frame()
{
m_ref_pics_tracker->advance_frame();
}
const reference_frames_tracker_frame_descriptor *
intra_refresh_tracker_row_h264::get_frame_descriptor()
{
m_ir_state_desc.base = *( (reference_frames_tracker_frame_descriptor_h264 *) m_ref_pics_tracker->get_frame_descriptor() );
return (reference_frames_tracker_frame_descriptor *) &m_ir_state_desc.base;
}
// start intra refresh tracker wave for the current frame
bool
intra_refresh_tracker_row_h264::start_ir_wave()
{
auto frame_type = ( (reference_frames_tracker_frame_descriptor_h264 *) get_frame_descriptor() )->gop_info->frame_type;
if( ( frame_type != PIPE_H2645_ENC_PICTURE_TYPE_B ) && ( frame_type != PIPE_H2645_ENC_PICTURE_TYPE_P ) )
{
debug_printf( "[intra_refresh_tracker_row_h264x::start_ir_wave] Error: IR wave can be only started on P/B frames.\n" );
assert( false );
return false;
}
if( m_ir_state_desc.intra_refresh_params.mode == INTRA_REFRESH_MODE_UNIT_ROWS )
{
debug_printf( "[intra_refresh_tracker_row_h264x::start_ir_wave] - Error: Another IR wave is currently active.\n" );
assert( false );
return false;
}
// Start IR wave with m_ir_wave_duration slices per frame (as per DX12 intra-refresh spec)
m_ir_state_desc.intra_refresh_params.mode = INTRA_REFRESH_MODE_UNIT_ROWS;
m_ir_state_desc.intra_refresh_params.need_sequence_header = true;
m_ir_state_desc.intra_refresh_params.offset = 0;
m_ir_state_desc.intra_refresh_params.region_size = m_total_frame_macroblocks / m_ir_wave_duration;
m_ir_state_desc.slices_config.slice_mode = PIPE_VIDEO_SLICE_MODE_BLOCKS;
m_ir_state_desc.slices_config.num_slice_descriptors = m_ir_wave_duration;
uint32_t slice_starting_mb = 0;
memset( m_ir_state_desc.slices_config.slices_descriptors, 0, sizeof( m_ir_state_desc.slices_config.slices_descriptors ) );
for( uint32_t i = 0; i < m_ir_state_desc.slices_config.num_slice_descriptors; i++ )
{
m_ir_state_desc.slices_config.slices_descriptors[i].macroblock_address = slice_starting_mb;
m_ir_state_desc.slices_config.slices_descriptors[i].num_macroblocks = m_ir_state_desc.intra_refresh_params.region_size;
slice_starting_mb += m_ir_state_desc.intra_refresh_params.region_size;
}
return true;
}
#endif
@@ -0,0 +1,235 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#if MFT_CODEC_H264ENC
#include <deque>
#include <memory>
#include <queue>
#include "dpb_buffer_manager.h"
#include "reference_frames_tracker.h"
typedef struct frame_descriptor_h264
{
uint32_t intra_period;
uint32_t ip_period;
pipe_h2645_enc_picture_type frame_type;
uint32_t frame_num; // H264: frame_num % max_frame_num, reset on IDR
uint32_t frame_num_no_wrap;
uint32_t current_reference_frame_count;
uint32_t picture_order_count;
frame_descriptor_reference_type reference_type;
uint32_t ltr_index;
uint32_t pic_order_cnt_type;
uint32_t idr_pic_id;
uint32_t log2_max_frame_num_minus4;
uint8_t temporal_id;
uint32_t log2_max_pic_order_cnt_lsb_minus4;
uint32_t long_term_reference_frame_info; // corresponds to MFT attribute MFSampleExtension_LongTermReferenceFrameInfo
} frame_descriptor_h264;
typedef struct reference_frames_tracker_frame_descriptor_h264
{
reference_frames_tracker_frame_descriptor base;
const struct frame_descriptor_h264 *gop_info;
std::vector<uint8_t> l0_reference_list;
std::vector<struct pipe_h264_ref_list_mod_entry> ref_list0_mod_operations;
std::vector<pipe_h264_ref_pic_marking_entry> mmco_operations;
std::vector<pipe_h264_enc_dpb_entry> dpb_snapshot; // for H265 use the same, ignore frame_num/idx
std::vector<uint32_t> dirty_rect_frame_num; // index corresponds to dbp_snapshot
} reference_frames_tracker_frame_descriptor_h264;
class reference_frames_tracker_h264 : public reference_frames_tracker
{
public:
typedef struct PrevFrameInfo
{
uint32_t picture_order_count;
uint32_t frame_num;
uint32_t frame_num_no_wrap;
bool is_ltr;
uint32_t ltr_index;
uint8_t temporal_id;
uint32_t dirty_rect_frame_num;
struct pipe_video_buffer *buffer;
struct pipe_video_buffer *downscaled_buffer;
} PrevFrameInfo;
// used to sort PrevFrameInfo array
typedef struct RefSortList
{
uint8_t pos; // index into location in the PrevFrameInfo array
// below are from PrevFrameInfo
uint32_t frame_num_no_wrap;
bool is_ltr;
uint32_t ltr_index;
uint8_t temporal_id;
} RefSortList;
HRESULT begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t markLTRIndex,
bool useLTR,
uint32_t useLTRBitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum );
void advance_frame();
const reference_frames_tracker_frame_descriptor *get_frame_descriptor();
void release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken );
// Declare other methods
reference_frames_tracker_h264( void *logId,
struct pipe_video_codec *codec,
uint32_t textureWidth,
uint32_t textureHeight,
uint32_t gopLength,
uint32_t uiBPictureCount,
bool bLayerCountSet,
uint32_t layerCount,
bool bLowLatency,
uint32_t MaxL0References,
uint32_t MaxDPBCapacity,
uint32_t MaxLongTermReferences,
bool bSendUnwrappedPOC,
std::unique_ptr<dpb_buffer_manager> upTwoPassDPBManager,
HRESULT &hr );
private:
uint32_t PrepareFrameRefLists( bool useLTR, uint32_t useLTRBitmap );
void emit_mmco_max_long_term_references();
void emit_mmc0_mark_current_frame_as_ltr( uint32_t ref_frame_index );
void emit_mmco_end_of_memory_management();
uint32_t GetNumberOfActiveLTR();
int FindEmptyLTRIndex();
void MarkLTRIndex( uint32_t index );
bool IsLTRIndexInLTRBitmap( uint32_t index );
bool IsLTRIndexInValidBitMap( uint32_t index );
reference_frames_tracker_frame_descriptor_h264 m_frame_state_descriptor = {};
uint32_t m_MaxL0References = 0;
uint32_t m_MaxDPBCapacity = 0;
uint32_t m_MaxLongTermReferences = 0;
bool m_bSendUnwrappedPOC = false;
bool m_bSendMaxLongTermReferences = false;
uint32_t m_ActiveLTRBitmap = 0;
const uint32_t m_ALL_LTR_VALID_MASK;
uint32_t m_ValidLTRBitmap = 0;
bool m_checkValidSTR = false;
uint64_t m_ValidSTRFrameNumNoWrap = UINT64_MAX;
std::deque<struct PrevFrameInfo> m_PrevFramesInfos;
const void *m_logId = {};
struct pipe_video_codec *m_codec;
dpb_buffer_manager m_DPBManager;
std::unique_ptr<dpb_buffer_manager> m_upTwoPassDPBManager;
bool m_pendingMarkLTR = false;
uint32_t m_pendingMarkLTRIndex = 0;
bool m_bLayerCountSet = false;
uint32_t m_uiLayerCount = 0;
// GOP Tracker
void GOPStateBeginFrame( bool forceKey );
pipe_h2645_enc_picture_type GetNextFrameType();
void ResetGopStateToIDR();
uint32_t m_gopLength = 0;
const uint32_t m_poc_increment = 2;
uint32_t m_p_picture_period = 0;
uint32_t m_max_frame_num = 0;
bool m_force_idr_on_gop_start = true;
bool m_first_idr = true;
uint32_t m_current_gop_frame_position_index = 0;
frame_descriptor_h264 m_gop_state;
bool m_layer_count_set = false;
uint32_t m_layer_count = 1;
// GOPTracker
};
typedef struct intra_refresh_tracker_frame_descriptor_h264
{
struct reference_frames_tracker_frame_descriptor_h264 base;
struct intra_refresh_slices_config slices_config;
uint32_t current_ir_wave_frame_index;
struct pipe_enc_intra_refresh intra_refresh_params;
} intra_refresh_tracker_frame_descriptor_h264;
class intra_refresh_tracker_row_h264 : public reference_frames_tracker, public intra_refresh_tracker
{
// reference_frames_tracker
public:
HRESULT begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t mark_ltr_index,
bool useLTR,
uint32_t use_ltr_bitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum );
void advance_frame(); // GOP Tracker
const reference_frames_tracker_frame_descriptor *get_frame_descriptor();
void release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken );
public:
// intra_refresh_tracker
bool start_ir_wave();
// intra_refresh_tracker_row_h264
intra_refresh_tracker_row_h264( reference_frames_tracker *ref_pic_tracker,
uint32_t ir_wave_duration,
intra_refresh_slices_config non_ir_wave_slices_config,
uint32_t total_frame_macroblocks,
bool continuous_refresh = true );
~intra_refresh_tracker_row_h264();
private:
bool m_continuous_refresh = true;
const uint32_t m_ir_wave_duration = 0u;
reference_frames_tracker *m_ref_pics_tracker = {};
const intra_refresh_slices_config m_non_ir_wave_slices_config = {};
intra_refresh_tracker_frame_descriptor_h264 m_ir_state_desc = {};
uint32_t m_total_frame_macroblocks = 0;
void reset_ir_state_desc();
};
#endif
@@ -0,0 +1,547 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#if MFT_CODEC_H265ENC
#include "reference_frames_tracker_hevc.h"
#include <algorithm>
#include <cmath>
#include <iterator>
#include "hmft_entrypoints.h"
#include "wpptrace.h"
#include "reference_frames_tracker_hevc.tmh"
reference_frames_tracker_hevc::reference_frames_tracker_hevc( void *logId,
struct pipe_video_codec *codec,
uint32_t textureWidth,
uint32_t textureHeight,
uint32_t gopLength,
uint32_t uiBPictureCount,
bool bLayerCountSet,
uint32_t layerCount,
bool bLowLatency,
uint32_t MaxL0References,
uint32_t MaxDPBCapacity,
uint32_t MaxLongTermReferences,
std::unique_ptr<dpb_buffer_manager> upTwoPassDPBManager,
HRESULT &hr )
: m_logId( logId ),
m_codec( codec ),
m_MaxL0References( MaxL0References ),
m_MaxDPBCapacity( MaxDPBCapacity ),
m_MaxLongTermReferences( MaxLongTermReferences ),
m_DPBManager(
logId,
m_codec,
textureWidth,
textureHeight,
ConvertProfileToFormat( m_codec->profile ),
m_codec->max_references + 1 /*curr pic*/ +
( bLowLatency ? 0 : MFT_INPUT_QUEUE_DEPTH ) /*MFT process input queue depth for delayed in flight recon pic release*/,
hr ),
m_upTwoPassDPBManager( std::move( upTwoPassDPBManager ) )
{
if( SUCCEEDED( hr ) )
{
assert( m_MaxL0References == 1 );
m_gopLength = gopLength;
m_force_idr_on_gop_start = true;
m_p_picture_period = uiBPictureCount + 1;
m_gop_state.log2_max_pic_order_cnt_lsb_minus4 = 4; // legal range is 0 to 12, we will fix to 4 which corresponds to [0..255]
ResetGopStateToIDR();
m_frame_state_descriptor.gop_info = &m_gop_state;
m_frame_state_descriptor.l0_reference_list.resize( 1 );
m_frame_state_descriptor.dpb_snapshot.reserve( m_MaxDPBCapacity + 1 );
m_frame_state_descriptor.dirty_rect_frame_num.reserve( m_MaxDPBCapacity + 1 );
}
}
// release reference frame buffers
void
reference_frames_tracker_hevc::release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken )
{
if( pAsyncDPBToken )
{
for( const auto &buffer : pAsyncDPBToken->dpb_buffers_to_release )
m_DPBManager.release_dpb_buffer( buffer );
if( m_upTwoPassDPBManager )
{
for( const auto &buffer : pAsyncDPBToken->dpb_downscaled_buffers_to_release )
m_upTwoPassDPBManager->release_dpb_buffer( buffer );
}
delete pAsyncDPBToken;
}
}
// pass control variables for current frame to reference tracker and compute reference frame states
HRESULT
reference_frames_tracker_hevc::begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t markLTRIndex,
bool useLTR,
uint32_t useLTRBitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum )
{
HRESULT hr = S_OK;
struct pipe_video_buffer *curframe_dpb_buffer = nullptr;
struct pipe_video_buffer *curframe_dpb_downscaled_buffer = nullptr;
uint32_t ltrUsedBitMask = 0;
uint32_t longTermReferenceFrameInfo;
bool isLTR;
curframe_dpb_buffer = m_DPBManager.get_fresh_dpb_buffer();
CHECKNULL_GOTO( curframe_dpb_buffer, E_OUTOFMEMORY, done );
if( m_upTwoPassDPBManager )
{
curframe_dpb_downscaled_buffer = m_upTwoPassDPBManager->get_fresh_dpb_buffer();
CHECKNULL_GOTO( curframe_dpb_downscaled_buffer, E_OUTOFMEMORY, done );
}
if( markLTR )
{
if( m_pendingMarkLTR )
{
debug_printf( "MFT: Mark LTR dropped due to pending LTR\n" );
}
else
{
m_pendingMarkLTR = markLTR;
m_pendingMarkLTRIndex = markLTRIndex;
}
}
GOPStateBeginFrame( forceKey );
if( m_frame_state_descriptor.gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR )
{
for( auto &i : m_PrevFramesInfos )
{
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( i.buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( i.downscaled_buffer );
}
m_PrevFramesInfos.clear();
m_ActiveLTRBitmap = 0;
}
if( m_MaxLongTermReferences > 0 && m_frame_state_descriptor.gop_info->temporal_id == 0 )
{
if( m_pendingMarkLTR )
{
assert( m_gop_state.temporal_id == 0 );
m_gop_state.reference_type = frame_descriptor_reference_type_long_term;
m_gop_state.ltr_index = m_pendingMarkLTRIndex;
m_pendingMarkLTR = false;
}
}
isLTR = ( m_frame_state_descriptor.gop_info->reference_type == frame_descriptor_reference_type_long_term );
if( m_frame_state_descriptor.gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_P )
{
if( useLTR )
{
auto itr = m_PrevFramesInfos.begin();
while( itr != m_PrevFramesInfos.end() )
{
bool is_ltr = itr->is_ltr;
uint32_t ltr_index = itr->ltr_index;
if( !is_ltr || ( is_ltr && !( useLTRBitmap & ( 1 << ltr_index ) ) ) )
{
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( itr->buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( itr->downscaled_buffer );
itr = m_PrevFramesInfos.erase( itr );
}
else
{
++itr;
}
}
m_ActiveLTRBitmap = useLTRBitmap & 0xFFFF; // synchronize active LTR bitmap with useLTRBitmap
}
ltrUsedBitMask = PrepareFrameRefLists();
}
longTermReferenceFrameInfo = ( ltrUsedBitMask << 16 ) | ( isLTR ? m_frame_state_descriptor.gop_info->ltr_index : 0xFFFF );
m_gop_state.long_term_reference_frame_info = longTermReferenceFrameInfo; // Update GOP State
// fill dpb descriptor
m_frame_state_descriptor.dpb_snapshot.clear();
m_frame_state_descriptor.dirty_rect_frame_num.clear();
for( const auto &frame : m_PrevFramesInfos )
{
m_frame_state_descriptor.dpb_snapshot.emplace_back(
/*id*/ 0u,
/*frame_idx ignored*/ 0u,
frame.picture_order_count,
frame.temporal_id,
frame.is_ltr,
frame.buffer,
frame.downscaled_buffer );
m_frame_state_descriptor.dirty_rect_frame_num.push_back( frame.dirty_rect_frame_num );
}
if( m_frame_state_descriptor.gop_info->reference_type != frame_descriptor_reference_type_none )
{
// Add current frame DPB info
m_frame_state_descriptor.dpb_snapshot.push_back( { /*id*/ 0u,
/* frame_idx - ignored */ 0u,
m_frame_state_descriptor.gop_info->picture_order_count,
m_frame_state_descriptor.gop_info->temporal_id,
isLTR,
curframe_dpb_buffer,
curframe_dpb_downscaled_buffer } );
m_frame_state_descriptor.dirty_rect_frame_num.push_back( dirtyRectFrameNum );
// if( m_frame_state_descriptor.gop_info->is_used_as_future_reference )
// Save frame infos if used as reference for next frame
// Remove oldest short-term if DPB full
if( m_PrevFramesInfos.size() == m_MaxDPBCapacity )
{
auto entryToRemove =
std::find_if( m_PrevFramesInfos.begin(), m_PrevFramesInfos.end(), [&]( const PrevFrameInfo &p ) { return !p.is_ltr; } );
assert( entryToRemove != m_PrevFramesInfos.end() );
if( entryToRemove == m_PrevFramesInfos.end() )
{
UNREACHABLE( "Unexpected zero STR" );
}
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( entryToRemove->buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( entryToRemove->downscaled_buffer );
m_PrevFramesInfos.erase( entryToRemove );
}
if( isLTR )
{
// if current LTR index is already used, we will remove the existing LTR picture.
if( IsLTRIndexInLTRBitmap( m_frame_state_descriptor.gop_info->ltr_index ) )
{
auto entryToRemove = m_PrevFramesInfos.begin();
for( ; entryToRemove != m_PrevFramesInfos.end(); ++entryToRemove )
{
if( entryToRemove->is_ltr && entryToRemove->ltr_index == m_frame_state_descriptor.gop_info->ltr_index )
{
break;
}
}
assert( entryToRemove != m_PrevFramesInfos.end() );
if( entryToRemove == m_PrevFramesInfos.end() )
{
UNREACHABLE( "Unexpected LTR replacement in Bitmap but not in PrevFramesInfos" );
}
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( entryToRemove->buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( entryToRemove->downscaled_buffer );
m_PrevFramesInfos.erase( entryToRemove );
}
MarkLTRIndex( m_frame_state_descriptor.gop_info->ltr_index );
}
m_PrevFramesInfos.push_back( { m_frame_state_descriptor.gop_info->picture_order_count,
isLTR,
m_frame_state_descriptor.gop_info->ltr_index,
m_frame_state_descriptor.gop_info->temporal_id,
dirtyRectFrameNum,
curframe_dpb_buffer,
curframe_dpb_downscaled_buffer } );
}
else
{
( pAsyncDPBToken )->dpb_buffers_to_release.push_back( curframe_dpb_buffer );
if( m_upTwoPassDPBManager )
( pAsyncDPBToken )->dpb_downscaled_buffers_to_release.push_back( curframe_dpb_downscaled_buffer );
}
done:
return hr;
}
// prepare the reference list for the current frame
uint32_t
reference_frames_tracker_hevc::PrepareFrameRefLists()
{
assert( m_PrevFramesInfos.size() >= 1 );
const auto max_poc_iter =
std::max_element( m_PrevFramesInfos.cbegin(), m_PrevFramesInfos.cend(), []( const auto &a, const auto &b ) noexcept {
return a.picture_order_count < b.picture_order_count;
} );
m_frame_state_descriptor.l0_reference_list[0] =
static_cast<uint8_t>( std::distance( m_PrevFramesInfos.cbegin(), max_poc_iter ) );
const uint32_t ltrUsedBitmask = max_poc_iter->is_ltr ? ( 1u << max_poc_iter->ltr_index ) : 0u;
return ltrUsedBitmask;
}
const reference_frames_tracker_frame_descriptor *
reference_frames_tracker_hevc::get_frame_descriptor()
{
return (const reference_frames_tracker_frame_descriptor *) &m_frame_state_descriptor;
}
// mark the ltr index in the active LTR bitmap
void
reference_frames_tracker_hevc::MarkLTRIndex( uint32_t index )
{
assert( index < m_MaxLongTermReferences );
m_ActiveLTRBitmap |= ( 1 << index );
}
// return whether the LTR index is in the active LTR bitmap which contains the active LTR indices.
bool
reference_frames_tracker_hevc::IsLTRIndexInLTRBitmap( uint32_t index )
{
assert( index < m_MaxLongTermReferences );
return m_ActiveLTRBitmap & ( 1 << index );
}
// reset gop state to IDR
void
reference_frames_tracker_hevc::ResetGopStateToIDR()
{
m_current_gop_frame_position_index = 0;
m_gop_state.intra_period = m_gopLength;
m_gop_state.ip_period = m_p_picture_period;
m_gop_state.frame_type = PIPE_H2645_ENC_PICTURE_TYPE_IDR;
m_gop_state.picture_order_count = 0;
m_gop_state.temporal_id = 0;
m_gop_state.is_used_as_future_reference = true;
m_gop_state.pic_order_cnt_type = ( m_p_picture_period > 2 ) ? 0u : 2u; // might not be needed
m_gop_state.reference_type = frame_descriptor_reference_type_short_term;
m_gop_state.ltr_index = 0;
}
// returns the frame type for the current frame derived using the current frame position index.
pipe_h2645_enc_picture_type
reference_frames_tracker_hevc::GetNextFrameType()
{
if( m_current_gop_frame_position_index == 0 )
return m_force_idr_on_gop_start ? PIPE_H2645_ENC_PICTURE_TYPE_IDR : PIPE_H2645_ENC_PICTURE_TYPE_I;
else if( m_p_picture_period == 0 )
return PIPE_H2645_ENC_PICTURE_TYPE_I;
else
return ( m_current_gop_frame_position_index % m_p_picture_period == 0 ) ? PIPE_H2645_ENC_PICTURE_TYPE_P :
PIPE_H2645_ENC_PICTURE_TYPE_B;
}
// initializes the gop state for the current frame
void
reference_frames_tracker_hevc::GOPStateBeginFrame( bool forceKey )
{
pipe_h2645_enc_picture_type next_frame_type = GetNextFrameType();
if( forceKey || next_frame_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR )
{
ResetGopStateToIDR();
}
else
{
m_gop_state.picture_order_count++;
m_gop_state.is_used_as_future_reference = true; // Note to future self: Do not use B frames as references for other frames
m_gop_state.frame_type = next_frame_type;
m_gop_state.long_term_reference_frame_info = 0x0000FFFF; // [31...16] ltr bitmap, [15...0] ltr index or 0xFFFF for STR
m_gop_state.reference_type = frame_descriptor_reference_type_short_term;
}
}
// moves the GOP state to the next frame for next frame
void
reference_frames_tracker_hevc::advance_frame()
{
m_current_gop_frame_position_index = ( m_gopLength > 0 ) ? // Wrap around m_gop_length for non-infinite GOP
( ( m_current_gop_frame_position_index + 1 ) % m_gopLength ) :
( m_current_gop_frame_position_index + 1 );
}
//
// Intra Refresh Tracker
//
void
intra_refresh_tracker_row_hevc::reset_ir_state_desc()
{
m_ir_state_desc.base = *( (reference_frames_tracker_frame_descriptor_hevc *) m_ref_pics_tracker->get_frame_descriptor() );
m_ir_state_desc.slices_config = m_non_ir_wave_slices_config;
m_ir_state_desc.current_ir_wave_frame_index = 0;
m_ir_state_desc.intra_refresh_params.mode = INTRA_REFRESH_MODE_NONE;
m_ir_state_desc.intra_refresh_params.need_sequence_header = false;
m_ir_state_desc.intra_refresh_params.offset = 0;
m_ir_state_desc.intra_refresh_params.region_size = 0;
}
intra_refresh_tracker_row_hevc::intra_refresh_tracker_row_hevc( reference_frames_tracker *ref_pic_tracker,
uint32_t ir_wave_duration,
intra_refresh_slices_config non_ir_wave_slices_config,
uint32_t total_frame_macroblocks,
bool continuous_refresh )
: m_ir_wave_duration( ir_wave_duration ),
m_ref_pics_tracker( ref_pic_tracker ),
m_non_ir_wave_slices_config( non_ir_wave_slices_config ),
m_ir_state_desc( {} ),
m_total_frame_macroblocks( total_frame_macroblocks ),
m_continuous_refresh( continuous_refresh )
{
reset_ir_state_desc();
}
intra_refresh_tracker_row_hevc::~intra_refresh_tracker_row_hevc()
{
if( m_ref_pics_tracker )
delete m_ref_pics_tracker;
}
// forward to underlying reference tracker
void
intra_refresh_tracker_row_hevc::release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken )
{
m_ref_pics_tracker->release_reconpic( pAsyncDPBToken );
}
// start intra refresh wave and then forward to underlying reference tracker
HRESULT
intra_refresh_tracker_row_hevc::begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t mark_ltr_index,
bool useLTR,
uint32_t use_ltr_bitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum )
{
HRESULT hr = S_OK;
if( m_ir_state_desc.intra_refresh_params.mode == INTRA_REFRESH_MODE_UNIT_ROWS )
{
if( ( ++m_ir_state_desc.current_ir_wave_frame_index ) < m_ir_wave_duration )
{
m_ir_state_desc.intra_refresh_params.need_sequence_header = false;
m_ir_state_desc.intra_refresh_params.offset += m_ir_state_desc.intra_refresh_params.region_size;
}
else
{
reset_ir_state_desc();
}
}
CHECKHR_GOTO( m_ref_pics_tracker->begin_frame( pAsyncDPBToken,
forceKey,
markLTR,
mark_ltr_index,
useLTR,
use_ltr_bitmap,
layerCountSet,
layerCount,
dirtyRectFrameNumSet,
dirtyRectFrameNum ),
done );
{
// If the underlying GOP tracker signaled an IDR (e.g a new GOP started) let's end any active IR wave
reference_frames_tracker_frame_descriptor_hevc *underlying_frame_desc =
(reference_frames_tracker_frame_descriptor_hevc *) m_ref_pics_tracker->get_frame_descriptor();
if( underlying_frame_desc->gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR )
{
reset_ir_state_desc();
}
else if( // For P, B frames, restart the continuous IR wave if not already active
( ( underlying_frame_desc->gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_P ) ||
( underlying_frame_desc->gop_info->frame_type == PIPE_H2645_ENC_PICTURE_TYPE_B ) ) &&
( m_continuous_refresh && ( m_ir_state_desc.intra_refresh_params.mode == INTRA_REFRESH_MODE_NONE ) ) )
{
start_ir_wave();
}
}
done:
return hr;
}
// forward to underlying reference tracker
void
intra_refresh_tracker_row_hevc::advance_frame()
{
m_ref_pics_tracker->advance_frame();
}
const reference_frames_tracker_frame_descriptor *
intra_refresh_tracker_row_hevc::get_frame_descriptor()
{
m_ir_state_desc.base = *( (reference_frames_tracker_frame_descriptor_hevc *) m_ref_pics_tracker->get_frame_descriptor() );
return (reference_frames_tracker_frame_descriptor *) &m_ir_state_desc.base;
}
// start intra refresh tracker wave for the current frame
bool
intra_refresh_tracker_row_hevc::start_ir_wave()
{
auto frame_type = ( (reference_frames_tracker_frame_descriptor_hevc *) get_frame_descriptor() )->gop_info->frame_type;
if( ( frame_type != PIPE_H2645_ENC_PICTURE_TYPE_B ) && ( frame_type != PIPE_H2645_ENC_PICTURE_TYPE_P ) )
{
debug_printf( "[intra_refresh_tracker_row_h264x::start_ir_wave] Error: IR wave can be only started on P/B frames.\n" );
assert( false );
return false;
}
if( m_ir_state_desc.intra_refresh_params.mode == INTRA_REFRESH_MODE_UNIT_ROWS )
{
debug_printf( "[intra_refresh_tracker_row_h264x::start_ir_wave] - Error: Another IR wave is currently active.\n" );
assert( false );
return false;
}
// Start IR wave with m_ir_wave_duration slices per frame (as per DX12 intra-refresh spec)
m_ir_state_desc.intra_refresh_params.mode = INTRA_REFRESH_MODE_UNIT_ROWS;
m_ir_state_desc.intra_refresh_params.need_sequence_header = true;
m_ir_state_desc.intra_refresh_params.offset = 0;
m_ir_state_desc.intra_refresh_params.region_size = m_total_frame_macroblocks / m_ir_wave_duration;
m_ir_state_desc.slices_config.slice_mode = PIPE_VIDEO_SLICE_MODE_BLOCKS;
m_ir_state_desc.slices_config.num_slice_descriptors = m_ir_wave_duration;
uint32_t slice_starting_mb = 0;
memset( m_ir_state_desc.slices_config.slices_descriptors, 0, sizeof( m_ir_state_desc.slices_config.slices_descriptors ) );
for( uint32_t i = 0; i < m_ir_state_desc.slices_config.num_slice_descriptors; i++ )
{
m_ir_state_desc.slices_config.slices_descriptors[i].macroblock_address = slice_starting_mb;
m_ir_state_desc.slices_config.slices_descriptors[i].num_macroblocks = m_ir_state_desc.intra_refresh_params.region_size;
slice_starting_mb += m_ir_state_desc.intra_refresh_params.region_size;
}
return true;
}
#endif
@@ -0,0 +1,205 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#if MFT_CODEC_H265ENC
#include <deque>
#include <memory>
#include <queue>
#include "dpb_buffer_manager.h"
#include "reference_frames_tracker.h"
typedef struct frame_descriptor_hevc
{
uint32_t intra_period;
uint32_t ip_period;
pipe_h2645_enc_picture_type frame_type;
bool is_used_as_future_reference;
uint32_t picture_order_count; // corresponds to PicOrderCntVal
frame_descriptor_reference_type reference_type;
uint32_t ltr_index;
uint32_t pic_order_cnt_type;
uint8_t temporal_id;
uint8_t log2_max_pic_order_cnt_lsb_minus4;
uint32_t long_term_reference_frame_info; // corresponds to MFT attribute MFSampleExtension_LongTermReferenceFrameInfo
} frame_descriptor_hevc;
typedef struct reference_frames_tracker_frame_descriptor_hevc
{
reference_frames_tracker_frame_descriptor base;
const struct frame_descriptor_hevc *gop_info;
std::vector<uint8_t> l0_reference_list;
std::vector<struct pipe_h264_ref_list_mod_entry> ref_list0_mod_operations;
std::vector<pipe_h264_enc_dpb_entry> dpb_snapshot; // for HEVC use the same, ignore frame_num/idx
std::vector<uint32_t> dirty_rect_frame_num; // index corresponds to dbp_snapshot
} reference_frames_tracker_frame_descriptor_hevc;
class reference_frames_tracker_hevc : public reference_frames_tracker
{
public:
typedef struct PrevFrameInfo
{
uint32_t picture_order_count;
bool is_ltr;
uint32_t ltr_index;
uint8_t temporal_id;
uint32_t dirty_rect_frame_num;
struct pipe_video_buffer *buffer;
struct pipe_video_buffer *downscaled_buffer;
} PrevFrameInfo;
// used to sort PrevFrameInfo array
typedef struct RefSortList
{
uint8_t pos; // index into location in the PrevFrameInfo array
// below are from PrevFrameInfo
uint32_t picture_order_count;
bool is_ltr;
uint32_t ltr_index;
uint8_t temporal_id;
} RefSortList;
// Declare reference_frames_tracker interface methods
HRESULT begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t markLTRIndex,
bool useLTR,
uint32_t useLTRBitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum );
void advance_frame(); // GOPTracker
const reference_frames_tracker_frame_descriptor *get_frame_descriptor();
void release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken );
// Declare other methods
reference_frames_tracker_hevc( void *logId,
struct pipe_video_codec *codec,
uint32_t textureWidth,
uint32_t textureHeight,
uint32_t gopLength,
uint32_t uiBPictureCount,
bool bLayerCountSet,
uint32_t layerCount,
bool bLowLatency,
uint32_t MaxL0References,
uint32_t MaxDPBCapacity,
uint32_t MaxLongTermReferences,
std::unique_ptr<dpb_buffer_manager> upTwoPassDPBManager,
HRESULT &hr );
private:
uint32_t PrepareFrameRefLists();
void MarkLTRIndex( uint32_t index );
bool IsLTRIndexInLTRBitmap( uint32_t index );
reference_frames_tracker_frame_descriptor_hevc m_frame_state_descriptor = {};
uint32_t m_MaxL0References = 0;
uint32_t m_MaxDPBCapacity = 0;
uint32_t m_MaxLongTermReferences = 0;
uint32_t m_ActiveLTRBitmap = 0;
std::deque<struct PrevFrameInfo> m_PrevFramesInfos;
const void *m_logId = {};
struct pipe_video_codec *m_codec;
dpb_buffer_manager m_DPBManager;
std::unique_ptr<dpb_buffer_manager> m_upTwoPassDPBManager;
bool m_pendingMarkLTR = false;
uint32_t m_pendingMarkLTRIndex = 0;
// GOP Tracker
void GOPStateBeginFrame( bool forceKey );
pipe_h2645_enc_picture_type GetNextFrameType();
void ResetGopStateToIDR();
uint32_t m_gopLength = 0;
uint32_t m_p_picture_period = 0;
bool m_force_idr_on_gop_start = true;
uint32_t m_current_gop_frame_position_index = 0;
frame_descriptor_hevc m_gop_state;
// GOP Tracker
};
typedef struct intra_refresh_tracker_frame_descriptor_hevc
{
struct reference_frames_tracker_frame_descriptor_hevc base;
struct intra_refresh_slices_config slices_config;
uint32_t current_ir_wave_frame_index;
struct pipe_enc_intra_refresh intra_refresh_params;
} intra_refresh_tracker_frame_descriptor_hevc;
class intra_refresh_tracker_row_hevc : public reference_frames_tracker, public intra_refresh_tracker
{
// reference_frames_tracker
public:
HRESULT begin_frame( reference_frames_tracker_dpb_async_token *pAsyncDPBToken,
bool forceKey,
bool markLTR,
uint32_t mark_ltr_index,
bool useLTR,
uint32_t use_ltr_bitmap,
bool layerCountSet,
uint32_t layerCount,
bool dirtyRectFrameNumSet,
uint32_t dirtyRectFrameNum );
void advance_frame();
const reference_frames_tracker_frame_descriptor *get_frame_descriptor();
void release_reconpic( reference_frames_tracker_dpb_async_token *pAsyncDPBToken );
public:
// intra_refresh_tracker
bool start_ir_wave();
// intra_refresh_tracker_row_h264x
intra_refresh_tracker_row_hevc( reference_frames_tracker *ref_pic_tracker,
uint32_t ir_wave_duration,
intra_refresh_slices_config non_ir_wave_slices_config,
uint32_t total_frame_macroblocks,
bool continuous_refresh = true );
~intra_refresh_tracker_row_hevc();
private:
bool m_continuous_refresh = true;
const uint32_t m_ir_wave_duration = 0u;
reference_frames_tracker *m_ref_pics_tracker = {};
const intra_refresh_slices_config m_non_ir_wave_slices_config = {};
intra_refresh_tracker_frame_descriptor_hevc m_ir_state_desc = {};
uint32_t m_total_frame_macroblocks = 0;
void reset_ir_state_desc();
};
#endif
@@ -0,0 +1,107 @@
#ifndef __STATICASYNCCALLBACK__
#define __STATICASYNCCALLBACK__
////////////////////////////////////////////////////////
//
#define STATICASYNCCALLBACK( Callback, Parent ) \
class Callback##AsyncCallback; \
friend class Callback##AsyncCallback; \
class Callback##AsyncCallback : public IMFAsyncCallback \
{ \
public: \
STDMETHOD_( ULONG, AddRef )() \
{ \
Parent *pThis = ( (Parent *) ( (BYTE *) this - offsetof( Parent, m_x##Callback ) ) ); \
return pThis->AddRef(); \
} \
STDMETHOD_( ULONG, Release )() \
{ \
Parent *pThis = ( (Parent *) ( (BYTE *) this - offsetof( Parent, m_x##Callback ) ) ); \
return pThis->Release(); \
} \
STDMETHOD( QueryInterface )( REFIID riid, __RPC__deref_out _Result_nullonfailure_ void **ppvObject ) \
{ \
return E_NOINTERFACE; \
} \
STDMETHOD( GetParameters )( __RPC__out DWORD * pdwFlags, __RPC__out DWORD *pdwQueue ) \
{ \
return S_OK; \
} \
STDMETHOD( Invoke )( __RPC__in_opt IMFAsyncResult * pResult ) \
{ \
Callback( pResult ); \
return S_OK; \
} \
} m_x##Callback;
////////////////////////////////////////////////////////
//
//
// We need to support QI interface so that DCOM is happy when it tries to marshal the interface pointer
//
#define METHODASYNCCALLBACKEX( Callback, Parent, Flag, Queue ) \
class Callback##AsyncCallback; \
friend class Callback##AsyncCallback; \
class Callback##AsyncCallback : public IMFAsyncCallback \
{ \
public: \
STDMETHOD_( ULONG, AddRef )() \
{ \
return GetParent()->AddRef(); \
} \
STDMETHOD_( ULONG, Release )() \
{ \
return GetParent()->Release(); \
} \
STDMETHOD( QueryInterface )( REFIID riid, __RPC__deref_out _Result_nullonfailure_ void **ppvObject ) \
{ \
if( riid == IID_IMFAsyncCallback || riid == IID_IUnknown ) \
{ \
( *ppvObject ) = this; \
AddRef(); \
return S_OK; \
} \
( *ppvObject ) = NULL; \
return E_NOINTERFACE; \
} \
STDMETHOD( GetParameters )( __RPC__out DWORD * pdwFlags, __RPC__out DWORD *pdwQueue ) \
{ \
*pdwFlags = Flag; \
*pdwQueue = Queue; \
return S_OK; \
} \
STDMETHOD( Invoke )( __RPC__in_opt IMFAsyncResult * pResult ) \
{ \
GetParent()->Callback( pResult ); \
return S_OK; \
} \
\
protected: \
Parent *GetParent() \
{ \
return ( (Parent *) ( (BYTE *) this - offsetof( Parent, m_x##Callback ) ) ); \
} \
} m_x##Callback;
////////////////////////////////////////////////////////
//
#define METHODFASTCALLBACK( Callback, Parent ) \
METHODASYNCCALLBACKEX( Callback, Parent, MFASYNC_FAST_IO_PROCESSING_CALLBACK, MFASYNC_CALLBACK_QUEUE_STANDARD )
#define METHODASYNCCALLBACK( Callback, Parent ) METHODASYNCCALLBACKEX( Callback, Parent, 0, MFASYNC_CALLBACK_QUEUE_STANDARD )
#define METHODASYNCRTCALLBACK( Callback, Parent ) METHODASYNCCALLBACKEX( Callback, Parent, 0, MFASYNC_CALLBACK_QUEUE_RT )
#define METHODASYNCIOCALLBACK( Callback, Parent ) \
METHODASYNCCALLBACKEX( Callback, Parent, MFASYNC_FAST_IO_PROCESSING_CALLBACK, MFASYNC_CALLBACK_QUEUE_IO )
////////////////////////////////////////////////////////
//
#define METHODASYNCCALLBACKEX2( Callback, Parent, GetQueue ) METHODASYNCCALLBACKEX( Callback, Parent, 0, GetParent()->GetQueue() )
#define METHODASYNCCALLBACKEX3( Callback, Parent, GetFlags, GetQueue ) \
METHODASYNCCALLBACKEX( Callback, Parent, GetParent()->GetFlags(), GetParent()->GetQueue() )
#endif
@@ -0,0 +1,405 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <mfapi.h>
#include <mfd3d12.h>
#include <mfidl.h>
#include <wrl/client.h>
#include "wpptrace.h"
#include "macros.h"
#include "stats_buffer_manager.h"
#include "stats_buffer_manager.tmh"
using namespace Microsoft::WRL;
HRESULT __stdcall stats_buffer_manager::QueryInterface( const IID &riid, void **ppvObject )
{
if( riid == IID_IUnknown )
{
// If the requested IID is supported, return 'this' pointer
*ppvObject = static_cast<IUnknown *>( this );
// Must call AddRef because we are returning a valid interface pointer
AddRef();
return S_OK;
}
// Interface not supported
*ppvObject = NULL;
return E_NOINTERFACE;
}
ULONG __stdcall stats_buffer_manager::AddRef()
{
return InterlockedIncrement( &m_refCount );
}
ULONG __stdcall stats_buffer_manager::Release()
{
ULONG ulCount = InterlockedDecrement( &m_refCount );
if( ulCount == 0 )
{
delete this;
}
return ulCount;
}
// helper to convert known pipe_format to DXGI_FORMAT.
static DXGI_FORMAT
PipeFormatToD3D12Format( enum pipe_format pipeFormat )
{
switch( pipeFormat )
{
case PIPE_FORMAT_R32_UINT:
return DXGI_FORMAT_R32_UINT;
case PIPE_FORMAT_R8_SINT:
return DXGI_FORMAT_R8_SINT;
case PIPE_FORMAT_Y8_U8V8_420_UNORM:
return DXGI_FORMAT_NV12;
default:
assert( false );
return DXGI_FORMAT_UNKNOWN;
}
}
HRESULT
stats_buffer_manager::CreateSample( stats_buffer_manager_pool_entry &entry )
{
HRESULT hr = S_OK;
D3D12_RESOURCE_DESC desc;
desc.Format = PipeFormatToD3D12Format( m_template.format );
// DXGI_FORMAT_R32_UINT;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = m_template.width0;
desc.Height = m_template.height0;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
D3D12_HEAP_PROPERTIES heap_pris = m_spD3D12Device->GetCustomHeapProperties( 0, D3D12_HEAP_TYPE_DEFAULT );
D3D12_HEAP_FLAGS heap_flags = D3D12_HEAP_FLAG_NONE;
hr = m_spD3D12Device->CreateCommittedResource( &heap_pris,
heap_flags,
&desc,
D3D12_RESOURCE_STATE_COMMON,
nullptr,
IID_PPV_ARGS( &entry.d3d12_resource ) );
if( FAILED( hr ) )
{
MFE_ERROR( "[dx12 hmft 0x%p] CreateCommittedResource failed hr=0x%08x", m_logId, hr );
}
return hr;
}
HRESULT
stats_buffer_manager::Create( void *logId,
ID3D12Device *pD3D12Device,
REFGUID guidExtension,
uint32_t width,
uint16_t height,
enum pipe_format buffer_format,
unsigned initial_pool_size,
unsigned max_pool_size,
stats_buffer_manager **ppInstance )
{
if( !ppInstance )
return E_INVALIDARG;
*ppInstance = nullptr;
assert( initial_pool_size <= max_pool_size );
HRESULT hr;
auto pInstance = new ( std::nothrow )
stats_buffer_manager( logId, pD3D12Device, guidExtension, width, height, buffer_format, initial_pool_size, max_pool_size, hr );
if( !pInstance )
return E_OUTOFMEMORY;
if( FAILED( hr ) )
{
delete pInstance;
return hr;
}
pInstance->m_refCount = 1;
*ppInstance = pInstance;
return S_OK;
}
// Helper to import d3d12 resource to pipe_resource*
// Returns NULL on failure.
struct pipe_resource *
AllocatePipeResourceFromD3D12Resource( ID3D12Resource *pD3D12Resource,
struct pipe_screen *pScreen,
const struct pipe_resource *templ )
{
// Build winsys_handle
struct winsys_handle whandle = {};
whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
whandle.com_obj = pD3D12Resource;
// templ->format contains the desired pipe_format
whandle.format = templ->format;
// Call resource_from_handle with the same templ for resource_create.
struct pipe_resource *pres = pScreen->resource_from_handle( pScreen, templ, &whandle, PIPE_USAGE_DEFAULT );
if( !pres )
{
// Release the detached COM object if resource_from_handle fails
if( whandle.com_obj )
{
static_cast<ID3D12Resource *>( whandle.com_obj )->Release();
}
return nullptr;
}
pD3D12Resource->AddRef(); // Hold a reference for the pipe_resource, so we do:
// pipe_resource_reference( &pipe_resource, nullptr )
// in context destructor, or we might leak some pipe_resources memory.
return pres;
}
// retrieve a buffer from the pool
struct pipe_resource *
stats_buffer_manager::get_new_tracked_buffer( struct vl_screen *pVlScreen )
{
auto lock = std::lock_guard<std::mutex>( m_lock );
for( auto &entry : m_pool )
{
if( !entry.used )
{
if( !entry.d3d12_resource )
{
HRESULT hr = stats_buffer_manager::CreateSample( entry );
if( FAILED( hr ) )
{
MFE_ERROR( "[dx12 hmft 0x%p] CreateSample failed", m_logId );
assert( false ); // Failed to create a new buffer
return NULL;
}
}
entry.used = true;
return AllocatePipeResourceFromD3D12Resource( entry.d3d12_resource.Get(), pVlScreen->pscreen, &m_template );
}
}
MFE_ERROR( "[dx12 hmft 0x%p] failed to find a free buffer", m_logId );
assert( false ); // Did not find an unused buffer
return NULL;
}
// release a buffer back to the pool
void
stats_buffer_manager::release_tracked_buffer( void *target )
{
auto lock = std::lock_guard<std::mutex>( m_lock );
bool found = false;
for( auto &entry : m_pool )
{
if( entry.d3d12_resource.Get() == target )
{
entry.used = false;
found = true;
break;
}
}
if( !found )
{
MFE_ERROR( "[dx12 hmft 0x%p] returned buffer was not found in the pool", m_logId );
}
}
stats_buffer_manager::stats_buffer_manager( void *logId,
ID3D12Device *pD3D12Device,
REFGUID resourceGUID,
uint32_t width,
uint16_t height,
enum pipe_format buffer_format,
unsigned initial_pool_size,
unsigned max_pool_size,
HRESULT &hr )
: m_logId( logId ), m_spD3D12Device( pD3D12Device ), m_resourceGUID( resourceGUID ), m_pool( max_pool_size )
{
hr = S_OK;
m_template.target = PIPE_TEXTURE_2D;
m_template.usage = PIPE_USAGE_DEFAULT;
m_template.depth0 = 1;
m_template.array_size = 1;
m_template.width0 = width;
m_template.height0 = height;
m_template.format = buffer_format;
unsigned buffer_count = 0;
for( auto &entry : m_pool )
{
if( buffer_count < initial_pool_size )
{
HRESULT hr = stats_buffer_manager::CreateSample( entry );
if( FAILED( hr ) )
{
MFE_ERROR( "[dx12 hmft 0x%p] CreateSample failed", m_logId );
assert( false );
break;
}
buffer_count++;
}
}
}
stats_buffer_manager::~stats_buffer_manager()
{ }
// callback from IMFTrackSample (i.e. application)
IFACEMETHODIMP
stats_buffer_manager::OnSampleAvailable( IMFAsyncResult *pResult )
{
HRESULT hr = S_OK;
ComPtr<IUnknown> spUnk;
ComPtr<IMFSample> spSample;
ComPtr<IMFMediaBuffer> spMediaBuffer;
ComPtr<IMFDXGIBuffer> spDXGIBuffer;
ComPtr<IMFD3D12SynchronizationObjectCommands> spOutputSync;
ComPtr<IMFD3D12SynchronizationObject> spSyncObj;
ComPtr<ID3D12Resource> spDXGISurface;
HANDLE hFree = NULL;
HMFT_ETW_EVENT_START( "OnSampleAvailable", this );
CHECKHR_GOTO( pResult->GetState( &spUnk ), done );
CHECKHR_GOTO( spUnk.As( &spSample ), done );
CHECKHR_GOTO( spSample->GetBufferByIndex( 0, &spMediaBuffer ), done );
CHECKHR_GOTO( spMediaBuffer.As( &spDXGIBuffer ), done );
CHECKHR_GOTO( spDXGIBuffer->GetResource( IID_PPV_ARGS( &spDXGISurface ) ), done );
CHECKHR_GOTO( spDXGIBuffer->GetUnknown( MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS( &spOutputSync ) ), done );
CHECKHR_GOTO( spOutputSync.As( &spSyncObj ), done );
hFree = CreateEvent( nullptr, FALSE, FALSE, nullptr );
if( !hFree )
{
CHECKHR_GOTO( HRESULT_FROM_WIN32( GetLastError() ), done );
}
CHECKHR_GOTO( spSyncObj->SignalEventOnFinalResourceRelease( hFree ), done );
(void) WaitForSingleObject( hFree, INFINITE );
spOutputSync.Reset();
release_tracked_buffer( (void *) spDXGISurface.Get() );
done:
if( hFree )
{
CloseHandle( hFree );
}
HMFT_ETW_EVENT_STOP( "OnSampleAvailable", this );
return hr;
}
// Converts a Gallium pipe_resource into a D3D12 resource and wraps it as an IMFMediaBuffer,
// then attaches it as a sample extension on an IMFSample using the specified GUID.
HRESULT
stats_buffer_manager::AttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
struct pipe_resource *pPipeRes,
ID3D12CommandQueue *pSyncObjectQueue,
IMFSample *pSample )
{
HRESULT hr = S_OK;
if( !pPipeRes || !pPipeContext || !pSample || !pSyncObjectQueue )
{
return E_INVALIDARG;
}
struct winsys_handle whandle = {};
whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
if( !pPipeContext->screen->resource_get_handle( pPipeContext->screen, pPipeContext, pPipeRes, &whandle, 0u ) )
{
return E_FAIL;
}
if( !whandle.com_obj )
{
return E_POINTER;
}
ComPtr<IMFTrackedSample> spTrackedSample;
hr = MFCreateTrackedSample( &spTrackedSample );
if( FAILED( hr ) )
{
return hr;
}
hr = spTrackedSample->SetAllocator( &m_xOnSampleAvailable, spTrackedSample.Get() );
if( FAILED( hr ) )
{
return hr;
}
ComPtr<IMFSample> spSample;
hr = spTrackedSample.As( &spSample );
if( FAILED( hr ) )
{
return hr;
}
ID3D12Resource *pD3D12Res = static_cast<ID3D12Resource *>( whandle.com_obj );
ComPtr<IMFMediaBuffer> spMediaBuffer;
hr = MFCreateDXGISurfaceBuffer( __uuidof( ID3D12Resource ), pD3D12Res, 0, FALSE, &spMediaBuffer );
if( FAILED( hr ) )
{
return hr;
}
// Tell MF that this buffer is ready to use.
ComPtr<IMFD3D12SynchronizationObjectCommands> spOutputSync; // needed to call Lock() for IMFMediaBuffer.
ComPtr<IMFDXGIBuffer> spDxgiBuffer;
hr = spMediaBuffer->QueryInterface( IID_PPV_ARGS( &spDxgiBuffer ) );
if( SUCCEEDED( hr ) )
{
hr = spDxgiBuffer->GetUnknown( MF_D3D12_SYNCHRONIZATION_OBJECT, IID_PPV_ARGS( &spOutputSync ) );
if( SUCCEEDED( hr ) )
{
hr = spOutputSync->EnqueueResourceReady( pSyncObjectQueue );
spSample->AddBuffer( spMediaBuffer.Get() );
if( FAILED( hr ) )
return hr;
}
else
{
return hr;
}
}
else
{
return hr;
}
return pSample->SetUnknown( m_resourceGUID, spMediaBuffer.Get() );
}
@@ -0,0 +1,109 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <vector>
#include "gallium/include/frontend/sw_winsys.h"
#include "gallium/winsys/sw/null/null_sw_winsys.h"
#include "util/u_video.h"
#include "vl/vl_winsys.h"
#include <unknwn.h>
#include <windows.h>
#include <d3d12.h>
#include <mfobjects.h>
#include <mutex>
#include "pipe_headers.h"
#include "staticasynccallback.h"
using namespace Microsoft::WRL;
using Microsoft::WRL::ComPtr;
using namespace std;
class stats_buffer_manager : public IUnknown
{
public:
// retrieve a new tracked buffer from the pool
struct pipe_resource *get_new_tracked_buffer( struct vl_screen *pVlScreen );
// release a tracked buffer back to the pool
void release_tracked_buffer( void *target );
HRESULT __stdcall QueryInterface( const IID &riid, void **ppvObject ) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
HRESULT
AttachPipeResourceAsSampleExtension( struct pipe_context *pPipeContext,
struct pipe_resource *pPipeRes,
ID3D12CommandQueue *pSyncObjectQueue,
IMFSample *pSample );
static HRESULT Create( void *logId,
ID3D12Device *pD3D12Device,
REFGUID guidExtension,
uint32_t width,
uint16_t height,
enum pipe_format buffer_format,
unsigned initial_pool_size,
unsigned max_pool_size,
stats_buffer_manager **ppInstance );
private:
stats_buffer_manager( void *logId,
ID3D12Device *pD3D12Device,
REFGUID guidExtension,
uint32_t width,
uint16_t height,
enum pipe_format buffer_format,
unsigned initial_pool_size,
unsigned max_pool_size,
HRESULT &hr );
~stats_buffer_manager();
STDMETHOD( OnSampleAvailable )( __in IMFAsyncResult *pAsyncResult );
METHODASYNCCALLBACKEX( OnSampleAvailable, stats_buffer_manager, 0, MFASYNC_CALLBACK_QUEUE_MULTITHREADED );
const void *m_logId = {};
std::mutex m_lock;
GUID m_resourceGUID {};
ULONG m_refCount = 0;
ComPtr<ID3D12Device> m_spD3D12Device = nullptr;
struct pipe_resource m_template = {};
struct stats_buffer_manager_pool_entry
{
ComPtr<ID3D12Resource> d3d12_resource {};
bool used {};
};
HRESULT CreateSample( stats_buffer_manager_pool_entry &entry );
std::vector<struct stats_buffer_manager_pool_entry> m_pool;
};
@@ -0,0 +1,80 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <strmif.h>
#include "../hmft_entrypoints.h"
#include <gtest/gtest.h>
#include "hmft_test_helpers.h"
TEST( MediaFoundationEntrypoint, VerifyBasicCodecAPI )
{
HRESULT hr = S_OK;
ComPtr<CDX12EncHMFT> spMFT {};
ComPtr<IMFDXGIDeviceManager> spDXGIMan {};
ComPtr<IMFAttributes> spAttrs {};
ComPtr<ICodecAPI> spCodecAPI {};
CHECKHR_GOTO( CDX12EncHMFT::CreateInstance( &spMFT ), done );
CHECKHR_GOTO( CreateD3D12Manager( &spDXGIMan, 0 ), done );
CHECKHR_GOTO( spMFT->GetAttributes( &spAttrs ), done );
UINT32 bAsync;
if( S_OK == spAttrs->GetUINT32( MF_TRANSFORM_ASYNC, &bAsync ) && bAsync )
{
CHECKHR_GOTO(spAttrs->SetUINT32( MF_TRANSFORM_ASYNC_UNLOCK, TRUE ), done );
}
CHECKHR_GOTO(spMFT->ProcessMessage( MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR) spDXGIMan.Get() ), done);
CHECKHR_GOTO(spMFT.As( &spCodecAPI ), done);
{
VARIANT vValue, vGetValue;
vValue.vt = VT_UI4;
vValue.ulVal = 8;
CHECKHR_GOTO( spCodecAPI->SetValue( &CODECAPI_AVEncCommonQualityVsSpeed, &vValue ), done );
CHECKHR_GOTO( spCodecAPI->GetValue( &CODECAPI_AVEncCommonQualityVsSpeed, &vGetValue ), done );
ASSERT_EQ( vValue.ulVal, vGetValue.ulVal );
}
{
VARIANT *pValues;
ULONG ulValuesCount;
CHECKHR_GOTO( spCodecAPI->GetParameterValues( &CODECAPI_AVEncVideoLTRBufferControl, &pValues, &ulValuesCount ), done );
}
{
VARIANT vMin;
VARIANT vMax;
VARIANT vDelta;
hr = spCodecAPI->IsSupported( &CODECAPI_AVEncSliceControlMode );
if( SUCCEEDED( hr ) )
{
CHECKHR_GOTO( spCodecAPI->GetParameterRange( &CODECAPI_AVEncSliceControlMode, &vMin, &vMax, &vDelta ), done );
ASSERT_TRUE( vMin.vt == VT_UI4 && vMax.vt == VT_UI4 && vDelta.vt == VT_UI4 );
ASSERT_TRUE( vMin.ulVal <= 2u && vMax.ulVal <= 2u );
ASSERT_TRUE( vMin.ulVal <= vMax.ulVal );
ASSERT_TRUE( vDelta.ulVal >= 1u && vDelta.ulVal <= 2u );
}
}
done:
ASSERT_HRESULT_SUCCEEDED( hr );
}
@@ -0,0 +1,225 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <strmif.h>
#include "../hmft_entrypoints.h"
#include <gtest/gtest.h>
#include "hmft_test_helpers.h"
TEST( MediaFoundationEntrypoint, VerifySimpleEncodeSoftwareSample )
{
HRESULT hr = S_OK;
MFStartupHelper mfStartupHelper( hr );
ASSERT_HRESULT_SUCCEEDED( hr );
CFrameGenerator frameGenerator;
ComPtr<CDX12EncHMFT> spMFT {};
ComPtr<IMFDXGIDeviceManager> spDXGIMan {};
ComPtr<IMFAttributes> spAttrs {};
ComPtr<ICodecAPI> spCodecAPI {};
ComPtr<IMFMediaEvent> spEvent {};
ComPtr<IMFMediaEventGenerator> spEventGenerator {};
uint32_t uiNeedInputCount = 0;
uint32_t uiProcessInputCount = 0;
uint32_t uiProcessOutputCount = 0;
uint32_t uiSampleCount = 0;
bool bIsMFTAllocator = true;
bool bEndOfStream = false;
const uint32_t frameRateDiv = frameGenerator.m_uiDiv;
const uint32_t frameRateNum = frameGenerator.m_uiNum;
const uint32_t width = frameGenerator.m_uiWidth;
const uint32_t height = frameGenerator.m_uiHeight;
const uint32_t bitRate = frameGenerator.m_uiBitRate;
ComPtr<IMFSample> spInSample;
ComPtr<IMFSample> spOutSample;
ComPtr<IMFMediaBuffer> spOutBuffer;
ComPtr<IMFMediaType> spInType = CreateVideoMT( width, height, FOURCC_NV12, FALSE, frameRateNum, frameRateDiv );
#if MFT_CODEC_H264ENC
ComPtr<IMFMediaType> spOutType = CreateVideoMT( width, height, FOURCC_H264, FALSE, frameRateNum, frameRateDiv, bitRate * 1024 );
#elif MFT_CODEC_H265ENC
ComPtr<IMFMediaType> spOutType = CreateVideoMT( width, height, FOURCC_HEVC, FALSE, frameRateNum, frameRateDiv, bitRate * 1024 );
#elif MFT_CODEC_AV1ENC
// NO AV1 doesn't work yet...
assert( false );
ComPtr<IMFMediaType> spOutType = CreateVideoMT( width, height, FOURCC_AV01, FALSE, frameRateNum, frameRateDiv, bitRate * 1024 );
#else
#error MFT_CODEC_xxx must be defined
#endif
GUID m_guidOutputVideoSubtype( MFVideoFormat_IYUV );
CHECKHR_GOTO( CDX12EncHMFT::CreateInstance( &spMFT ), done );
CHECKHR_GOTO( CreateD3D12Manager( &spDXGIMan, 0 ), done );
CHECKHR_GOTO( spMFT->GetAttributes( &spAttrs ), done );
UINT32 bAsync;
if( S_OK == spAttrs->GetUINT32( MF_TRANSFORM_ASYNC, &bAsync ) && bAsync )
{
CHECKHR_GOTO( spAttrs->SetUINT32( MF_TRANSFORM_ASYNC_UNLOCK, TRUE ), done );
}
CHECKHR_GOTO( spMFT->ProcessMessage( MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR) spDXGIMan.Get() ), done );
CHECKHR_GOTO( spMFT.As( &spCodecAPI ), done );
{
VARIANT *pValues;
ULONG ulValuesCount;
CHECKHR_GOTO( spCodecAPI->GetParameterValues( &CODECAPI_AVEncVideoLTRBufferControl, &pValues, &ulValuesCount ), done );
}
CHECKHR_GOTO( spMFT->SetOutputType( 0, spOutType.Get(), 0 ), done );
CHECKHR_GOTO( spMFT->SetInputType( 0, spInType.Get(), 0 ), done );
CHECKHR_GOTO( MFCreateSample( &spOutSample ), done );
ASSERT_HRESULT_SUCCEEDED( spMFT->QueryInterface( IID_IMFMediaEventGenerator, &spEventGenerator ) );
ASSERT_HRESULT_SUCCEEDED( spMFT->ProcessMessage( MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0 ) );
ASSERT_HRESULT_SUCCEEDED( spMFT->ProcessMessage( MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0 ) );
for( ;; )
{
MediaEventType eventType = 0;
DWORD status;
MFT_OUTPUT_DATA_BUFFER OutputDataBuf = { 0 };
OutputDataBuf.pSample = nullptr; // spOutSample.Get();
if( bEndOfStream )
{
if( uiProcessInputCount == uiProcessOutputCount )
{
break;
}
CHECKHR_GOTO( spEventGenerator->GetEvent( 0, &spEvent ), done );
CHECKHR_GOTO( spEvent->GetType( &eventType ), done );
if( eventType != METransformHaveOutput && eventType != METransformDrainComplete )
{
// Only respond to METransformHaveOutput or METransformDrainComplete events after source is at EOS
continue;
}
}
else if( uiNeedInputCount > uiProcessInputCount && uiProcessInputCount == uiProcessOutputCount )
{
// We already counted this so decrement to avoid counting twice
uiNeedInputCount--;
// The MFT has requested more samples than we have given so try to feed a sample
eventType = METransformNeedInput;
}
else
{
CHECKHR_GOTO( spEventGenerator->GetEvent( 0, &spEvent ), done );
CHECKHR_GOTO( spEvent->GetType( &eventType ), done );
}
if( eventType == METransformNeedInput )
{
uiNeedInputCount++;
frameGenerator.GenerateSoftwareFrame( &spInSample, &bEndOfStream );
if( !bEndOfStream )
{
CHECKHR_GOTO( spMFT->ProcessInput( 0, spInSample.Get(), 0 ), done );
uiProcessInputCount++;
}
else
{
CHECKHR_GOTO( spMFT->ProcessMessage( MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0 ), done );
CHECKHR_GOTO( spMFT->ProcessMessage( MFT_MESSAGE_COMMAND_DRAIN, 0 ), done );
}
}
else if( eventType == METransformHaveOutput )
{
if( bIsMFTAllocator )
{
OutputDataBuf.pSample = NULL;
}
status = 0;
hr = spMFT->ProcessOutput( 0, 1, &OutputDataBuf, &status );
if( SUCCEEDED( hr ) )
{
uiProcessOutputCount++;
uiSampleCount++;
if( OutputDataBuf.pSample != NULL )
{
CHECKHR_GOTO( OutputDataBuf.pSample->GetBufferByIndex( 0, &spOutBuffer ), done );
DWORD dwLen;
BYTE *pBuf;
CHECKHR_GOTO( spOutBuffer->Lock( &pBuf, NULL, &dwLen ), done );
printf( "Received %d\n", dwLen );
// #define DUMP
#if defined( DUMP )
{
#if MFT_CODEC_H264ENC
FILE *fp = fopen( "d:\\test\\output.h264", "ab" );
#elif MFT_CODEC_H265ENC
FILE *fp = fopen( "d:\\test\\output.h265", "ab" );
#elif MFT_CODEC_AV1ENC
FILE *fp = fopen( "d:\\test\\output.av1", "ab" );
#endif
fwrite( pBuf, 1, dwLen, fp );
fclose( fp );
}
#endif
CHECKHR_GOTO( spOutBuffer->Unlock(), done );
spOutBuffer.Reset();
OutputDataBuf.pSample->Release();
}
else
{
CHECKHR_GOTO( E_FAIL, done );
}
}
else if( MF_E_TRANSFORM_STREAM_CHANGE == hr )
{
ComPtr<IMFMediaType> spNewOutputType;
CHECKHR_GOTO( spMFT->GetOutputAvailableType( 0, 0, &spNewOutputType ), done );
CHECKHR_GOTO( spMFT->SetOutputType( 0, spNewOutputType.Get(), 0 ), done );
}
else
{
CHECKHR_GOTO( hr, done );
}
}
else if( eventType == METransformDrainComplete )
{
CHECKHR_GOTO( spMFT->ProcessMessage( MFT_MESSAGE_COMMAND_FLUSH, 0 ), done );
break;
}
else
{
CHECKHR_GOTO( E_FAIL, done ); // unexpected event type.
}
}
CHECKHR_GOTO( spMFT->ProcessMessage( MFT_MESSAGE_SET_D3D_MANAGER, (ULONG_PTR) NULL ), done );
done:
ASSERT_HRESULT_SUCCEEDED( hr );
}
@@ -0,0 +1,297 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <strmif.h>
#include "../hmft_entrypoints.h"
#include <gtest/gtest.h>
#include "hmft_test_helpers.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
const char *
TryFindD3D12CoreNextToSelf( char *path, DWORD path_arr_size )
{
UINT32 path_size = GetModuleFileNameA( (HINSTANCE) &__ImageBase, path, path_arr_size );
if( !path_arr_size || path_size == path_arr_size )
{
printf( "Unable to get path to self\n" );
return nullptr;
}
auto last_slash = strrchr( path, '\\' );
if( !last_slash )
{
printf( "Unable to get path to self\n" );
return nullptr;
}
*( last_slash + 1 ) = '\0';
if( strcat_s( path, path_arr_size, "D3D12Core.dll" ) != 0 )
{
printf( "Unable to get path to D3D12Core.dll next to self\n" );
return nullptr;
}
if( GetFileAttributesA( path ) == INVALID_FILE_ATTRIBUTES )
{
printf( "No D3D12Core.dll exists next to self\n" );
return nullptr;
}
*( last_slash + 1 ) = '\0';
return path;
}
HRESULT
CreateD3D12DeviceFactory( ID3D12DeviceFactory **ppFactory, UINT32 SDKVersion )
{
/* A device factory allows us to isolate things like debug layer enablement from other callers,
* and can potentially even refer to a different D3D12 redist implementation from others.
*/
HMODULE D3D12Module = LoadLibraryW( L"d3d12.dll" );
if( !D3D12Module )
{
printf( "D3D12: Failed to LoadLibrary d3d12.dll" );
return MF_E_DXGI_DEVICE_NOT_INITIALIZED;
}
typedef HRESULT( WINAPI * PFN_D3D12_GET_INTERFACE )( REFCLSID clsid, REFIID riid, void **ppFactory );
PFN_D3D12_GET_INTERFACE D3D12GetInterface = (PFN_D3D12_GET_INTERFACE) GetProcAddress( D3D12Module, "D3D12GetInterface" );
if( !D3D12GetInterface )
{
printf( "D3D12: Failed to retrieve D3D12GetInterface" );
return MF_E_DXGI_DEVICE_NOT_INITIALIZED;
}
/* First, try to create a device factory from a DLL-parallel D3D12Core.dll */
ID3D12SDKConfiguration *sdk_config = nullptr;
if( SUCCEEDED( D3D12GetInterface( CLSID_D3D12SDKConfiguration, IID_PPV_ARGS( &sdk_config ) ) ) )
{
ID3D12SDKConfiguration1 *sdk_config1 = nullptr;
if( SUCCEEDED( sdk_config->QueryInterface( &sdk_config1 ) ) )
{
char self_path[MAX_PATH];
const char *d3d12core_path = TryFindD3D12CoreNextToSelf( self_path, sizeof( self_path ) );
if( d3d12core_path &&
SUCCEEDED( sdk_config1->CreateDeviceFactory( SDKVersion, d3d12core_path, IID_PPV_ARGS( ppFactory ) ) ) )
{
sdk_config->Release();
sdk_config1->Release();
( *ppFactory )
->SetFlags( D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_EXISTING_DEVICE |
D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_INCOMPATIBLE_EXISTING_DEVICE );
return S_OK;
}
printf( "D3D12: Can't find matching D3D12Core.dll next to self." );
sdk_config->Release();
sdk_config1->Release();
return MF_E_DXGI_DEVICE_NOT_INITIALIZED;
}
else
{
printf( "D3D12: Failed to retrieve ID3D12SDKConfiguration1" );
return MF_E_DXGI_DEVICE_NOT_INITIALIZED;
}
}
else
{
printf( "D3D12: Failed to retrieve CLSID_D3D12SDKConfiguration" );
return MF_E_DXGI_DEVICE_NOT_INITIALIZED;
}
return MF_E_DXGI_DEVICE_NOT_INITIALIZED;
}
HRESULT
CreateD3D12Manager( IMFDXGIDeviceManager **ppMgr, UINT32 SDKVersion )
{
HRESULT hr = S_OK;
UINT resetToken;
ComPtr<ID3D12Device> spD3D12Device;
DXGI_ADAPTER_DESC adapterDesc = { 0 };
ComPtr<IDXGIFactory4> spDXGIFactory;
ComPtr<IDXGIAdapter> spDXGIAdapter;
ComPtr<ID3D12DeviceFactory> spFactory;
CHECKHR_GOTO( CreateDXGIFactory1( IID_PPV_ARGS( &spDXGIFactory ) ), done );
if( 0 /* m_inputParams.m_eGPU == GPU_WARP */ )
{
CHECKHR_GOTO( spDXGIFactory->EnumWarpAdapter( IID_PPV_ARGS( &spDXGIAdapter ) ), done );
CHECKHR_GOTO( spDXGIAdapter->GetDesc( &adapterDesc ), done );
}
else
{
for( UINT i = 0; spDXGIFactory->EnumAdapters( i, &spDXGIAdapter ) != DXGI_ERROR_NOT_FOUND; ++i )
{
CHECKHR_GOTO( spDXGIAdapter->GetDesc( &adapterDesc ), done );
}
}
CHECKHR_GOTO( MFCreateDXGIDeviceManager( &resetToken, ppMgr ), done );
if( SDKVersion != 0 )
{
CHECKHR_GOTO( CreateD3D12DeviceFactory( &spFactory, SDKVersion ), done );
/*
if( m_inputParams.m_bD3DDebugLayer )
{
ComPtr<ID3D12Debug> spDebugController;
CHECKHR_GOTO( spFactory->GetConfigurationInterface( CLSID_D3D12Debug, IID_PPV_ARGS( &spDebugController ) ), done );
spDebugController->EnableDebugLayer();
}
*/
CHECKHR_GOTO( spFactory->CreateDevice( spDXGIAdapter.Get(), D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS( &spD3D12Device ) ), done );
}
else
{
CHECKHR_GOTO( D3D12CreateDevice( spDXGIAdapter.Get(), D3D_FEATURE_LEVEL_12_1, IID_PPV_ARGS( &spD3D12Device ) ), done );
}
CHECKHR_GOTO( ( *ppMgr )->ResetDevice( spD3D12Device.Get(), resetToken ), done );
done:
return hr;
}
IMFMediaType *
CreateVideoMT( ULONG32 Width, ULONG32 Height, DWORD fourCC, BOOL interlaced, ULONG32 frNum, ULONG32 frDenom, UINT32 bitRate )
{
HRESULT hr = S_OK;
ComPtr<IMFMediaType> spVideoType {};
GUID guid = { 0x00000000, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 };
guid.Data1 = fourCC;
CHECKHR_GOTO( MFCreateMediaType( &spVideoType ), done );
CHECKHR_GOTO( spVideoType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Video ), done );
CHECKHR_GOTO( spVideoType->SetGUID( MF_MT_SUBTYPE, guid ), done );
CHECKHR_GOTO( MFSetAttributeRatio( spVideoType.Get(), MF_MT_FRAME_RATE, frNum, frDenom ), done );
CHECKHR_GOTO( MFSetAttributeSize( spVideoType.Get(), MF_MT_FRAME_SIZE, Width, Height ), done );
CHECKHR_GOTO( spVideoType->SetUINT32( MF_MT_AVG_BITRATE, ( Width * Height ) / 8 ), done );
CHECKHR_GOTO( spVideoType->SetUINT32( MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive ), done );
if( bitRate > 0 )
{
CHECKHR_GOTO( spVideoType->SetUINT32( MF_MT_AVG_BITRATE, bitRate ), done );
}
done:
if( FAILED( hr ) )
{
return nullptr;
}
return spVideoType.Detach();
}
CFrameGenerator::CFrameGenerator()
{ }
CFrameGenerator::~CFrameGenerator()
{ }
HRESULT
CFrameGenerator::GenerateSoftwareFrame( IMFSample **pFrame, bool *endOfStream )
{
HRESULT hr = S_OK;
const uint32_t inLength = m_uiWidth * m_uiHeight * 3 / 2;
ComPtr<IMFSample> spInSample;
ComPtr<IMFMediaBuffer> spInBuffer;
uint8_t *pBuf;
uint32_t offsetX = m_uiOffsetX;
uint32_t offsetY = m_uiOffsetY;
const uint8_t yellowY = 210;
const uint8_t yellowU = 16;
const uint8_t yellowV = 146;
const uint8_t tealY = 93;
const uint8_t tealU = 146;
const uint8_t tealV = 71;
const uint32_t boxWidth = 40;
const uint32_t boxHeight = 80;
*endOfStream = false;
if( m_uiFrameCount >= m_maxFrameCount )
{
*endOfStream = true;
return hr;
}
CHECKHR_GOTO( MFCreateSample( &spInSample ), done );
CHECKHR_GOTO( MFCreateMemoryBuffer( inLength, &spInBuffer ), done );
spInSample->AddBuffer( spInBuffer.Get() );
spInBuffer->Lock( &pBuf, NULL, NULL );
{
BYTE *pNV12 = pBuf;
for( uint32_t i = 0; i < m_uiHeight; i++ )
{
memset( pNV12 + i * m_uiWidth, yellowY, m_uiWidth );
}
pNV12 += m_uiWidth * m_uiHeight;
for( uint32_t i = 0; i < m_uiHeight / 2; i++ )
{
for( uint32_t j = 0; j < m_uiWidth; j += 2 )
{
pNV12[i * m_uiWidth + j] = yellowU;
pNV12[i * m_uiWidth + j + 1] = yellowV;
}
}
pNV12 = pBuf + offsetY * m_uiWidth + offsetX;
for( uint32_t i = 0; i < boxHeight; i++ )
{
memset( pNV12 + i * m_uiWidth, tealY, boxWidth );
}
pNV12 = pBuf + m_uiWidth * m_uiHeight + ( offsetY ) * ( m_uiWidth / 2 ) + ( offsetX );
for( uint32_t i = 0; i < boxHeight / 2; i++ )
{
for( uint32_t j = 0; j < boxWidth; j += 2 )
{
pNV12[i * m_uiWidth + j] = tealU;
pNV12[i * m_uiWidth + j + 1] = tealV;
}
}
m_uiOffsetX += 8;
if( m_uiOffsetX >= m_uiWidth - boxWidth )
{
m_uiOffsetX = 0;
}
}
spInBuffer->Unlock();
spInSample->SetSampleTime( ( m_uiFrameCount * 10000000i64 ) / m_uiNum );
spInSample->SetSampleDuration( 10000000i64 / m_uiNum );
m_uiFrameCount++;
*pFrame = spInSample.Detach();
done:
return hr;
}
@@ -0,0 +1,79 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "../hmft_entrypoints.h"
const char *
TryFindD3D12CoreNextToSelf( char *path, DWORD path_arr_size );
HRESULT
CreateD3D12DeviceFactory( ID3D12DeviceFactory **ppFactory, UINT32 SDKVersion );
HRESULT
CreateD3D12Manager( IMFDXGIDeviceManager **ppMgr, UINT32 SDKVersion );
IMFMediaType *
CreateVideoMT( ULONG32 Width, ULONG32 Height, DWORD fourCC, BOOL interlaced, ULONG32 frNum, ULONG32 frDenon, UINT32 bitRate = 0);
class MFStartupHelper
{
public:
MFStartupHelper(HRESULT& hr)
{
hr = S_OK;
if( SUCCEEDED( hr = CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED ) ) )
{
hr = MFStartup( MF_VERSION );
}
}
~MFStartupHelper()
{
MFShutdown();
// Free any unreferenced modules to catch potential leaks.
CoFreeUnusedLibrariesEx( 0, 0 );
CoUninitialize();
// CheckMFPlatStartupLeaks();
}
};
class CFrameGenerator
{
public:
CFrameGenerator();
~CFrameGenerator();
HRESULT GenerateSoftwareFrame( IMFSample **pFrame, bool *endOfStream );
public:
const uint32_t m_uiDiv = 1;
const uint32_t m_uiNum = 30;
const uint32_t m_uiWidth = 320;
const uint32_t m_uiHeight = 240;
const uint32_t m_maxFrameCount = 88;
uint32_t m_uiBitRate = 150;
uint32_t m_uiFrameCount = 0;
uint32_t m_uiOffsetX = 0;
uint32_t m_uiOffsetY = 0;
};
@@ -0,0 +1,18 @@
mediafoundation_test_st = {}
foreach codec : mft_codecs
test_lib = static_library(
'mediafoundation_test_st_' + codec,
files(
'hmft_test_helpers.cpp',
'hmft_codecapi_test.cpp',
'hmft_simple_encode_test.cpp',
'stub.cpp',
),
cpp_args : mf_codecs_cpp_args[codec],
override_options: ['cpp_std=c++20'],
include_directories: [inc_include, inc_src, inc_gallium, inc_gallium_aux],
dependencies: [idep_gtest, idep_mesautil, dep_dxheaders],
)
mediafoundation_test_st += {codec : test_lib}
endforeach
@@ -0,0 +1,43 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <guiddef.h>
#if MFT_CODEC_H264ENC
const wchar_t *g_pMFTFriendlyName = L"Microsoft AVC DX12 Encoder HMFT";
DEFINE_GUID( CLSID_CDX12EncoderHMFT, 0x8994db7c, 0x288a, 0x4c62, 0xa1, 0x36, 0xa3, 0xc3, 0xc2, 0xa2, 0x08, 0xa8 );
#elif MFT_CODEC_H265ENC
const wchar_t *g_pMFTFriendlyName = L"Microsoft HEVC DX12 Encoder HMFT";
DEFINE_GUID( CLSID_CDX12EncoderHMFT, 0xe7ffb8eb, 0xfa0b, 0x4fb0, 0xac, 0xdf, 0x12, 0x2, 0xf6, 0x63, 0xcd, 0xe5 );
#elif MFT_CODEC_AV1ENC
const wchar_t *g_pMFTFriendlyName = L"Microsoft AV1 DX12 Encoder HMFT";
DEFINE_GUID( CLSID_CDX12EncoderHMFT, 0x1a6f3150, 0xb121, 0x4ce9, 0x94, 0x97, 0x50, 0xfe, 0xdb, 0x3d, 0xcb, 0x70 );
#else
#error MFT_CODEC_xxx must be defined
#endif
extern "C" struct pipe_screen *
sw_screen_create_vk( struct sw_winsys *winsys, const struct pipe_screen_config *config, bool sw_vk )
{
return nullptr;
}
@@ -0,0 +1,237 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "videobufferlock.h"
#include "mfbufferhelp.h"
HRESULT
VideoBufferLock::lock( __in MF2DBuffer_LockFlags flags )
{
HRESULT hr = S_OK;
DWORD maxSize = 0;
BYTE *pbBufferStart = NULL;
DWORD dwBufferLength = 0;
UINT32 dwMinSize = 0;
LONG lDefaultStride = 0;
if( _bLocked2D || _bLocked2D2 || _bLockedBuffer )
{
return S_FALSE;
}
if( _pInputBuffer == nullptr )
{
return MF_E_NOT_INITIALIZED;
}
GUID format;
UINT32 unWidth = 0, unHeight = 0;
hr = _pmt->GetGUID( MF_MT_SUBTYPE, &format );
if( SUCCEEDED( hr ) )
{
hr = MFGetAttributeSize( _pmt.Get(), MF_MT_FRAME_SIZE, &unWidth, &unHeight );
if( SUCCEEDED( hr ) )
{
hr = MFGetStrideForBitmapInfoHeader( format.Data1, unWidth, &lDefaultStride );
}
}
if( FAILED( hr ) )
{
lDefaultStride = 0;
}
hr = MFCalculateImageSize( format, unWidth, unHeight, &dwMinSize );
if( FAILED( hr ) )
{
dwMinSize = 0;
(void) _pInputBuffer->GetCurrentLength( (DWORD *) &dwMinSize );
}
hr = _pInputBuffer.As( &_pInputBuffer2D2 );
if( SUCCEEDED( hr ) )
{
hr = _pInputBuffer2D2->Lock2DSize( flags, &_pData, &_lPitch, &pbBufferStart, &dwBufferLength );
if( SUCCEEDED( hr ) )
{
if( dwBufferLength < dwMinSize || abs( _lPitch ) < abs( lDefaultStride ) )
{
_pInputBuffer2D2->Unlock2D();
return MF_E_BUFFERTOOSMALL;
}
_bLocked2D2 = TRUE;
_uiSize = dwBufferLength;
_pDataTop = _pData;
_pData = pbBufferStart;
}
}
if( !_bLocked2D2 )
{
hr = _pInputBuffer.As( &_pInputBuffer2D );
if( SUCCEEDED( hr ) )
{
hr = _pInputBuffer2D->Lock2D( &_pData, &_lPitch );
if( SUCCEEDED( hr ) )
{
hr = _pInputBuffer->GetMaxLength( (DWORD *) &_uiSize );
if( FAILED( hr ) || abs( _lPitch ) < abs( lDefaultStride ) || _uiSize < dwMinSize )
{
_pInputBuffer2D->Unlock2D();
return MF_E_BUFFERTOOSMALL;
}
_uiSize = dwMinSize;
_bLocked2D = TRUE;
_pDataTop = _pData;
if( _lPitch < 0 )
{
_pData += _uiSize - abs( _lPitch );
}
}
}
}
if( !( _bLocked2D2 || _bLocked2D ) )
{
hr = _pInputBuffer->Lock( &_pData, &maxSize, NULL );
if( SUCCEEDED( hr ) )
{
hr = _pInputBuffer->GetMaxLength( (DWORD *) &_uiSize );
if( FAILED( hr ) || _uiSize < dwMinSize )
{
_pInputBuffer->Unlock();
return MF_E_BUFFERTOOSMALL;
}
_uiSize = dwMinSize;
_bLockedBuffer = TRUE;
_lPitch = lDefaultStride;
_pDataTop = _pData;
if( _lPitch < 0 )
{
_pData += _uiSize - abs( _lPitch );
}
}
}
return hr;
}
HRESULT
VideoBufferLock::lockRemap( __in MF2DBuffer_LockFlags flags, bool topDown, LONG restride )
{
HRESULT hr = S_OK;
if( FAILED( hr = lock( flags ) ) )
{
return hr;
}
if( restride != 0 || topDown && _lPitch < 0 )
{
LONG newPitch = _lPitch;
if( restride != 0 )
{
newPitch = restride;
}
if( topDown )
{
newPitch = abs( _lPitch );
}
BYTE *temp = new BYTE[newPitch * lines()];
if( nullptr == temp )
{
return E_OUTOFMEMORY;
}
if( FAILED( hr = MFCopyImage( temp, newPitch, _pData, _lPitch, abs( _lPitch ), lines() ) ) )
{
delete[] temp;
return hr;
}
_uiSize = newPitch * lines();
_pData = temp;
_pDataTop = temp;
_lPitch = newPitch;
_localAlloc = true;
}
return hr;
}
BOOL
VideoBufferLock::validate( BYTE *ptr ) const
{
if( _lPitch >= 0 )
{
return ptr <= _pData + _uiSize && ptr >= _pData;
}
else
{
return ptr >= _pData - _uiSize + abs( _lPitch ) && ptr <= _pData + abs( _lPitch );
}
}
VideoBufferLock &
VideoBufferLock::operator=( VideoBufferLock &&move )
{
_bLockedBuffer = move._bLockedBuffer;
_bLocked2D = move._bLocked2D;
_bLocked2D2 = move._bLocked2D2;
_localAlloc = move._localAlloc;
_pDataTop = move._pDataTop;
_pData = move._pData;
_lPitch = move._lPitch;
_pInputBuffer = move._pInputBuffer;
_uiSize = move._uiSize;
_pmt = move._pmt;
move._bLocked2D = FALSE;
move._bLocked2D2 = FALSE;
move._bLockedBuffer = FALSE;
return *this;
}
HRESULT
VideoBufferLock::unlock()
{
HRESULT hr = S_OK;
if( _bLockedBuffer && _pInputBuffer )
{
hr = _pInputBuffer->Unlock();
_bLockedBuffer = FALSE;
_pInputBuffer = nullptr;
}
if( _bLocked2D && _pInputBuffer2D )
{
hr = _pInputBuffer2D->Unlock2D();
_bLocked2D = FALSE;
_pInputBuffer2D = nullptr;
}
if( _bLocked2D2 && _pInputBuffer2D2 )
{
hr = _pInputBuffer2D2->Unlock2D();
_bLocked2D2 = FALSE;
_pInputBuffer2D2 = nullptr;
}
if( _localAlloc )
{
delete[] _pData;
_localAlloc = false;
}
return hr;
}
@@ -0,0 +1,129 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <Windows.h>
#include <mfapi.h>
#include <mferror.h>
#include <utility>
#include <wrl/client.h>
using namespace Microsoft::WRL;
// RAII class for safely taking IMFMediaBuffer locks.
// Provides extended information about the buffer using
// the IMFMediaType associated with the buffer
class VideoBufferLock
{
public:
VideoBufferLock()
{ }
// Main ctor
VideoBufferLock( IMFMediaBuffer *pBuffer, IMFMediaType *pmt ) : _pInputBuffer( pBuffer ), _pmt( pmt )
{ }
// Shortcut ctor that calls GetBufferByIndex for you
VideoBufferLock( IMFSample *pSamp, IMFMediaType *pmt, UINT index = 0 ) : _pmt( pmt )
{
// If this call fails, _pInputBuffer will be NULL which will fail lock()
(void) pSamp->GetBufferByIndex( index, &_pInputBuffer );
}
// Only support move semantics
VideoBufferLock( VideoBufferLock &&move )
{
*this = std::move( move );
}
// Only support move semantics
VideoBufferLock &operator=( VideoBufferLock &&move );
// Lock a video buffer
HRESULT lock( __in MF2DBuffer_LockFlags flags = MF2DBuffer_LockFlags_ReadWrite );
// Lock a video buffer, if the buffer does not match the given topDown and stride parameters the buffer
// will be copied into a buffer matching those properties.
HRESULT
lockRemap( __in MF2DBuffer_LockFlags flags = MF2DBuffer_LockFlags_ReadWrite, bool topDown = true, LONG restride = 0 );
// Unlock video buffer
HRESULT unlock();
~VideoBufferLock()
{
unlock();
}
// Returns a pointer to the buffer
BYTE *data() const
{
return _pData;
}
// Returns a pointer to the top of the buffer (no stride adjustment)
BYTE *dataTop() const
{
return _pDataTop;
}
// Returns the size of the buffer in bytes
UINT size() const
{
return _uiSize;
}
// Returns the size of one line of the buffer in bytes,
// may be negative for bottom-up images
LONG stride() const
{
return _lPitch;
}
// Returns the number of lines in the image (count of stride in size)
LONG lines() const
{
return _uiSize / abs( _lPitch );
}
// Validate if the given pointer is inside the buffer
BOOL validate( BYTE *ptr ) const;
private:
ComPtr<IMFMediaType> _pmt;
ComPtr<IMFMediaBuffer> _pInputBuffer;
BOOL _bLockedBuffer = FALSE;
ComPtr<IMF2DBuffer> _pInputBuffer2D;
BOOL _bLocked2D = FALSE;
ComPtr<IMF2DBuffer2> _pInputBuffer2D2;
BOOL _bLocked2D2 = FALSE;
BYTE *_pData = nullptr;
BYTE *_pDataTop = nullptr;
LONG _lPitch = 0;
UINT _uiSize = 0;
BOOL _localAlloc = FALSE;
};
@@ -0,0 +1,216 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
//
// Defines a set of macro that expand control model specified
// with WPP_CONTROL_GUIDS (example shown below)
// into an enum of trace levels and required structures that
// contain the mask of levels, logger handle and some information
// required for registration.
//
#ifndef WPP_ALREADY_INCLUDED
#define WPP_EVAL(x) x
#define WPP_STR(x) #x
#define WPP_STRINGIZE(x) WPP_STR(x)
#define WPP_GLUE(a, b) a ## b
#define WPP_GLUE3(a, b, c) a ## b ## c
#define WPP_GLUE4(a, b, c, d) a ## b ## c ## d
#define WPP_XGLUE(a, b) WPP_GLUE(a, b)
#define WPP_XGLUE3(a, b, c) WPP_GLUE3(a, b, c)
#define WPP_XGLUE4(a, b, c, d) WPP_GLUE4(a, b, c, d)
///////////////////////////////////////////////////////////////////////////////////
//
// #define WPP_CONTROL_GUIDS \
// WPP_DEFINE_CONTROL_GUID(Regular,(81b20fea,73a8,4b62,95bc,354477c97a6f), \
// WPP_DEFINE_BIT(Error) \
// WPP_DEFINE_BIT(Unusual) \
// WPP_DEFINE_BIT(Noise) \
// ) \
// WPP_DEFINE_CONTROL_GUID(HiFreq,(91b20fea,73a8,4b62,95bc,354477c97a6f), \
// WPP_DEFINE_BIT(Entry) \
// WPP_DEFINE_BIT(Exit) \
// WPP_DEFINE_BIT(ApiCalls) \
// WPP_DEFINE_BIT(RandomJunk) \
// WPP_DEFINE_BIT(LovePoem) \
// )
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WPP_NO_CONTROL_GUIDS
#ifdef WPP_DEFAULT_CONTROL_GUID
# ifdef WPP_CONTROL_GUIDS
# error WPP_DEFAULT_CONTROL_GUID cannot be used together with WPP_CONTROL_GUIDS.
# else // WPP_CONTROL_GUIDS
# define WPP_CONTROL_GUIDS \
WPP_DEFINE_CONTROL_GUID(Default,(WPP_DEFAULT_CONTROL_GUID), \
WPP_DEFINE_BIT(Error) \
WPP_DEFINE_BIT(Unusual) \
WPP_DEFINE_BIT(Noise) \
)
# endif // WPP_CONTROL_GUIDS
#endif // WPP_DEFAULT_CONTROL_GUID
#ifndef WPP_CONTROL_GUIDS
# pragma message(__FILE__ " : error : Please define control model via WPP_CONTROL_GUIDS or WPP_DEFAULT_CONTROL_GUID macros")
# pragma message(__FILE__ " : error : don't forget to call WPP_INIT_TRACING and WPP_CLEANUP in your main, DriverEntry or DllInit")
# pragma message(__FILE__ " : error : see tracewpp.doc for further information")
# error WPP_CONTROL_GUIDS not defined.
#endif // WPP_CONTROL_GUIDS
// a set of macro to convert a guid in a form x(81b20fea,73a8,4b62,95bc,354477c97a6f)
// into either a a struct or text string
#define _WPPW(x) WPP_GLUE(L, x)
#define WPP_GUID_NORM(l,w1,w2,w3,ll) l ## w1 ## w2 ## w3 ## ll
#define WPP_GUID_TEXT(l,w1,w2,w3,ll) #l "-" #w1 "-" #w2 "-" #w3 "-" #ll
#define WPP_GUID_WTEXT(l,w1,w2,w3,ll) _WPPW(#l) L"-" _WPPW(#w1) L"-" _WPPW(#w2) L"-" _WPPW(#w3) L"-" _WPPW(#ll)
#define WPP_EXTRACT_BYTE(val,n) (((ULONGLONG)(0x ## val) >> (8 * n)) & 0xFF)
#define WPP_GUID_STRUCT(l,w1,w2,w3,ll) {0x ## l, 0x ## w1, 0x ## w2,\
{WPP_EXTRACT_BYTE(w3, 1), WPP_EXTRACT_BYTE(w3, 0),\
WPP_EXTRACT_BYTE(ll, 5), WPP_EXTRACT_BYTE(ll, 4),\
WPP_EXTRACT_BYTE(ll, 3), WPP_EXTRACT_BYTE(ll, 2),\
WPP_EXTRACT_BYTE(ll, 1), WPP_EXTRACT_BYTE(ll, 0)} }
#ifndef WPP_FORCEINLINE
#define WPP_FORCEINLINE __forceinline
#endif
// define an enum of control block names
//////
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) WPP_XGLUE(WPP_CTL_, WPP_EVAL(Name)),
enum WPP_CTL_NAMES { WPP_CONTROL_GUIDS WPP_LAST_CTL};
#undef WPP_DEFINE_CONTROL_GUID
// define control guids
//////
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) \
extern __declspec(selectany) const GUID WPP_XGLUE4(WPP_, ThisDir, _CTLGUID_, WPP_EVAL(Name)) = WPP_GUID_STRUCT Guid;
WPP_CONTROL_GUIDS
#undef WPP_DEFINE_CONTROL_GUID
// define enums of individual bits
/////
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) \
WPP_XGLUE(WPP_BLOCK_START_, WPP_EVAL(Name)) = WPP_XGLUE(WPP_CTL_, WPP_EVAL(Name)) * 0x10000, Bits WPP_XGLUE(WPP_BLOCK_END_, WPP_EVAL(Name)),
# define WPP_DEFINE_BIT(Name) WPP_BIT_ ## Name,
enum WPP_DEFINE_BIT_NAMES { WPP_CONTROL_GUIDS };
# undef WPP_DEFINE_BIT
#undef WPP_DEFINE_CONTROL_GUID
#define WPP_MASK(CTL) (1 << ( ((CTL)-1) & 31 ))
#define WPP_FLAG_NO(CTL) ( (0xFFFF & ((CTL)-1) ) / 32)
#define WPP_CTRL_NO(CTL) ((CTL) >> 16)
// calculate how many DWORDs we need to get the required number of bits
// upper estimate. Sometimes will be off by one
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) | WPP_XGLUE(WPP_BLOCK_END_, WPP_EVAL(Name))
enum _WPP_FLAG_LEN_ENUM { WPP_FLAG_LEN = 1 | ((0 WPP_CONTROL_GUIDS) & 0xFFFF) / 32 };
#undef WPP_DEFINE_CONTROL_GUID
//
// Check that maximum number of flags does not exceed 32
//
#ifndef C_ASSERT
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
#endif
#define MAX_NUMBER_OF_ETW_FLAGS 34 // 32 flags plus 2 separators
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) && ((WPP_XGLUE(WPP_BLOCK_END_, WPP_EVAL(Name) & 0xFFFF)) < MAX_NUMBER_OF_ETW_FLAGS)
enum _WPP_FLAG_LEN_ENUM_MAX { WPP_MAX_FLAG_LEN_CHECK = (1 WPP_CONTROL_GUIDS) };
#undef WPP_DEFINE_CONTROL_GUID
#ifndef WPP_CB
#define WPP_CB WPP_GLOBAL_Control
#endif
#ifndef WPP_CB_TYPE
#define WPP_CB_TYPE WPP_PROJECT_CONTROL_BLOCK
#endif
#ifndef WPP_CHECK_INIT
#define WPP_CHECK_INIT (WPP_CB != (WPP_CB_TYPE*)&WPP_CB) &&
#endif
typedef union {
WPP_TRACE_CONTROL_BLOCK Control;
UCHAR ReserveSpace[ sizeof(WPP_TRACE_CONTROL_BLOCK) + sizeof(ULONG) * (WPP_FLAG_LEN - 1) ];
} WPP_CB_TYPE ;
extern __declspec(selectany) WPP_CB_TYPE *WPP_CB = (WPP_CB_TYPE*)&WPP_CB;
#if ENABLE_WPP_RECORDER
#ifndef WPP_RECORDER_CHECK_INIT
#define WPP_RECORDER_CHECK_INIT (WPP_RECORDER_INITIALIZED != (WPP_CB_TYPE*)&WPP_RECORDER_INITIALIZED) &&
#endif
// Global varaible used to track if WPP_RECORDER was initialized.
// It will be initialized on calling WPP_INIT_TRACING macro.
extern __declspec(selectany) WPP_CB_TYPE *WPP_RECORDER_INITIALIZED = (WPP_CB_TYPE*)&WPP_RECORDER_INITIALIZED;
#endif
#define WPP_CONTROL(CTL) (WPP_CB[WPP_CTRL_NO(CTL)].Control)
// Define the default WPP_LEVEL_LOGGER/WPP_LEVEL_ENABLED macros for the
// predefined DoTraceMessage(LEVEL) function.
#ifdef WPP_USE_TRACE_LEVELS
#ifndef WPP_LEVEL_LOGGER
#define WPP_LEVEL_LOGGER(lvl) (WPP_CONTROL(WPP_BIT_ ## DUMMY).Logger),
#endif
#ifndef WPP_LEVEL_ENABLED
#define WPP_LEVEL_ENABLED(lvl) (WPP_CONTROL(WPP_BIT_ ## DUMMY).Level >= lvl)
#endif
#else // WPP_USE_TRACE_LEVELS
// For historical reasons, the use of LEVEL means flags by default.
// This was a bad choice but very difficult to undo.
#ifndef WPP_LEVEL_LOGGER
# define WPP_LEVEL_LOGGER(CTL) (WPP_CONTROL(WPP_BIT_ ## CTL).Logger),
#endif
#ifndef WPP_LEVEL_ENABLED
# define WPP_LEVEL_ENABLED(CTL) (WPP_CONTROL(WPP_BIT_ ## CTL).Flags[WPP_FLAG_NO(WPP_BIT_ ## CTL)] & WPP_MASK(WPP_BIT_ ## CTL))
#endif
#endif // WPP_USE_TRACE_LEVELS
// Define default WPP_FLAG_LOGGER/WPP_FLAG_ENABLED macros for convenience in
// defining a function that takes a FLAG parameter e.g. DoTrace(FLAG).
#ifndef WPP_FLAG_LOGGER
# define WPP_FLAG_LOGGER(CTL) (WPP_CONTROL(WPP_BIT_ ## CTL).Logger),
#endif
#ifndef WPP_FLAG_ENABLED
# define WPP_FLAG_ENABLED(CTL) (WPP_CONTROL(WPP_BIT_ ## CTL).Flags[WPP_FLAG_NO(WPP_BIT_ ## CTL)] & WPP_MASK(WPP_BIT_ ## CTL))
#endif
#ifndef WPP_ENABLED
# define WPP_ENABLED() 1
#endif
#ifndef WPP_LOGGER
# define WPP_LOGGER() (WPP_CB[0].Control.Logger),
#endif
#endif // WPP_NO_CONTROL_GUIDS
#ifndef WPP_GET_LOGGER
# define WPP_GET_LOGGER Logger
#endif
#ifndef WPP_LOGGER_ARG
# define WPP_LOGGER_ARG TRACEHANDLE Logger,
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif // WPP_ALREADY_INCLUDED
@@ -0,0 +1,670 @@
#
# Default configuration options for tracewpp.
#
# This file provides configuration settings for tracewpp. By default, tracewpp
# uses "defaultwpp.ini" for configuration settings. An alternate INI file can
# be specified via the -defwpp parameter. Additional configuration settings can
# be specified via the -ini parameter or via "begin_wpp config" blocks in
# files specified via the -scan parameter.
#
# When parsing an INI file or a "begin_wpp config" block, tracewpp searches for
# syntax that looks like a function call, e.g. "FunctionName(arg1, ...);". For
# each function call, if the function name is one of the recognized commands
# described below (e.g. NOPREFIX, USEPREFIX, INCLUDE), that command is
# executed. Otherwise, the function call is treated as the definition of a
# trace function.
################################
# General configuration commands
################################
#
# FUNC FunctionName(ARG1, ARG2, MSG, ...);
# FUNC FunctionName{ARG1=value, ARG2=value}(ARG3, ARG4, MSG, ...);
#
# Defines a trace function and its arguments. The tracewpp tool will scan all
# source files for calls to the specified trace function. The generated TMH
# file will then define the specified name as a macro and will generate code
# to handle each call to the macro.
#
# Function definitions are often prefixed by "FUNC", e.g.
# "FUNC DoTraceMessage(LEVEL, MSG, ...);". The "FUNC" prefix is optional
# but is helpful in drawing attention to function definitions.
#
# Arguments provided in {braces} are defaulted parameters (sometimes called
# "assumed arguments"). If you define a trace function
# MyTrace{ARG1=5}(MSG, ...), then WPP will treat any use
# of MyTrace("...", a, b) as if it were MyTrace(5, "...", a, b), and WPP will
# generate macros for MyTrace that include an ARG1 parameter (for use by
# user-specified expressions in the macro definition).
#
# Note that when using TMF-based WPP, WPP will expect the user to define
# ENABLED and LOGGER macros based on the arguments for defined functions.
# For example, if you define a trace function
# MyTrace(FLAG, MYARG, MSG, ...), WPP will expect user-defined macros
# WPP_FLAG_MYARG_ENABLED(FLAG, MYARG) and WPP_FLAG_MYARG_LOGGER(FLAG, MYARG)
# to be provided by the user. These user-supplied macros are usually defined
# in terms of the corresponding WPP-supplied macros WPP_LEVEL_ENABLED(LEVEL)
# and WPP_LEVEL_LOGGER(LEVEL).
#
# Certain argument names trigger special behavior:
# - "MSG" is the format string.
# - "..." is a placeholder for the format string arguments. If present, it
# must be the last argument.
# - "PUBLIC_FILTER" marks the function as conditionally public. The function
# will be public if the WPP_PUBLIC_<Flag> macro is defined when the file is
# compiled (where <Flag> is the value of the PUBLIC_FILTER argument).
#
# Certain argument names trigger special behavior in manifest-based WPP:
# - "ControlGuid" specifies the name of the control GUID for the event. If
# there is no ControlGuid argument, tracewpp will determine the control
# GUID based on the event's level or keywords.
# - "Level" specifies the level of the event. If there is no Level argument,
# tracewpp will look for valid level names in all arguments of the event.
# If no level name is found, the level will default to "win:Verbose".
# - "Keywords" specifies the keywords (flags) of the event. If there is no
# Keywords argument, tracewpp will look for valid keyword names in all
# arguments of the event. If no keywords are found, the keyword will be
# "win:AnyKeyword" (i.e. 0).
# - "Name" specifies the event name.
# - "Id" allows manual assignment of event Id and Version attributes. Syntax
# is either "ID" or "IDvVERSION", e.g. "24" or "24v2". The specified Id
# must be a number from 0..65535 that is outside of the auto-assignment
# pool. Note that the auto-assignment pool defaults to 10..65535, so manual
# assignment generally requires adjusting the auto-assignment pool (via the
# TRACERANGE command).
# - "Func" specifies the name of the event's call site function. Note that
# when using manifest-based WPP, tracewpp is unable to automatically set
# the event's function name during manifest generation. The function name
# can be manually specified via the Func parameter or it can be included in
# the event payload via DEFAULT_FUNC_NAME_IN_EVENT/USE_FUNC_NAME_IN_EVENT.
#
# NOPREFIX(FunctionName);
#
# Removes the default trace message prefix "%!STDPREFIX!" for the specified
# trace function.
#
# USEPREFIX(FunctionName, [Prefix, ArgNames...]);
# USESUFFIX(FunctionName, [Suffix, ArgNames...]);
#
# Sets the trace message prefix or suffix for the specified trace function.
# Each time WPP sees function("message", ...), it will add the specified
# prefix or suffix to "message".
#
# PUBLIC_FILTER(FunctionName, Flag);
#
# Marks the named function as conditionally public. The function will be
# public if the WPP_PUBLIC_<Flag> macro is defined when the file is compiled.
# Public functions omit certain metadata from the TMF such as filename and
# line number. (Not applicable to manifest-based WPP.)
#
# INCLUDE(IniFileName);
#
# Immediately processes the specified file as an INI file.
#
# PROCESSFILES(SourceFile...);
#
# Processes the specified input file(s) as if they were specified on the
# tracewpp command line. Example: PROCESSFILES("MyFile.cpp", "B*.c");
#
# SCANFORMACROS(HeaderFile...);
#
# Scans the specified file(s) as if they were specified with
# /scan:HeaderFile on the tracewpp command line.
#
# SEPARATE_TRACE_GUID_PER_FILE(Enabled);
#
# If enabled (1), a new trace GUID will be generated for each input file
# scanned. This is useful for TMF-based WPP, as it means changes in one
# source file will not affect the trace GUID or event IDs of other source
# files. This is undesirable for manifest-based WPP, as it requires a
# large number of providers to be registered.
#
# This is enabled (1) by default for TMF-based WPP. This is disabled (0) by
# default for manifest-based WPP (when the /man parameter is specified).
#
# TRACERANGE(Min, Max);
#
# Configures the range of numbers that WPP will use when automatically
# assigning event IDs. Default is 10..65535. If manually assigning Ids, you
# will need to reduce this range to reserve Ids for manual assignment, e.g.
# use TRACERANGE(1000, 65535) so that Ids 1..999 can be manually assigned.
#
# WPP_FLAGS(Option...);
#
# Processes the specified options as if they were specified on the tracewpp
# command line. Example: WPP_FLAGS(noshrieks, p:MyProject);
################################
# Type definition commands
################################
#
# The following commands can be used to define data types for use with WPP
# trace functions. WPP type definitions may include the following settings:
#
# - Name: the WPP name of the type being defined. This name must be unique.
# When reading the WPP format strings from source code, WPP matches the
# requested type against this name. For example, "%d" will cause WPP to look
# for a type named "d", and "%!HRESULT!" will cause WPP to look for a type
# named "HRESULT".
# - EquivType: the name of the type in C or C++, e.g. "int". This type will be
# used for the parameter of the inline helper function in the generated
# code.
# - MofType: the MOF name of the type (shows up in the TMF file).
# - FormatSpec: the format string to use for this type in the message string.
# For example, if FormatSpec is "I64x" then a message string might look like:
# "Value = %10!I64x!".
# - Sig: the short name to use for this type when generating the names for
# helper functions. Two different WPP types might use the same signature
# because the types are compatible in terms of the helper functions (the
# underlying C/C++ types are the same and the types serialize into ETW data
# the same way).
# - Priority: the priority to give the type during argument sorting (only
# significant when the /reorder parameter is used). This value is typically
# set to the type's alignment so that more-aligned values sort first and
# remain aligned within the ETW data.
# - ManifestType: describes the how the type should be treated in
# manifest-based WPP. The ManifestType is a semicolon-separated list of type
# parameters. The first parameter is required and specifies the winmeta input
# type, e.g. "win:UInt32" (valid winmeta types are described in winmeta.xml).
# Subsequent parameters specify options in the form of a name=value pair. The
# supported options are:
# - outType: Specifies the winmeta output type (i.e. a type formatting
# qualifier), e.g. "xs:string". If not set, the type will not include an
# outType attribute in the manifest and will receive default formatting by
# the trace decoder. Example use of outType: win:Int32;outType=win:HResult
# - adapter: Specifies a function or macro that should be applied to values
# of this type before passing the value to the MC-generated EventWrite
# macro. For example, if argument a10 has no adapter and argument a11 has
# "ADAPT" as its adapter, the MC-generated EventWrite macro would be
# invoked as EventWriteMyEvent(a10, ADAPT(a11)). The adapter might perform
# a cast (e.g. cast ULONG_PTR to void*) or in the case of a Counted type
# might convert a single value into a length+pointer pair. For example, the
# adapter for a PUNICODE_STRING type might be the following macro:
# #define ADAPT_PSTR(p) p->Length/2, p->Buffer
# Example use of adapter: win:CountedUnicodeString;adapter=ADAPT_PSTR
#
# CUSTOM_TYPE(Name, BaseType(Extension), [FormatSpec]);
#
# Creates a new type by adding an extension to an existing type. Typically
# used to define enumerations, e.g.:
# ItemListByte(EnumValues...), ItemListShort(EnumValues...),
# ItemListLong(EnumValues...), ItemSetByte(EnumValues...),
# ItemSetShort(EnumValues...), ItemSetLong(EnumValues...),
# ItemEnum(EnumName), or ItemFlagsEnum(EnumName).
#
# ItemList types are used for list enums, i.e. items counting up from 0.
# ItemList types support skipping values via Value=number syntax.
#
# ItemSet types are used for bitset enums, i.e. the first item has value
# 1, the second has value 2, the third has value 4, the fourth has value 8.
#
# ItemEnum and ItemFlagsEnum types reference the name of a C/C++ enum and
# are resolved using symbol information from the PDB. (ItemEnum and
# ItemFlagsEnum do not work for manifest-based WPP because the PDB is not
# used for resolving enumerations.)
#
# TYPEMACRO(Name, BaseType(Extension), [FormatSpec]);
#
# Deprecated. Same as CUSTOM_TYPE.
#
# DEFINE_SIMPLE_TYPE(Name, EquivType, MofType, FormatSpec, Sig, Priority,
# [ManifestType]);
#
# Creates a new fixed-length type that is passed to the helper function by
# value (uses helper macro WPP_LOGTYPEVAL). Size in the event payload will
# be sizeof(EquivType).
#
# DEFINE_SIMPLE_TYPE_PTR(Name, EquivType, MofType, FormatSpec, Sig, Priority,
# [ManifestType]);
#
# Creates a new fixed-length type that is passed to the helper function by
# address (uses helper macro WPP_LOGTYPEPTR). Size in the event payload will
# be sizeof(*value).
#
# DEFINE_FLAVOR(Name, BaseType, [MofType, FormatSpec, ManifestType]);
#
# Defines a new type that is based on another similar type, potentially
# overriding the base type's MofType, FormatSpec, and manifest type. Omitted
# or blank settings will remain the same as the base type.
#
# DEFINE_CPLX_TYPE(Name, MacroName, EquivType, MofType, FormatSpec, Sig,
# Priority, [ManifestType]);
#
# Defines a complex type, i.e. one that requires special handling via a
# helper macro other than WPP_LOGTYPEVAL or WPP_LOGTYPEPTR. Any type with a
# variable length (e.g. any string type) is complex.
#
# MacroName is the name of the helper macro that WPP should invoke when
# passing this value to the helper function. The helper macro should itself
# invoke the WPP_LOGPAIR macro with the data size and the data pointer. (Note
# that helper macros are only used for TMF-based WPP, not for manifest-based
# WPP.)
################################
# Manifest definition commands
################################
#
# The following commands are used with manifest-based WPP. Many of these
# commands accept a required Name, and allow for an optional Symbol. The item
# defined by such a command can be referenced by either its name or its
# symbol. If no symbol is defined, it can only be referenced by its name. The
# symbol may be useful in cases where the desired name is not a C/C++-friendly
# identifier.
#
# MANIFEST_CONFIGURATION(ManifestFile, [HeaderFile, Prefix]);
#
# For use with manifest-based WPP. Normally specified via the command-line
# -man option, not in an INI file or via configuration blocks.
#
# MANIFEST_RESOURCES(ResourceFile, [MessageFile, Culture]);
#
# For use with manifest-based WPP. Specifies information about the installed
# location of the DLL/EXE/SYS file that contains a manifest's resource data.
# If not specified, Culture defaults to "en-us". Since the install location
# is usually not known at build time, tracewpp defaults to using dummy paths
# for the resource file and message file. The dummy paths are typically
# overridden by the /rf and /mf parameters on the wevtutil command line
# during manifest installation. Note that the ResourceFile and MessageFile
# values must be absolute paths.
#
# DEFINE_CONTROL_GUID(Name, [Guid, Symbol]);
#
# For use with manifest-based WPP. Defines a control GUID (aka a provider).
# If the Guid parameter is not specified, the GUID for the provider will be
# computed by hashing the Name using the same name hashing algorithm as is
# used by tracelog, xperf, EventSource, and other ETW tools.
#
# DEFINE_BIT(Name, [Mask, Symbol]);
#
# For use with manifest-based WPP. Adds a keyword to the most recently
# defined control guid. The default mask of the keyword is the control
# guid's lowest unused keyword bit.
#
# Mask may be specified as decimal or hexadecimal and must be a power of 2.
#
# DEFINE_KEYWORD(Name, ControlGuidId, Mask, [Symbol]);
#
# For use with manifest-based WPP. Defines a keyword associated with the
# specified control GUID. Rarely used: DEFINE_BIT is usually simpler.
#
# DEFINE_LEVEL(Name, ControlGuidId, Value, [Symbol]);
#
# For use with manifest-based WPP. Defines a level associated with the
# specified control GUID. The level value must not conflict with any
# built-in levels (level values 0 through 15 are built-in levels). Rarely
# used: the built-in levels are sufficient for most components.
#
# DEFINE_BUILTIN_KEYWORD(Name, Mask, [Symbol, Symbol...]);
#
# For use with manifest-based WPP. Normally used in the defaultwpp.ini file,
# not in per-project INI files or configuration blocks. Defines a global
# (Microsoft-defined) keyword value. These keywords can be used with any
# control GUID. These keywords will not be defined in the manifest - they
# are expected to match keyword definitions from winmeta.xml.
#
# DEFINE_BUILTIN_LEVEL(Name, Value, [Symbol, Symbol...]);
#
# For use with manifest-based WPP. Normally used in the defaultwpp.ini file,
# not in per-project INI files or configuration blocks. Defines a global
# (Microsoft-defined) level value. These levels can be used with any control
# GUID. These levels will not be defined in the manifest - they are expected
# to match level definitions from winmeta.xml.
#
# DEFAULT_FUNC_NAME_IN_EVENT(Expression, [TypeName]);
#
# For use with manifest-based WPP. When using manifest-based WPP, tracewpp is
# unable to automatically set the event's function name during manifest
# generation. The function name can be manually specified via the Func
# parameter or it can be included in the event payload via
# DEFAULT_FUNC_NAME_IN_EVENT or USE_FUNC_NAME_IN_EVENT.
# The DEFAULT_FUNC_NAME_IN_EVENT command will add a hidden string property
# named "!FUNC!" to every event (except when overridden by
# USE_FUNC_NAME_IN_EVENT). The value of the property will be taken from the
# specified Expression. The Expression will typically be set to
# "__FUNCTION__". TypeName is the WPP name of the type to use for the hidden
# argument. TypeName defaults to "hs" (i.e. nul-terminated char* string).
#
# USE_FUNC_NAME_IN_EVENT(FunctionName, Expression, [TypeName]);
#
# For use with manifest-based WPP. When using manifest-based WPP, tracewpp is
# unable to automatically set the event's function name during manifest
# generation. The function name can be manually specified via the Func
# parameter or it can be included in the event payload via
# DEFAULT_FUNC_NAME_IN_EVENT or USE_FUNC_NAME_IN_EVENT.
#
# The USE_FUNC_NAME_IN_EVENT command with a non-empty value for Expression
# will add a hidden string property named "!FUNC!" to every event generated
# by the specified trace function. The value of the property will be taken
# from the specified Expression. The Expression will typically be set to
# "__FUNCTION__". TypeName is the WPP name of the type to use for the hidden
# argument. TypeName defaults to "hs" (i.e. nul-terminated char* string).
#
# If Expression is empty (i.e. ""), the "!FUNC!" property will not be added
# to events generated by the specified trace function. A blank Expression
# can be used to override a default set by DEFAULT_FUNC_NAME_IN_EVENT.
#
################################
# Format string syntax
################################
#
# The format string is parsed to determine the type and format of event
# properties. Format string syntax is similar to printf, i.e. a '%' character
# not immediately followed by another '%' character will be treated as the
# start of a property reference.
#
# A property reference is parsed as one of the following:
#
# '%' [ '{' PropertyName '}' ] [Prefix] ShortTypeName
# '%' [ '{' PropertyName '}' ] [ArgNum] '!' [Prefix] LongTypeName '!'
#
# {PropertyName} is optional. If specified, the name must contain only
# identifier characters, i.e. a-z, 0-9, and '_'.
#
# Prefix includes flags ('-', '+', '#'), width digits, and/or '.' followed by
# precision digits. Note that prefix does not support "*" or ".*".
#
# If prefix is specified, it will be included in the event's format string
# along with the type's FormatSpec. For example, "%+02hX" would be parsed as
# Prefix="+02", ShortTypeName="hX". Type "hX" has FormatSpec="X", so the final
# WPP format string for the property would be "+02X".
#
# If the -NoShrieks command-line option is set and the prefix before a
# ShortTypeName contains only digits, tracewpp will treat the number as an
# ArgNum instead of a Width.
#
# The ArgNum before '!' is optional. It indicates the index of the argument to
# use for this property reference. If not specified, ArgNum is determined from
# the position of the property reference in the format string.
#
# By default, ShortTypeName is a length (one of "", "I", "I64", "h", "w", "l",
# or "ll") followed by a specifier (any single character). However, if the
# -NoShrieks command-line option is set, ShortTypeName is any number of
# identifier characters (a-z, A-Z, 0-9, '_') and ends at the first
# non-identifier character.
#
# LongTypeName is any non-empty sequence of characters ending at the '!'.
#
# ShortTypeName or LongTypeName must match the name of a defined WPP type (i.e.
# the type names defined below or your own custom types).
#
################################
# Default WPP configuration
################################
# our basic arithmetic types
DEFINE_SIMPLE_TYPE( XINT64, signed __int64, ItemLongLongX, "I64x", i, 8, win:HexInt64);
DEFINE_SIMPLE_TYPE( XXINT64,signed __int64, ItemLongLongXX,"I64X", i, 8, win:HexInt64);
DEFINE_SIMPLE_TYPE( OINT64, signed __int64, ItemLongLongO, "I64o", i, 8, win:HexInt64);
DEFINE_SIMPLE_TYPE( SBYTE, signed char, ItemChar, "c", c, 1, win:Int8);
DEFINE_SIMPLE_TYPE( SSHORT, signed short, ItemShort, "hd", h, 2, win:Int16);
DEFINE_SIMPLE_TYPE( SINT, signed int, ItemLong, "d", d, 4, win:Int32);
DEFINE_SIMPLE_TYPE( SLONG, signed long, ItemLong, "ld", l, 4, win:Int32);
DEFINE_SIMPLE_TYPE( SINT64, signed __int64, ItemLongLong, "I64d", i, 8, win:Int64);
DEFINE_SIMPLE_TYPE( UBYTE, unsigned char, ItemChar, "c", C, 1, win:UInt8);
DEFINE_SIMPLE_TYPE( USHORT, unsigned short, ItemShort, "hu", H, 2, win:UInt16);
DEFINE_SIMPLE_TYPE( UINT, unsigned int, ItemLong, "u", D, 4, win:UInt32);
DEFINE_SIMPLE_TYPE( ULONG, unsigned long, ItemLong, "lu", L, 4, win:UInt32);
DEFINE_SIMPLE_TYPE( UINT64, unsigned __int64,ItemULongLong, "I64u", I, 8, win:UInt64);
DEFINE_SIMPLE_TYPE( DOUBLE, double, ItemDouble, "s", g, 8, win:Double);
DEFINE_FLAVOR( UCHAR, UBYTE, ItemUChar, "c", win:UInt8; outType=xs:string);
DEFINE_FLAVOR( SCHAR, SBYTE, ItemChar, "c", win:Int8; outType=xs:string);
# arch dependent types
DEFINE_SIMPLE_TYPE( SLONGPTR, LONG_PTR, ItemPtr, "Id", p, 7, win:Pointer; adapter=WPP_ADAPTER_PVOID; outType=xs:long);
DEFINE_SIMPLE_TYPE( ULONGPTR, ULONG_PTR, ItemPtr, "Iu", P, 7, win:Pointer; adapter=WPP_ADAPTER_PVOID; outType=xs:unsignedLong);
DEFINE_SIMPLE_TYPE( PTR, const void*, ItemPtr, "p", q, 6, win:Pointer);
DEFINE_SIMPLE_TYPE( HANDLE, const void*, ItemPtr, "p", q, 6, win:Pointer);
DEFINE_SIMPLE_TYPE_PTR(GUID, LPCGUID, ItemGuid, "s", _guid_, 4, win:GUID);
# Predefined constants.
# Typically used in the function's prefix or suffix.
DEFINE_SIMPLE_TYPE( COMPNAME,,, "__COMPNAME__",,);
DEFINE_SIMPLE_TYPE( FILE,,, "__FILE__",,);
DEFINE_SIMPLE_TYPE( LINE,,, "__LINE__",,);
DEFINE_SIMPLE_TYPE( SPACE,,, " ",,);
# The following can be used in the prefix or suffix.
DEFINE_SIMPLE_TYPE( FUNC,,, "%!FUNC!",,);
DEFINE_SIMPLE_TYPE( LEVEL,,, "%!LEVEL!",,);
DEFINE_SIMPLE_TYPE( KEYWORDS,,, "%!FLAGS!",,);
DEFINE_SIMPLE_TYPE( STDPREFIX,,, "%0",,); # Only works at start of prefix. Ignored for manifest-based WPP.
DEFINE_SIMPLE_TYPE( MOD,,, "%1!s!",,);
DEFINE_SIMPLE_TYPE( TYP,,, "%2!s!",,);
DEFINE_SIMPLE_TYPE( TID,,, "%3!x!",,);
DEFINE_SIMPLE_TYPE( NOW,,, "%4!s!",,);
DEFINE_SIMPLE_TYPE( SEQ,,, "%7!u!",,);
DEFINE_SIMPLE_TYPE( PID,,, "%8!x!",,);
DEFINE_SIMPLE_TYPE( CPU,,, "%9!u!",,);
# Complex types
# Strings and SID require custom processing
DEFINE_CPLX_TYPE(ASTR, WPP_LOGASTR, LPCSTR, ItemString, "s", s, 1, win:AnsiString);
DEFINE_CPLX_TYPE(ARSTR, WPP_LOGASTR, LPCSTR, ItemRString, "s", s, 1, win:AnsiString);
DEFINE_CPLX_TYPE(ARWSTR,WPP_LOGWSTR, LPCWSTR, ItemRWString,"s", S, 2, win:UnicodeString);
DEFINE_CPLX_TYPE(WSTR, WPP_LOGWSTR, LPCWSTR, ItemWString, "s", S, 2, win:UnicodeString);
DEFINE_CPLX_TYPE(CSTR, WPP_LOGPCSTR, const CSTRING*, ItemPString, "s", z, 1, win:CountedAnsiString; adapter=WPP_ADAPTER_PCSTR);
DEFINE_CPLX_TYPE(USTR, WPP_LOGPUSTR, PCUNICODE_STRING, ItemPWString,"s", Z, 2, win:CountedUnicodeString; adapter=WPP_ADAPTER_PUSTR);
DEFINE_CPLX_TYPE(ANSTR, WPP_LOGPCSTR, const ANSI_STRING*, ItemPString, "s", aZ, 1, win:CountedAnsiString; adapter=WPP_ADAPTER_PCSTR);
DEFINE_CPLX_TYPE(sid, WPP_LOGPSID, PSID, ItemSid, "s", _sid_, 0, win:SID; adapter=WPP_ADAPTER_PSID);
# Raw binary data. Usage: DoTraceMessage(FLAG, "%!BIN!", WppBinary(pointer, size));
DEFINE_CPLX_TYPE(BIN, WPP_LOGCSTR, WPP_BINARY, ItemHexDump, "s", _zb_, 1, win:CountedBinary; adapter=WPP_ADAPTER_BIN);
# C++ string types
DEFINE_CPLX_TYPE(str, WPP_LOGCPPSTR, const std::string&, ItemPString, "s", _str_, 0, win:CountedAnsiString; adapter=WPP_ADAPTER_CPPSTR);
DEFINE_CPLX_TYPE(wstr, WPP_LOGCPPSTR, const std::wstring&, ItemPWString, "s", _wstr_, 0, win:CountedUnicodeString; adapter=WPP_ADAPTER_CPPSTR);
DEFINE_CPLX_TYPE(sv, WPP_LOGCPPVEC, const std::string_view&, ItemPString, "s", _sv_, 0, win:CountedAnsiString; adapter=WPP_ADAPTER_CPPVEC);
DEFINE_CPLX_TYPE(wsv, WPP_LOGCPPVEC, const std::wstring_view&,ItemPWString, "s", _wsv_, 0, win:CountedUnicodeString; adapter=WPP_ADAPTER_CPPVEC);
# Define printf-compatible types
DEFINE_FLAVOR(e, DOUBLE,,);
DEFINE_FLAVOR(E, DOUBLE,,);
DEFINE_FLAVOR(f, DOUBLE,,);
DEFINE_FLAVOR(g, DOUBLE,,);
DEFINE_FLAVOR(G, DOUBLE,,);
DEFINE_FLAVOR(c, SCHAR,,);
DEFINE_FLAVOR(hc, SCHAR,,);
DEFINE_FLAVOR(lc, SSHORT,,);
DEFINE_FLAVOR(wc, SSHORT,,);
DEFINE_FLAVOR(C, SSHORT,,);
DEFINE_FLAVOR(s, ASTR,,);
DEFINE_FLAVOR(hs, ASTR,,);
DEFINE_FLAVOR(S, WSTR,,);
DEFINE_FLAVOR(ws, WSTR,,);
DEFINE_FLAVOR(ls, WSTR,,);
DEFINE_FLAVOR(hi, SSHORT,,);
DEFINE_FLAVOR(hd, SSHORT,,);
DEFINE_FLAVOR(hu, USHORT,,"u");
DEFINE_FLAVOR(hx, USHORT,,"x", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(hX, USHORT,,"X", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(ho, USHORT,,"o", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(Id, ULONGPTR,,"Id");
DEFINE_FLAVOR(Iu, ULONGPTR,,"Iu");
DEFINE_FLAVOR(Ix, ULONGPTR,,"Ix", win:Pointer; adapter=WPP_ADAPTER_PVOID);
DEFINE_FLAVOR(IX, ULONGPTR,,"IX", win:Pointer; adapter=WPP_ADAPTER_PVOID);
DEFINE_FLAVOR(Io, ULONGPTR,,"Io", win:Pointer; adapter=WPP_ADAPTER_PVOID);
DEFINE_FLAVOR(i, SINT,,);
DEFINE_FLAVOR(d, SINT,,);
DEFINE_FLAVOR(u, UINT,,"u");
DEFINE_FLAVOR(x, UINT,,"x", win:HexInt32);
DEFINE_FLAVOR(X, UINT,,"X", win:HexInt32);
DEFINE_FLAVOR(o, UINT,,"o", win:HexInt32);
DEFINE_FLAVOR(cccc, SINT, ItemChar4, "s", win:AnsiString; length=4; adapter=WPP_ADAPTER_CCCC);
DEFINE_FLAVOR(li, SLONG,,);
DEFINE_FLAVOR(ld, SLONG,,);
DEFINE_FLAVOR(lu, ULONG,,"u");
DEFINE_FLAVOR(lx, ULONG,,"x", win:HexInt32);
DEFINE_FLAVOR(lX, ULONG,,"X", win:HexInt32);
DEFINE_FLAVOR(lo, ULONG,,"o", win:HexInt32);
DEFINE_FLAVOR(I64d, SINT64,,);
DEFINE_FLAVOR(I64u, UINT64,,);
DEFINE_FLAVOR(I64x, XINT64,,"I64x");
DEFINE_FLAVOR(I64X, XXINT64,,"I64X");
DEFINE_FLAVOR(I64o, OINT64,,"I64o");
DEFINE_FLAVOR(lld, SINT64,,);
DEFINE_FLAVOR(llu, UINT64,,);
DEFINE_FLAVOR(llx, XINT64,,"I64x");
DEFINE_FLAVOR(llX, XXINT64,,"I64X");
DEFINE_FLAVOR(llo, OINT64,,"I64o");
DEFINE_FLAVOR(p, PTR,,);
DEFINE_FLAVOR(Z, ANSTR,,);
DEFINE_FLAVOR(wZ, USTR,,);
DEFINE_FLAVOR(z, CSTR,,);
DEFINE_FLAVOR(hZ, CSTR,,);
# default formats for those who don't care to provide their own strings
DEFINE_FLAVOR(XBYTE, SBYTE,, "02x", win:UInt8; outType=win:HexInt8);
DEFINE_FLAVOR(OBYTE, SBYTE,, "o", win:UInt8; outType=win:HexInt8);
DEFINE_FLAVOR(XSHORT, SSHORT,, "04hX", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(OSHORT, SSHORT,, "ho", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(XINT, SINT,, "08x", win:HexInt32);
DEFINE_FLAVOR(OINT, SINT,, "o", win:HexInt32);
DEFINE_FLAVOR(XLONG, SLONG,, "08lX", win:HexInt32);
DEFINE_FLAVOR(OLONG, SLONG,, "lo", win:HexInt32);
DEFINE_FLAVOR(XLONGPTR, SLONGPTR,,"Ix", win:Pointer; adapter=WPP_ADAPTER_PVOID);
DEFINE_FLAVOR(OLONGPTR, SLONGPTR,,"Io", win:Pointer; adapter=WPP_ADAPTER_PVOID);
# special formats
DEFINE_FLAVOR(IPADDR, UINT, ItemIPAddr, "s", win:UInt32; outType=win:IPv4);
DEFINE_FLAVOR(PORT, USHORT, ItemPort, "s", win:UInt16; outType=win:Port);
DEFINE_FLAVOR(STATUS, SINT, ItemNTSTATUS, "s", win:HexInt32; outType=win:NTSTATUS);
DEFINE_FLAVOR(WINERROR, UINT, ItemWINERROR, "s", win:UInt32; outType=win:Win32Error);
DEFINE_FLAVOR(HRESULT, SINT, ItemHRESULT, "s", win:Int32; outType=win:HResult);
# Note: The %!NDIS_STATUS! and %!NDIS_OID! types work for for TMF-based WPP but
# do not work well with manifest-based WPP. Manifest-based ETW decoders will
# treat %!NDIS_STATUS! and %!NDIS_OID! items as HexInt32 items.
DEFINE_FLAVOR(NDIS_STATUS, SINT, ItemNDIS_STATUS, "s", win:HexInt32);
DEFINE_FLAVOR(NDIS_OID, UINT, ItemNDIS_OID, "s", win:HexInt32);
DEFINE_FLAVOR(ipaddr,IPADDR,,);
DEFINE_FLAVOR(port,PORT,,);
DEFINE_FLAVOR(status,STATUS,,);
DEFINE_FLAVOR(hresult,HRESULT,,);
DEFINE_FLAVOR(winerr,WINERROR,,);
DEFINE_FLAVOR(guid,GUID,,);
# time related stuff
DEFINE_FLAVOR(TIMESTAMP, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(TIME, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(DATE, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(WAITTIME, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(due, SINT64, ItemWaitTime, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(delta, SINT64, ItemTimeDelta, "s");
DEFINE_FLAVOR(datetime, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
# enumeration types
DEFINE_FLAVOR(ItemListByte, SBYTE, ItemListByte, "s", win:UInt8);
DEFINE_FLAVOR(ItemListShort, SSHORT, ItemListShort, "s", win:UInt16);
DEFINE_FLAVOR(ItemListLong, SLONG, ItemListLong, "s", win:UInt32);
DEFINE_FLAVOR(ItemSetByte, UBYTE, ItemSetByte, "s", win:UInt8; outType=win:HexInt8);
DEFINE_FLAVOR(ItemSetShort, USHORT, ItemSetShort, "s", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(ItemSetLong, ULONG, ItemSetLong, "s", win:HexInt32);
# Note: The "ItemEnum" and "ItemFlagsEnum" types work for for TMF-based WPP but
# do not work well with manifest-based WPP. Manifest-based ETW decoders will
# treat types based on "ItemEnum" as UInt32 and will treat types based on
# "ItemFlagsEnum" as HexInt32. For better results, use ItemListLong,
# ItemSetLong, or a "begin_wpp enum" block for your enumeration.
DEFINE_FLAVOR(ItemEnum, ULONG, ItemEnum, "s");
DEFINE_FLAVOR(ItemFlagsEnum, ULONG, ItemFlagsEnum, "s", win:HexInt32);
DEFINE_FLAVOR(CLSID, GUID, ItemCLSID, "s");
DEFINE_FLAVOR(LIBID, GUID, ItemLIBID, "s");
DEFINE_FLAVOR(IID, GUID, ItemIID, "s");
CUSTOM_TYPE(b1, ItemSetByte(1,2,3,4,5,6,7,8) );
CUSTOM_TYPE(b2, ItemSetShort(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) );
CUSTOM_TYPE(b4, ItemSetLong(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32) );
CUSTOM_TYPE(bool, ItemListLong(false,true) );
CUSTOM_TYPE(bool16, ItemListShort(false,true) );
CUSTOM_TYPE(bool8, ItemListByte(false,true) );
CUSTOM_TYPE(BOOLEAN, ItemListByte(FALSE,TRUE) );
CUSTOM_TYPE(irql, ItemListByte(Low,APC,DPC) );
CUSTOM_TYPE(pnpmn, ItemListByte(IRP_MN_START_DEVICE,IRP_MN_QUERY_REMOVE_DEVICE,IRP_MN_REMOVE_DEVICE,IRP_MN_CANCEL_REMOVE_DEVICE,IRP_MN_STOP_DEVICE,IRP_MN_QUERY_STOP_DEVICE,IRP_MN_CANCEL_STOP_DEVICE,IRP_MN_QUERY_DEVICE_RELATIONS,IRP_MN_QUERY_INTERFACE,IRP_MN_QUERY_CAPABILITIES,IRP_MN_QUERY_RESOURCES,IRP_MN_QUERY_RESOURCE_REQUIREMENTS,IRP_MN_QUERY_DEVICE_TEXT,IRP_MN_FILTER_RESOURCE_REQUIREMENTS,IRP_MN_PNP_14,IRP_MN_READ_CONFIG,IRP_MN_WRITE_CONFIG,IRP_MN_EJECT,IRP_MN_SET_LOCK,IRP_MN_QUERY_ID,IRP_MN_QUERY_PNP_DEVICE_STATE,IRP_MN_QUERY_BUS_INFORMATION,IRP_MN_DEVICE_USAGE_NOTIFICATION,IRP_MN_SURPRISE_REMOVAL) );
CUSTOM_TYPE(sysctrl, ItemListByte(IRP_MN_QUERY_ALL_DATA,IRP_MN_QUERY_SINGLE_INSTANCE, IRP_MN_CHANGE_SINGLE_INSTANCE, IRP_MN_CHANGE_SINGLE_ITEM, IRP_MN_ENABLE_EVENTS, IRP_MN_DISABLE_EVENTS, IRP_MN_ENABLE_COLLECTION, IRP_MN_DISABLE_COLLECTION, IRP_MN_REGINFO, IRP_MN_EXECUTE_METHOD, IRP_MN_Reserved_0a, IRP_MN_REGINFO_EX) );
CUSTOM_TYPE(pnpmj, ItemListByte(IRP_MJ_CREATE,IRP_MJ_CREATE_NAMED_PIPE,IRP_MJ_CLOSE,IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_QUERY_INFORMATION,IRP_MJ_SET_INFORMATION,IRP_MJ_QUERY_EA,IRP_MJ_SET_EA,IRP_MJ_FLUSH_BUFFERS,IRP_MJ_QUERY_VOLUME_INFORMATION,IRP_MJ_SET_VOLUME_INFORMATION,IRP_MJ_DIRECTORY_CONTROL,IRP_MJ_FILE_SYSTEM_CONTROL,IRP_MJ_DEVICE_CONTROL,IRP_MJ_INTERNAL_DEVICE_CONTROL,IRP_MJ_SHUTDOWN,IRP_MJ_LOCK_CONTROL,IRP_MJ_CLEANUP,IRP_MJ_CREATE_MAILSLOT,IRP_MJ_QUERY_SECURITY,IRP_MJ_SET_SECURITY,IRP_MJ_POWER,IRP_MJ_SYSTEM_CONTROL,IRP_MJ_DEVICE_CHANGE,IRP_MJ_QUERY_QUOTA,IRP_MJ_SET_QUOTA,IRP_MJ_PNP) );
# Built-in levels (for use with manifests)
DEFINE_BUILTIN_LEVEL(win:LogAlways, 0, WINEVENT_LEVEL_LOG_ALWAYS);
DEFINE_BUILTIN_LEVEL(win:Critical, 1, WINEVENT_LEVEL_CRITICAL, TRACE_LEVEL_CRITICAL);
DEFINE_BUILTIN_LEVEL(win:Error, 2, WINEVENT_LEVEL_ERROR, TRACE_LEVEL_ERROR);
DEFINE_BUILTIN_LEVEL(win:Warning, 3, WINEVENT_LEVEL_WARNING, TRACE_LEVEL_WARNING);
DEFINE_BUILTIN_LEVEL(win:Informational, 4, WINEVENT_LEVEL_INFO, TRACE_LEVEL_INFORMATION);
DEFINE_BUILTIN_LEVEL(win:Verbose, 5, WINEVENT_LEVEL_VERBOSE, TRACE_LEVEL_VERBOSE);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel6, 6, WINEVENT_LEVEL_RESERVED_6);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel7, 7, WINEVENT_LEVEL_RESERVED_7);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel8, 8, WINEVENT_LEVEL_RESERVED_8);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel9, 9, WINEVENT_LEVEL_RESERVED_9);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel10, 10, WINEVENT_LEVEL_RESERVED_10);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel11, 11, WINEVENT_LEVEL_RESERVED_11);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel12, 12, WINEVENT_LEVEL_RESERVED_12);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel13, 13, WINEVENT_LEVEL_RESERVED_13);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel14, 14, WINEVENT_LEVEL_RESERVED_14);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel15, 15, WINEVENT_LEVEL_RESERVED_15);
# Built-in keywords (for use with manifests)
DEFINE_BUILTIN_KEYWORD(win:AnyKeyword, 0x0, WINEVT_KEYWORD_ANY);
DEFINE_BUILTIN_KEYWORD(win:ResponseTime, 0x0001000000000000, WINEVENT_KEYWORD_RESPONSE_TIME);
DEFINE_BUILTIN_KEYWORD(win:WDIContext, 0x0002000000000000, WINEVENT_KEYWORD_WDI_CONTEXT);
DEFINE_BUILTIN_KEYWORD(win:WDIDiag, 0x0004000000000000, WINEVENT_KEYWORD_WDI_DIAG);
DEFINE_BUILTIN_KEYWORD(win:SQM, 0x0008000000000000, WINEVENT_KEYWORD_SQM);
DEFINE_BUILTIN_KEYWORD(win:AuditFailure, 0x0010000000000000, WINEVENT_KEYWORD_AUDIT_FAILURE);
DEFINE_BUILTIN_KEYWORD(win:AuditSuccess, 0x0020000000000000, WINEVENT_KEYWORD_AUDIT_SUCCESS);
DEFINE_BUILTIN_KEYWORD(win:CorrelationHint, 0x0040000000000000, WINEVENT_KEYWORD_CORRELATION_HINT);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword56, 0x0100000000000000, WINEVENT_KEYWORD_RESERVED_56);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword57, 0x0200000000000000, WINEVENT_KEYWORD_RESERVED_57);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword58, 0x0400000000000000, WINEVENT_KEYWORD_RESERVED_58);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword59, 0x0800000000000000, WINEVENT_KEYWORD_RESERVED_59);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword60, 0x1000000000000000, WINEVENT_KEYWORDE_RESERVED_60);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword61, 0x2000000000000000, WINEVENT_KEYWORD_RESERVED_61);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword62, 0x4000000000000000, WINEVENT_KEYWORD_RESERVED_62);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword63, 0x8000000000000000, WINEVENT_KEYWORD_RESERVED_63);
# default tracing macros
FUNC DoTraceMessage(LEVEL,MSG,...); # Uses WPP-provided ENABLED/LOGGER macros
FUNC DoDebugTrace(TRACELEVEL,MSG,...); # Requires used-defined ENABLED/LOGGER macros
# default prefix (use traceprt default)
USEPREFIX(*,"%!STDPREFIX!"); # traceprt will add standard prefix
# the source file that calls WPP_INIT_TRACING is given special treatment
WPP_FLAGS(-lookfor:WPP_INIT_TRACING);
@@ -0,0 +1,73 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
`* Dump definitions specified via -D on the command line to WPP *`
`FORALL def IN MacroDefinitions`
#define `def.Name` `def.Alias`
`ENDFOR`
#define WPP_THIS_FILE `SourceFile.CanonicalName`
#ifndef WPP_IsValidSid
#define WPP_IsValidSid IsValidSid
#endif
#ifndef WPP_GetLengthSid
#define WPP_GetLengthSid GetLengthSid
#endif
#if !defined(WPP_KERNEL_MODE)
# include <windows.h>
# pragma warning(disable: 4201)
# include <wmistr.h>
# include <evntrace.h>
# define WPP_TRACE TraceMessage
#else
#define WPP_TRACE WmiTraceMessage
#endif
#if !defined(WPP_PRIVATE)
# define WPP_INLINE __inline
# define WPP_SELECT_ANY extern "C" __declspec(selectany)
#else
# define WPP_INLINE static
# define WPP_SELECT_ANY static
#endif
__inline TRACEHANDLE WppQueryLogger(_In_opt_ PCWSTR LoggerName)
{
{
#if defined(WPP_KERNEL_MODE)
ULONG ReturnLength ;
NTSTATUS Status ;
TRACEHANDLE TraceHandle ;
UNICODE_STRING Buffer ;
RtlInitUnicodeString(&Buffer, LoggerName ? LoggerName : L"stdout");
if ((Status = WmiQueryTraceInformation(TraceHandleByNameClass,
(PVOID)&TraceHandle,
sizeof(TraceHandle),
&ReturnLength,
(PVOID)&Buffer)) == STATUS_SUCCESS) {
return TraceHandle ;
}
#else
ULONG status;
EVENT_TRACE_PROPERTIES LoggerInfo;
ZeroMemory(&LoggerInfo, sizeof(LoggerInfo));
LoggerInfo.Wnode.BufferSize = sizeof(LoggerInfo);
LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
status = QueryTraceW(0, LoggerName ? LoggerName : L"stdout", &LoggerInfo);
if (status == ERROR_SUCCESS || status == ERROR_MORE_DATA) {
return (TRACEHANDLE) LoggerInfo.Wnode.HistoricalContext;
}
#endif
}
return 0;
}
@@ -0,0 +1,20 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// `Compiler.Checksum` Generated file. Do not edit.
// File created by `Compiler.Name` compiler version `Compiler.Version`
// from template `TemplateFile`
#pragma once
`INCLUDE km-header.tpl`
`INCLUDE control.tpl`
`INCLUDE tracemacro.tpl`
`IF FOUND WPP_INIT_TRACING`
` INCLUDE km-init.tpl`
`ENDIF`
@@ -0,0 +1,284 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
#ifdef WPP_THIS_FILE
// included twice
# define WPP_ALREADY_INCLUDED
# undef WPP_THIS_FILE
#endif // #ifdef WPP_THIS_FILE
#define WPP_THIS_FILE `SourceFile.CanonicalName`
#ifndef WPP_ALREADY_INCLUDED
`* Dump the definitions specified via -D on the command line to WPP *`
`FORALL def IN MacroDefinitions`
#define `def.Name` `def.Alias`
`ENDFOR`
#include <evntrace.h>
#include <stddef.h>
#include <stdarg.h>
#include <wmistr.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef
LONG
(*PFN_WPPQUERYTRACEINFORMATION) (
IN TRACE_INFORMATION_CLASS TraceInformationClass,
OUT PVOID TraceInformation,
IN ULONG TraceInformationLength,
OUT PULONG RequiredLength OPTIONAL,
IN PVOID Buffer OPTIONAL
);
typedef
LONG
(*PFN_WPPTRACEMESSAGE)(
IN ULONG64 LoggerHandle,
IN ULONG MessageFlags,
IN LPCGUID MessageGuid,
IN USHORT MessageNumber,
IN ...
);
typedef enum _WPP_TRACE_API_SUITE {
WppTraceDisabledSuite,
WppTraceWin2K,
WppTraceWinXP,
WppTraceTraceLH,
WppTraceServer08,
WppTraceMaxSuite
} WPP_TRACE_API_SUITE;
_IRQL_requires_same_
typedef
VOID
(NTAPI *PETW_CLASSIC_CALLBACK)(
_In_ LPCGUID Guid,
_In_ UCHAR ControlCode,
_In_ PVOID EnableContext,
_In_opt_ PVOID CallbackContext
);
_IRQL_requires_same_
typedef
NTSTATUS
NTKERNELAPI
(FN_ETWREGISTERCLASSICPROVIDER)(
_In_ LPCGUID ProviderGuid,
_In_ ULONG Type,
_In_ PETW_CLASSIC_CALLBACK EnableCallback,
_In_opt_ PVOID CallbackContext,
_Out_ PREGHANDLE RegHandle
);
typedef FN_ETWREGISTERCLASSICPROVIDER *PFN_ETWREGISTERCLASSICPROVIDER;
typedef
BOOLEAN
NTKERNELAPI
(FN_WPPGETVERSION)(
_Out_opt_ PULONG MajorVersion,
_Out_opt_ PULONG MinorVersion,
_Out_opt_ PULONG BuildNumber,
_Out_opt_ PUNICODE_STRING CSDVersion
);
typedef FN_WPPGETVERSION *PFN_WPPGETVERSION;
typedef
NTSTATUS
NTKERNELAPI
(FN_ETWUNREGISTER)(
_In_ REGHANDLE RegHandle
);
typedef FN_ETWUNREGISTER *PFN_ETWUNREGISTER;
#pragma prefast(suppress:__WARNING_ENCODE_GLOBAL_FUNCTION_POINTER, "this pointer can not be encoded");
__declspec(selectany) PFN_WPPQUERYTRACEINFORMATION pfnWppQueryTraceInformation = NULL;
#pragma prefast(suppress:__WARNING_ENCODE_GLOBAL_FUNCTION_POINTER, "this pointer can not be encoded");
__declspec(selectany) PFN_WPPTRACEMESSAGE pfnWppTraceMessage = NULL;
#pragma prefast(suppress:__WARNING_ENCODE_GLOBAL_FUNCTION_POINTER, "this pointer can not be encoded");
__declspec(selectany) PFN_ETWUNREGISTER pfnEtwUnregister = NULL;
#pragma prefast(suppress:__WARNING_ENCODE_GLOBAL_FUNCTION_POINTER, "this pointer can not be encoded");
__declspec(selectany) PFN_ETWREGISTERCLASSICPROVIDER pfnEtwRegisterClassicProvider = NULL;
#pragma prefast(suppress:__WARNING_ENCODE_GLOBAL_FUNCTION_POINTER, "this pointer can not be encoded");
__declspec(selectany) PFN_WPPGETVERSION pfnWppGetVersion = NULL;
__declspec(selectany) WPP_TRACE_API_SUITE WPPTraceSuite = WppTraceDisabledSuite;
#if !defined(_NTRTL_)
#if !defined(_NTHAL_)
// fake RTL_TIME_ZONE_INFORMATION //
typedef int RTL_TIME_ZONE_INFORMATION;
#endif
#define _WMIKM_
#endif
#ifndef WPP_TRACE
#define WPP_TRACE pfnWppTraceMessage
#endif
#if ENABLE_WPP_RECORDER
#define _ENABLE_WPP_RECORDER TRUE
#ifndef WPP_RECORDER
#define WPP_RECORDER WppAutoLogTrace
#endif
//
// This setting is only applicable when IFR is enabled.
// Setting this to 1 will allow a WPP trace session to
// capture trace messages as usual i.e it will require the
// user to provide WPP trace ENABLED and LOGGER macro. If
// this is set to 0 by default the IFR trace filter also
// affects which trace messages land in the WPP trace session.
//
#if !defined(ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER)
#define ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER 0
#endif
#if !defined(WPP_RECORDER_LEVEL_FLAGS_ARGS)
#define WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags) WPP_CONTROL(WPP_BIT_ ## flags).AutoLogContext, lvl, WPP_BIT_ ## flags
#define WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl,flags) (lvl < TRACE_LEVEL_VERBOSE || WPP_CONTROL(WPP_BIT_ ## flags).AutoLogVerboseEnabled)
#endif
#if !defined(WPP_RECORDER_LEVEL_ARGS)
#define WPP_RECORDER_LEVEL_ARGS(lvl) WPP_CONTROL(WPP_BIT_ ## lvl).AutoLogContext, 0, WPP_BIT_ ## lvl
#define WPP_RECORDER_LEVEL_FILTER(lvl) (WPP_CONTROL(WPP_BIT_ ## lvl).AutoLogVerboseEnabled)
#endif
NTSTATUS
WppAutoLogTrace(
IN PVOID AutoLogContext,
IN UCHAR MessageLevel,
IN ULONG MessageFlags,
IN LPGUID MessageGuid,
IN USHORT MessageNumber,
IN ...
);
#else
#define _ENABLE_WPP_RECORDER FALSE
#endif
VOID
WppLoadTracingSupport(
VOID
);
NTSTATUS
WppTraceCallback(
_In_ UCHAR MinorFunction,
_In_opt_ PVOID DataPath,
_In_ ULONG BufferLength,
_Inout_updates_bytes_(BufferLength) PVOID Buffer,
_Inout_ PVOID Context,
_Out_ PULONG Size
);
#if !defined(WPP_TRACE_CONTROL_NULL_GUID)
DEFINE_GUID(WPP_TRACE_CONTROL_NULL_GUID, 0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
#endif
#define WPP_TRACE_CONTROL(Function,Buffer,BufferSize,ReturnSize) WppTraceCallback(Function,NULL,BufferSize,Buffer,&WPP_CB[0],&ReturnSize);
__inline ULONG64 WppQueryLogger(_In_opt_ PCWSTR LoggerName)
{
if (WppTraceWinXP != WPPTraceSuite) {
return (ULONG64)0;
}
ULONG ReturnLength;
LONG Status;
ULONG64 TraceHandle;
UNICODE_STRING Buffer;
RtlInitUnicodeString(&Buffer, LoggerName ? LoggerName : L"stdout");
Status = pfnWppQueryTraceInformation(TraceHandleByNameClass,
(PVOID)&TraceHandle,
sizeof(TraceHandle),
&ReturnLength,
(PVOID)&Buffer
);
if (Status != STATUS_SUCCESS) {
return (ULONG64)0;
}
return TraceHandle;
}
typedef LONG (*WMIENTRY_NEW)(
_In_ UCHAR MinorFunction,
_In_opt_ PVOID DataPath,
_In_ ULONG BufferLength,
_Inout_updates_bytes_(BufferLength) PVOID Buffer,
_In_ PVOID Context,
_Out_ PULONG Size
);
typedef struct _WPP_TRACE_CONTROL_BLOCK
{
WMIENTRY_NEW Callback;
LPCGUID ControlGuid;
struct _WPP_TRACE_CONTROL_BLOCK *Next;
__int64 Logger;
PUNICODE_STRING RegistryPath;
UCHAR FlagsLen;
UCHAR Level;
USHORT Reserved;
ULONG Flags[1];
ULONG ReservedFlags;
REGHANDLE RegHandle;
#if ENABLE_WPP_RECORDER
PVOID AutoLogContext;
USHORT AutoLogVerboseEnabled;
USHORT AutoLogAttachToMiniDump;
#endif
} WPP_TRACE_CONTROL_BLOCK, *PWPP_TRACE_CONTROL_BLOCK;
VOID WppCleanupKm(_When_(_ENABLE_WPP_RECORDER, _In_) _When_(!_ENABLE_WPP_RECORDER, _In_opt_) PDRIVER_OBJECT DriverObject);
#define WPP_CLEANUP(DriverObject) WppCleanupKm((PDRIVER_OBJECT)DriverObject)
#define WPP_IsValidSid RtlValidSid
#define WPP_GetLengthSid RtlLengthSid
//
// Callback routine to be defined by the driver, which will be called from WPP callback
// WPP will pass current valued of : GUID, Logger, Enable, Flags, and Level
//
// To activate driver must define WPP_PRIVATE_ENABLE_CALLBACK in their code, sample below
// #define WPP_PRIVATE_ENABLE_CALLBACK MyPrivateCallback;
//
typedef
VOID
(*PFN_WPP_PRIVATE_ENABLE_CALLBACK)(
_In_ LPCGUID Guid,
_In_ __int64 Logger,
_In_ BOOLEAN Enable,
_In_ ULONG Flags,
_In_ UCHAR Level);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // #ifndef WPP_ALREADY_INCLUDED
@@ -0,0 +1,989 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
//
// Defines a set of functions that simplifies
// kernel mode registration for tracing
//
#pragma warning(disable: 4201)
#include <ntddk.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WPPINIT_EXPORT
#define WPPINIT_EXPORT
#endif
#ifndef WppDebug
#define WppDebug(a,b)
#endif
WPPINIT_EXPORT
VOID
WppInitGlobalLogger(
_In_ LPCGUID ControlGuid,
_Out_ PTRACEHANDLE LoggerHandle,
_Out_ PULONG Flags,
_Out_ PUCHAR Level
);
WPPINIT_EXPORT
VOID
WppInitKm(
_When_(_ENABLE_WPP_RECORDER, _In_) _When_(!_ENABLE_WPP_RECORDER, _In_opt_) PDRIVER_OBJECT DriverObject,
_When_(_ENABLE_WPP_RECORDER, _In_) _When_(!_ENABLE_WPP_RECORDER, _In_opt_) PCUNICODE_STRING RegPath
);
#if ENABLE_WPP_RECORDER
WPPINIT_EXPORT
VOID
WppAutoLogStart(
_In_ WPP_CB_TYPE * WppCb,
_In_ PDRIVER_OBJECT DrvObj,
_In_ PCUNICODE_STRING RegPath
);
VOID
WppAutoLogStop(
_In_ WPP_CB_TYPE * WppCb,
_In_ PDRIVER_OBJECT DrvObj
);
VOID
imp_WppRecorderReplay(
_In_ PVOID WppCb,
_In_ TRACEHANDLE WppTraceHandle,
_In_ ULONG EnableFlags,
_In_ UCHAR EnableLevel
);
#ifndef ENABLE_WPP_RECORDER_REPLAY
#define ENABLE_WPP_RECORDER_REPLAY 1
#endif
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, WppLoadTracingSupport)
#pragma alloc_text( PAGE, WppInitGlobalLogger)
#pragma alloc_text( PAGE, WppTraceCallback)
#pragma alloc_text( PAGE, WppInitKm)
#pragma alloc_text( PAGE, WppCleanupKm)
#endif // ALLOC_PRAGMA
// define annotation record that will carry control information to pdb (in case somebody needs it)
WPP_FORCEINLINE void WPP_CONTROL_ANNOTATION() {
#if !defined(WPP_NO_ANNOTATIONS)
#ifndef WPP_TMC_ANNOT_SUFIX
#ifdef WPP_PUBLIC_TMC
#define WPP_TMC_ANNOT_SUFIX ,L"PUBLIC_TMF:"
#else
#define WPP_TMC_ANNOT_SUFIX
#endif
#endif
# define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) __annotation(L"TMC:", WPP_GUID_WTEXT Guid, _WPPW(WPP_STRINGIZE(Name)) Bits WPP_TMC_ANNOT_SUFIX);
# define WPP_DEFINE_BIT(Name) , _WPPW(#Name)
WPP_CONTROL_GUIDS
# undef WPP_DEFINE_BIT
# undef WPP_DEFINE_CONTROL_GUID
#endif
}
#define WPP_NEXT(Name) ((WPP_TRACE_CONTROL_BLOCK*) \
(WPP_XGLUE(WPP_CTL_, WPP_EVAL(Name)) + 1 == WPP_LAST_CTL ? 0:WPP_MAIN_CB + WPP_XGLUE(WPP_CTL_, WPP_EVAL(Name)) + 1))
#if ENABLE_WPP_RECORDER
#define INIT_WPP_RECORDER(Arr) \
Arr->Control.AutoLogContext = NULL; \
Arr->Control.AutoLogVerboseEnabled = 0x0; \
Arr->Control.AutoLogAttachToMiniDump = 0x0;
#else
#define INIT_WPP_RECORDER(Arr)
#endif
WPP_CB_TYPE WPP_MAIN_CB[WPP_LAST_CTL];
__inline void WPP_INIT_CONTROL_ARRAY(WPP_CB_TYPE* Arr) {
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) \
Arr->Control.Callback = NULL; \
Arr->Control.ControlGuid = WPP_XGLUE4(&WPP_, ThisDir, _CTLGUID_, WPP_EVAL(Name)); \
Arr->Control.Next = WPP_NEXT(WPP_EVAL(Name)); \
Arr->Control.RegistryPath= NULL; \
Arr->Control.FlagsLen = WPP_FLAG_LEN; \
Arr->Control.Level = 0; \
Arr->Control.Reserved = 0; \
Arr->Control.Flags[0] = 0; \
INIT_WPP_RECORDER(Arr) \
++Arr;
#define WPP_DEFINE_BIT(BitName) L" " L ## #BitName
WPP_CONTROL_GUIDS
#undef WPP_DEFINE_BIT
#undef WPP_DEFINE_CONTROL_GUID
}
#undef WPP_INIT_STATIC_DATA
#define WPP_INIT_STATIC_DATA WPP_INIT_CONTROL_ARRAY(WPP_MAIN_CB)
// define WPP_INIT_TRACING. For performance reasons turn off during
// static analysis compilation with Static Driver Verifier (SDV).
#ifndef _SDV_
#define WPP_INIT_TRACING(DriverObject, RegPath) \
{ \
WppDebug(0,("WPP_INIT_TRACING: &WPP_CB[0] %p\n", &WPP_MAIN_CB[0])); \
WPP_INIT_STATIC_DATA; \
WppLoadTracingSupport(); \
( WPP_CONTROL_ANNOTATION(), \
WPP_MAIN_CB[0].Control.RegistryPath = NULL, \
WppInitKm( (PDRIVER_OBJECT)DriverObject, RegPath ) \
); \
}
#else
#define WPP_INIT_TRACING(DriverObject, RegPath)
#endif
#define WMIREG_FLAG_CALLBACK 0x80000000 // not exposed in DDK
#ifndef WMIREG_FLAG_TRACE_PROVIDER
#define WMIREG_FLAG_TRACE_PROVIDER 0x00010000
#endif
//
// Public routines to break down the Loggerhandle
//
#if !defined(KERNEL_LOGGER_ID)
#define KERNEL_LOGGER_ID 0xFFFF // USHORT only
#endif
typedef struct _WPP_TRACE_ENABLE_CONTEXT {
USHORT LoggerId; // Actual Id of the logger
UCHAR Level; // Enable level passed by control caller
UCHAR InternalFlag; // Reserved
ULONG EnableFlags; // Enable flags passed by control caller
} WPP_TRACE_ENABLE_CONTEXT, *PWPP_TRACE_ENABLE_CONTEXT;
#if !defined(WmiGetLoggerId)
#define WmiGetLoggerId(LoggerContext) \
(((PWPP_TRACE_ENABLE_CONTEXT) (&LoggerContext))->LoggerId == \
(USHORT)KERNEL_LOGGER_ID) ? \
KERNEL_LOGGER_ID : \
((PWPP_TRACE_ENABLE_CONTEXT) (&LoggerContext))->LoggerId
#define WmiGetLoggerEnableFlags(LoggerContext) \
((PWPP_TRACE_ENABLE_CONTEXT) (&LoggerContext))->EnableFlags
#define WmiGetLoggerEnableLevel(LoggerContext) \
((PWPP_TRACE_ENABLE_CONTEXT) (&LoggerContext))->Level
#endif
__inline int WppIsEqualGuid(_In_ const GUID* g1, _In_ const GUID* g2)
{
const ULONG* p1 = (const ULONG*)g1;
const ULONG* p2 = (const ULONG*)g2;
return p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2] && p1[3] == p2[3];
}
VOID
WppLoadTracingSupport(
VOID
)
/*++
Routine Description:
This function assigns at runtime the ETW API set to be use for tracing.
Arguments:
Remarks:
At runtime determine assing the funtions pointers for the trace APIs to be use.
XP and above will use TraceMessage, and Win2K is not supported.
--*/
{
ULONG MajorVersion = 0;
UNICODE_STRING name;
PAGED_CODE();
RtlInitUnicodeString(&name, L"PsGetVersion");
pfnWppGetVersion = (PFN_WPPGETVERSION) (INT_PTR)
MmGetSystemRoutineAddress(&name);
RtlInitUnicodeString(&name, L"WmiTraceMessage");
pfnWppTraceMessage = (PFN_WPPTRACEMESSAGE) (INT_PTR)
MmGetSystemRoutineAddress(&name);
//
// WinXp
//
RtlInitUnicodeString(&name, L"WmiQueryTraceInformation");
pfnWppQueryTraceInformation = (PFN_WPPQUERYTRACEINFORMATION) (INT_PTR)
MmGetSystemRoutineAddress(&name);
WPPTraceSuite = WppTraceWinXP;
//
// Server08
//
if (pfnWppGetVersion != NULL) {
pfnWppGetVersion(&MajorVersion,
NULL,
NULL,
NULL);
}
if (MajorVersion >= 6) {
RtlInitUnicodeString(&name, L"EtwRegisterClassicProvider");
pfnEtwRegisterClassicProvider = (PFN_ETWREGISTERCLASSICPROVIDER) (INT_PTR)
MmGetSystemRoutineAddress(&name);
if (pfnEtwRegisterClassicProvider != NULL) {
//
// For Vista SP1 and later
//
RtlInitUnicodeString(&name, L"EtwUnregister");
pfnEtwUnregister = (PFN_ETWUNREGISTER) (INT_PTR)
MmGetSystemRoutineAddress(&name);
WPPTraceSuite = WppTraceServer08;
}
}
}
#ifdef WPP_GLOBALLOGGER
#define DEFAULT_GLOBAL_LOGGER_KEY L"WMI\\GlobalLogger\\"
#define WPP_TEXTGUID_LEN 38
#define GREGVALUENAMELENGTH (18 + WPP_TEXTGUID_LEN) // wslen(L"WMI\\GlobalLogger\\") + GUIDLENGTH
WPPINIT_EXPORT
VOID
WppInitGlobalLogger(
_In_ LPCGUID ControlGuid,
_Out_ PTRACEHANDLE LoggerHandle,
_Out_ PULONG Flags,
_Out_ PUCHAR Level
)
{
WCHAR GRegValueName[GREGVALUENAMELENGTH];
RTL_QUERY_REGISTRY_TABLE Parms[3];
ULONG CurrentFlags = 0;
ULONG CurrentLevel = 0;
ULONG Start = 0;
NTSTATUS Status;
ULONG Zero = 0;
UNICODE_STRING GuidString;
PAGED_CODE();
WppDebug(0,("WPP checking Global Logger\n"));
//
// Fill in the query table to find out if the Global Logger is Started
//
// Trace Flags
Parms[0].QueryRoutine = NULL;
Parms[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
Parms[0].Name = L"Start";
Parms[0].EntryContext = &Start;
Parms[0].DefaultType = REG_DWORD;
Parms[0].DefaultData = &Zero;
Parms[0].DefaultLength = sizeof(ULONG);
// Termination
Parms[1].QueryRoutine = NULL;
Parms[1].Flags = 0;
//
// Perform the query
//
Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL | RTL_REGISTRY_OPTIONAL,
DEFAULT_GLOBAL_LOGGER_KEY,
Parms,
NULL,
NULL);
if (!NT_SUCCESS(Status) || Start == 0 ) {
return;
}
// Fill in the query table to find out if we should use the Global logger
//
// Trace Flags
Parms[0].QueryRoutine = NULL;
Parms[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
Parms[0].Name = L"Flags";
Parms[0].EntryContext = &CurrentFlags;
Parms[0].DefaultType = REG_DWORD;
Parms[0].DefaultData = &Zero;
Parms[0].DefaultLength = sizeof(ULONG);
// Trace level
Parms[1].QueryRoutine = NULL;
Parms[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
Parms[1].Name = L"Level";
Parms[1].EntryContext = &CurrentLevel;
Parms[1].DefaultType = REG_DWORD;
Parms[1].DefaultData = &Zero;
Parms[1].DefaultLength = sizeof(UCHAR);
// Termination
Parms[2].QueryRoutine = NULL;
Parms[2].Flags = 0;
RtlCopyMemory(GRegValueName, DEFAULT_GLOBAL_LOGGER_KEY, (wcslen(DEFAULT_GLOBAL_LOGGER_KEY)+1) *sizeof(WCHAR));
#if defined(__cplusplus)
Status = RtlStringFromGUID(*ControlGuid, &GuidString);
#else
Status = RtlStringFromGUID(ControlGuid, &GuidString);
#endif
if( Status != STATUS_SUCCESS ) {
WppDebug(0,("WPP GlobalLogger failed RtlStringFromGUID \n"));
return;
}
if (GuidString.Length > (WPP_TEXTGUID_LEN * sizeof(WCHAR))){
WppDebug(0,("WPP GlobalLogger RtlStringFromGUID too large\n"));
RtlFreeUnicodeString(&GuidString);
return;
}
// got the GUID in form "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
// need GUID in form "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
// copy the translated GUID string
RtlCopyMemory(&GRegValueName[(ULONG)wcslen(GRegValueName)], &GuidString.Buffer[1], GuidString.Length);
GRegValueName[(ULONG)wcslen(GRegValueName) - 1] = L'\0';
RtlFreeUnicodeString(&GuidString);
//
// Perform the query
//
Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL | RTL_REGISTRY_OPTIONAL,
GRegValueName,
Parms,
NULL,
NULL);
if (NT_SUCCESS(Status)) {
if (Start==1) {
*LoggerHandle= WMI_GLOBAL_LOGGER_ID;
*Flags = CurrentFlags & 0x7FFFFFFF;
*Level = (UCHAR)(CurrentLevel & 0xFF);
WppDebug(0,("WPP Enabled via Global Logger Flags=0x%08X Level=0x%02X\n",CurrentFlags,CurrentLevel));
}
} else {
WppDebug(0,("WPP GlobalLogger has No Flags/Levels Status=%08X\n",Status));
}
}
#endif //#ifdef WPP_GLOBALLOGGER
#define WPP_MAX_COUNT_REGISTRATION_GUID 63
WPPINIT_EXPORT
NTSTATUS
WppTraceCallback(
_In_ UCHAR MinorFunction,
_In_opt_ PVOID DataPath,
_In_ ULONG BufferLength,
_Inout_updates_bytes_(BufferLength) PVOID Buffer,
_Inout_ PVOID Context,
_Out_ PULONG Size
)
/*++
Routine Description:
This function is the callback WMI calls when we register and when our
events are enabled or disabled.
Arguments:
MinorFunction - specifies the type of callback (register, event enable/disable)
DataPath - varies depending on the ActionCode
BufferLength - size of the Buffer parameter
Buffer - in/out buffer where we read from or write to depending on the type
of callback
Context - the pointer private struct WPP_TRACE_CONTROL_BLOCK
Size - output parameter to receive the amount of data written into Buffer
Return Value:
NTSTATUS code indicating success/failure
Comments:
if return value is STATUS_BUFFER_TOO_SMALL and BufferLength >= 4,
then first ulong of buffer contains required size
--*/
{
PWPP_TRACE_CONTROL_BLOCK cntl;
NTSTATUS Status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(DataPath);
PAGED_CODE();
WppDebug(0,("WppTraceCallBack 0x%08X %p\n", MinorFunction, Context));
*Size = 0;
switch(MinorFunction)
{
case IRP_MN_REGINFO:
{
PWMIREGINFOW WmiRegInfo;
PCUNICODE_STRING RegPath;
PWCHAR StringPtr;
ULONG RegistryPathOffset;
ULONG BufferNeeded;
ULONG GuidCount = 0;
//
// Initialize locals
//
cntl = (PWPP_TRACE_CONTROL_BLOCK)Context;
WmiRegInfo = (PWMIREGINFO)Buffer;
RegPath = cntl->RegistryPath;
//
// Count the number of guid to be identified.
//
while(cntl) { GuidCount++; cntl = cntl->Next; }
if (GuidCount > WPP_MAX_COUNT_REGISTRATION_GUID){
Status = STATUS_INVALID_PARAMETER;
break;
}
WppDebug(0,("WppTraceCallBack: GUID count %d\n", GuidCount));
//
// Calculate buffer size need to hold all info.
// Calculate offset to where RegistryPath parm will be copied.
//
if (RegPath == NULL)
{
RegistryPathOffset = 0;
BufferNeeded = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) +
GuidCount * sizeof(WMIREGGUIDW);
} else {
RegistryPathOffset = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) +
GuidCount * sizeof(WMIREGGUIDW);
BufferNeeded = RegistryPathOffset +
RegPath->Length + sizeof(USHORT);
}
//
// If the provided buffer is large enough, then fill with info.
//
if (BufferNeeded <= BufferLength)
{
ULONG i;
RtlZeroMemory(Buffer, BufferLength);
//
// Fill in the WMIREGINFO
//
WmiRegInfo->BufferSize = BufferNeeded;
WmiRegInfo->RegistryPath = RegistryPathOffset;
WmiRegInfo->GuidCount = GuidCount;
if (RegPath != NULL) {
StringPtr = (PWCHAR)((PUCHAR)Buffer + RegistryPathOffset);
*StringPtr++ = RegPath->Length;
RtlCopyMemory(StringPtr, RegPath->Buffer, RegPath->Length);
}
//
// Fill in the WMIREGGUID
//
cntl = (PWPP_TRACE_CONTROL_BLOCK) Context;
for (i=0; i<GuidCount; i++) {
WmiRegInfo->WmiRegGuid[i].Guid = *cntl->ControlGuid;
WmiRegInfo->WmiRegGuid[i].Flags = WMIREG_FLAG_TRACE_CONTROL_GUID |
WMIREG_FLAG_TRACED_GUID;
cntl->Level = 0;
cntl->Flags[0] = 0;
WppDebug(0,("Control GUID::%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
cntl->ControlGuid->Data1,
cntl->ControlGuid->Data2,
cntl->ControlGuid->Data3,
cntl->ControlGuid->Data4[0],
cntl->ControlGuid->Data4[1],
cntl->ControlGuid->Data4[2],
cntl->ControlGuid->Data4[3],
cntl->ControlGuid->Data4[4],
cntl->ControlGuid->Data4[5],
cntl->ControlGuid->Data4[6],
cntl->ControlGuid->Data4[7]
));
cntl = cntl->Next;
}
Status = STATUS_SUCCESS;
*Size = BufferNeeded;
} else {
Status = STATUS_BUFFER_TOO_SMALL;
if (BufferLength >= sizeof(ULONG)) {
*((PULONG)Buffer) = BufferNeeded;
*Size = sizeof(ULONG);
}
}
#ifdef WPP_GLOBALLOGGER
// Check if Global logger is active
cntl = (PWPP_TRACE_CONTROL_BLOCK) Context;
while(cntl) {
WppInitGlobalLogger(
cntl->ControlGuid,
(PTRACEHANDLE)&cntl->Logger,
&cntl->Flags[0],
&cntl->Level);
cntl = cntl->Next;
}
#endif //#ifdef WPP_GLOBALLOGGER
break;
}
case IRP_MN_ENABLE_EVENTS:
case IRP_MN_DISABLE_EVENTS:
{
PWNODE_HEADER Wnode;
ULONG Level;
ULONG ReturnLength;
ULONG index;
if (Context == NULL ) {
Status = STATUS_WMI_GUID_NOT_FOUND;
break;
}
if (BufferLength < sizeof(WNODE_HEADER)) {
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Initialize locals
//
Wnode = (PWNODE_HEADER)Buffer;
//
// Traverse this ProjectControlBlock's ControlBlock list and
// find the "cntl" ControlBlock which matches the Wnode GUID.
//
cntl = (PWPP_TRACE_CONTROL_BLOCK) Context;
index = 0;
while(cntl) {
if (WppIsEqualGuid(cntl->ControlGuid, &Wnode->Guid )) {
break;
}
index++;
cntl = cntl->Next;
}
if (cntl == NULL) {
Status = STATUS_WMI_GUID_NOT_FOUND;
break;
}
//
// Do the requested event action
//
Status = STATUS_SUCCESS;
if (MinorFunction == IRP_MN_DISABLE_EVENTS) {
WppDebug(0,("WppTraceCallBack: DISABLE_EVENTS\n"));
cntl->Level = 0;
cntl->Flags[0] = 0;
cntl->Logger = 0;
} else {
TRACEHANDLE lh;
lh = (TRACEHANDLE)( Wnode->HistoricalContext );
cntl->Logger = lh;
if (WppTraceWinXP == WPPTraceSuite) {
Status = pfnWppQueryTraceInformation( TraceEnableLevelClass,
&Level,
sizeof(Level),
&ReturnLength,
(PVOID)Wnode);
if (Status == STATUS_SUCCESS) {
cntl->Level = (UCHAR)Level;
}
Status = pfnWppQueryTraceInformation( TraceEnableFlagsClass,
&cntl->Flags[0],
sizeof(cntl->Flags[0]),
&ReturnLength,
(PVOID) Wnode );
} else {
cntl->Flags[0] = ((PWPP_TRACE_ENABLE_CONTEXT) &lh)->EnableFlags;
cntl->Level = (UCHAR) ((PWPP_TRACE_ENABLE_CONTEXT) &lh)->Level;
}
WppDebug(0,("WppTraceCallBack: ENABLE_EVENTS "
"LoggerId %d, Flags 0x%08X, Level 0x%02X\n",
(USHORT) cntl->Logger,
cntl->Flags[0],
cntl->Level));
}
#ifdef WPP_PRIVATE_ENABLE_CALLBACK
//
// Notify changes to flags, level for GUID
//
WPP_PRIVATE_ENABLE_CALLBACK( cntl->ControlGuid,
cntl->Logger,
(MinorFunction != IRP_MN_DISABLE_EVENTS) ? TRUE:FALSE,
cntl->Flags[0],
cntl->Level );
#endif
break;
}
case IRP_MN_ENABLE_COLLECTION:
case IRP_MN_DISABLE_COLLECTION:
{
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_ALL_DATA:
case IRP_MN_QUERY_SINGLE_INSTANCE:
case IRP_MN_CHANGE_SINGLE_INSTANCE:
case IRP_MN_CHANGE_SINGLE_ITEM:
case IRP_MN_EXECUTE_METHOD:
{
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
default:
{
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
}
return(Status);
}
VOID
NTAPI
WppClassicProviderCallback(
_In_ LPCGUID Guid,
_In_ UCHAR ControlCode,
_In_ PVOID EnableContext,
_Inout_ PVOID CallbackContext
)
/*++
Routine Description:
Enable callback function when EtwRegisterClassicProvider was used.
It happens in Windows Vista SP1 and newer.
Arguments:
Guid - provider guid.
ControlCode - code indicating operations request.
EnableContext - context from the ETW infrastructure.
CallbackContext - context from the user.
Return Value:
None.
--*/
{
PWPP_TRACE_CONTROL_BLOCK TraceCb = (PWPP_TRACE_CONTROL_BLOCK)CallbackContext;
PWPP_TRACE_ENABLE_CONTEXT TraceContext = (PWPP_TRACE_ENABLE_CONTEXT)EnableContext;
UNREFERENCED_PARAMETER (Guid);
WppDebug(0,("WppClassicProviderCallback %d\n", (int)ControlCode));
//
// Only handle enable and disable operations.
//
if ((ControlCode != EVENT_CONTROL_CODE_ENABLE_PROVIDER) &&
(ControlCode != EVENT_CONTROL_CODE_DISABLE_PROVIDER)) {
return;
}
if (ControlCode != EVENT_CONTROL_CODE_DISABLE_PROVIDER) {
TraceCb->Flags[0] = TraceContext->EnableFlags;
TraceCb->Level = (UCHAR)TraceContext->Level;
TraceCb->Logger = *((TRACEHANDLE*)TraceContext);
#if ENABLE_WPP_RECORDER
#if ENABLE_WPP_RECORDER_REPLAY && (NTDDI_VERSION >= NTDDI_WIN10_RS1)
imp_WppRecorderReplay(&WPP_CB[0], TraceCb->Logger, TraceContext->EnableFlags, TraceContext->Level);
#endif
#endif //#if ENABLE_WPP_RECORDER
WppDebug(0,("ENABLE: LoggerId=%d Flags=%08x Level=%02d\n", (int)TraceContext->LoggerId, TraceCb->Flags[0], TraceCb->Level));
} else {
TraceCb->Level = 0;
TraceCb->Flags[0] = 0;
TraceCb->Logger = 0;
}
#ifdef WPP_PRIVATE_ENABLE_CALLBACK
//
// Notify changes to flags, level for GUID
//
WppDebug(0,("WppClassicProviderCallback: calling private callback.\n"));
WPP_PRIVATE_ENABLE_CALLBACK(TraceCb->ControlGuid,
TraceCb->Logger,
ControlCode,
TraceCb->Flags[0],
TraceCb->Level);
#endif
}
#pragma warning(push)
#pragma warning(disable:4068)
WPPINIT_EXPORT
VOID
WppInitKm(
_When_(_ENABLE_WPP_RECORDER, _In_) _When_(!_ENABLE_WPP_RECORDER, _In_opt_) PDRIVER_OBJECT DriverObject,
_When_(_ENABLE_WPP_RECORDER, _In_) _When_(!_ENABLE_WPP_RECORDER, _In_opt_) PCUNICODE_STRING RegPath
)
/*++
Routine Description:
This function registers a driver with ETW as a provider of trace
events from the defined GUIDs.
Arguments:
DriverObject - Pointer to a driver object. This is required for WppRecorder
and is optional otherwise (not used unless it's for
WppRecorder).
RegPath - Optional pointer to registry path, needed for wpp recorder.
Remarks:
This function is called by the WPP_INIT_TRACING(DriverObject, RegPath) macro.
--*/
{
C_ASSERT(WPP_MAX_FLAG_LEN_CHECK);
NTSTATUS Status;
PWPP_TRACE_CONTROL_BLOCK WppReg = NULL;
PAGED_CODE();
UNREFERENCED_PARAMETER(DriverObject);
UNREFERENCED_PARAMETER(RegPath);
if (WPP_CB != WPP_MAIN_CB) {
WPP_CB = WPP_MAIN_CB;
} else {
//
// WPP_INIT_TRACING already called
//
WppDebug(0,("Warning : WPP_INIT_TRACING already called, ignoring this one"));
return;
}
WppReg = &WPP_CB[0].Control;
WppDebug(0,("WPP Init.\n"));
if (WppTraceServer08 == WPPTraceSuite) {
//
// Windows version >= Vista SP1
//
while (WppReg) {
WppReg->RegHandle = 0;
Status = pfnEtwRegisterClassicProvider(
WppReg->ControlGuid,
0,
WppClassicProviderCallback,
(PVOID)WppReg,
&WppReg->RegHandle);
if (!NT_SUCCESS(Status)) {
WppDebug(0,("EtwRegisterClassicProvider Status = %d, ControlBlock = %p.\n", Status, WppReg));
}
WppReg = WppReg->Next;
}
} else if (WppTraceWinXP == WPPTraceSuite) {
WppReg -> Callback = WppTraceCallback;
#pragma prefast(suppress:__WARNING_BANNED_API_ARGUMENT_USAGE, "WPP generated, requires legacy providers");
Status = IoWMIRegistrationControl(
(PDEVICE_OBJECT)WppReg,
WMIREG_ACTION_REGISTER |
WMIREG_FLAG_CALLBACK |
WMIREG_FLAG_TRACE_PROVIDER
);
if (!NT_SUCCESS(Status)) {
WppDebug(0,("IoWMIRegistrationControl Status = %08X\n",Status));
}
}
#if ENABLE_WPP_RECORDER
WppAutoLogStart(&WPP_CB[0], DriverObject, RegPath);
WPP_RECORDER_INITIALIZED = WPP_MAIN_CB;
#endif
}
WPPINIT_EXPORT
VOID
WppCleanupKm(
_When_(_ENABLE_WPP_RECORDER, _In_) _When_(!_ENABLE_WPP_RECORDER, _In_opt_) PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This function deregisters a driver from ETW as provider of trace
events.
Arguments:
DriverObject - Pointer to a driver object. This is required for WppRecorder
and is optional otherwise (not used unless it's for
WppRecorder).
Remarks:
This function is called by the WPP_CLEANUP(DriverObject) macro.
--*/
{
UNREFERENCED_PARAMETER(DriverObject);
PAGED_CODE();
if (WPP_CB == (WPP_CB_TYPE*)&WPP_CB){
//
// WPP_INIT_TRACING macro has not been called
//
WppDebug(0,("Warning : WPP_CLEANUP already called, or called with out WPP_INIT_TRACING first"));
return;
}
if (WppTraceServer08 == WPPTraceSuite) {
PWPP_TRACE_CONTROL_BLOCK WppReg = &WPP_CB[0].Control;
while (WppReg) {
if (WppReg->RegHandle) {
pfnEtwUnregister(WppReg->RegHandle);
WppDebug(0,("EtwUnregister RegHandle = %lld.\n",WppReg->RegHandle));
WppReg->RegHandle = 0;
} else {
WppDebug(0,("WppCleanupKm: invalid RegHandle.\n"));
}
WppReg = WppReg->Next;
}
} else if (WppTraceWinXP == WPPTraceSuite) {
PWPP_TRACE_CONTROL_BLOCK WppReg = &WPP_CB[0].Control;
IoWMIRegistrationControl( (PDEVICE_OBJECT)WppReg,
WMIREG_ACTION_DEREGISTER |
WMIREG_FLAG_CALLBACK );
}
#if ENABLE_WPP_RECORDER
WppAutoLogStop(&WPP_CB[0], DriverObject);
WPP_RECORDER_INITIALIZED = (WPP_CB_TYPE*) &WPP_RECORDER_INITIALIZED;
#endif
WPP_CB = (WPP_CB_TYPE*)&WPP_CB;
}
#pragma warning(pop)
#define WPP_SYSTEMCONTROL(PDO)
#define WPP_SYSTEMCONTROL2(PDO, offset)
#ifdef __cplusplus
} // extern "C"
#endif
@@ -0,0 +1,20 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// `Compiler.Checksum` Generated file. Do not edit.
// File created by `Compiler.Name` compiler version `Compiler.Version`
// from template `TemplateFile`
#pragma once
`INCLUDE km-StorHeader.tpl`
`INCLUDE control.tpl`
`INCLUDE tracemacro.tpl`
`IF FOUND WPP_INIT_TRACING`
` INCLUDE km-StorInit.tpl`
`ENDIF`
@@ -0,0 +1,188 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
#ifdef WPP_THIS_FILE
// included twice
# define WPP_ALREADY_INCLUDED
# undef WPP_THIS_FILE
#endif // #ifdef WPP_THIS_FILE
#define WPP_THIS_FILE `SourceFile.CanonicalName`
#ifndef WPP_ALREADY_INCLUDED
`* Dump the definitions specified via -D on the command line to WPP *`
`FORALL def IN MacroDefinitions`
#define `def.Name` `def.Alias`
`ENDFOR`
#include <stortrce.h>
#include <stddef.h>
#include <stdarg.h>
#include <wmistr.h>
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(_NTRTL_)
#if !defined(_NTHAL_)
// fake RTL_TIME_ZONE_INFORMATION //
typedef int RTL_TIME_ZONE_INFORMATION;
#endif
#define _WMIKM_
#endif
#ifndef WPP_TRACE
#define WPP_TRACE StorWmiTraceMessage
#endif
#if ENABLE_WPP_RECORDER
#error ENABLE_WPP_RECORDER not supported by km-StorDefault.tpl
#endif
///////////////////////////////////////////////////////////////////////////////
//
// B O R R O W E D D E F I N I T I O N S
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(_NTDEF_)
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;
#endif
#define TRACE_MESSAGE_SEQUENCE 1 // Message should include a sequence number
#define TRACE_MESSAGE_GUID 2 // Message includes a GUID
#define TRACE_MESSAGE_COMPONENTID 4 // Message has no GUID, Component ID instead
#define TRACE_MESSAGE_TIMESTAMP 8 // Message includes a timestamp
#define TRACE_MESSAGE_PERFORMANCE_TIMESTAMP 16 // *Obsolete* Clock type is controlled by
// the logger
#define TRACE_MESSAGE_SYSTEMINFO 32 // Message includes system information TID,PID
#define TRACE_MESSAGE_FLAG_MASK 0xFFFF // Only the lower 16 bits of flags are
// placed in the message those above 16
// bits are reserved for local processing
#ifndef TRACE_MESSAGE_MAXIMUM_SIZE
#define TRACE_MESSAGE_MAXIMUM_SIZE 8*1024 // the maximum size allowed for a single trace
#endif // message
#ifndef NTSTATUS
typedef LONG NTSTATUS;
#endif
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS)0xC0000295L)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L)
typedef ULONG64 TRACEHANDLE, *PTRACEHANDLE;
#ifndef TRACE_INFORMATION_CLASS_DEFINE
typedef enum _TRACE_INFORMATION_CLASS {
TraceIdClass,
TraceHandleClass,
TraceEnableFlagsClass,
TraceEnableLevelClass,
GlobalLoggerHandleClass,
EventLoggerHandleClass,
AllLoggerHandlesClass,
TraceHandleByNameClass
} TRACE_INFORMATION_CLASS;
#endif
//
// Action code for IoWMIRegistrationControl api
//
#define WMIREG_ACTION_REGISTER 1
#define WMIREG_ACTION_DEREGISTER 2
#define WMIREG_ACTION_REREGISTER 3
#define WMIREG_ACTION_UPDATE_GUIDS 4
#define WMIREG_ACTION_BLOCK_IRPS 5
///////////////////////////////////////////////////////////////////////////////
__inline ULONG64 WppQueryLogger(_In_opt_ PCWSTR LoggerName)
{
ULONG ReturnLength;
LONG Status;
ULONG64 TraceHandle;
UNICODE_STRING Buffer;
StorRtlInitUnicodeString(&Buffer, LoggerName ? LoggerName : L"stdout");
Status = StorWmiQueryTraceInformation(TraceHandleByNameClass,
(PVOID)&TraceHandle,
sizeof(TraceHandle),
&ReturnLength,
(PVOID)&Buffer
);
if (Status != STATUS_SUCCESS) {
return (ULONG64)0;
}
return TraceHandle;
}
typedef LONG (*WMIENTRY_NEW)(
_In_ UCHAR MinorFunction,
_In_opt_ PVOID DataPath,
_In_ ULONG BufferLength,
_Inout_updates_bytes_(BufferLength) PVOID Buffer,
_In_ PVOID Context,
_Out_ PULONG Size
);
typedef struct _WPP_TRACE_CONTROL_BLOCK
{
WMIENTRY_NEW Callback;
LPCGUID ControlGuid;
struct _WPP_TRACE_CONTROL_BLOCK *Next;
__int64 Logger;
PUNICODE_STRING RegistryPath;
UCHAR FlagsLen;
UCHAR Level;
USHORT Reserved;
ULONG Flags[1];
ULONG ReservedFlags;
} WPP_TRACE_CONTROL_BLOCK, *PWPP_TRACE_CONTROL_BLOCK;
VOID WppCleanupKm(_In_ PVOID TraceContext);
#define WPP_CLEANUP(DriverObject, TraceContext) WppCleanupKm(TraceContext)
//
// Callback routine to be defined by the driver, which will be called from WPP callback
// WPP will pass current valued of : GUID, Logger, Enable, Flags, and Level
//
// To activate driver must define WPP_PRIVATE_ENABLE_CALLBACK in their code, sample below
// #define WPP_PRIVATE_ENABLE_CALLBACK MyPrivateCallback;
//
typedef
VOID
(*PFN_WPP_PRIVATE_ENABLE_CALLBACK)(
_In_ LPCGUID Guid,
_In_ __int64 Logger,
_In_ BOOLEAN Enable,
_In_ ULONG Flags,
_In_ UCHAR Level);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // #ifndef WPP_ALREADY_INCLUDED
@@ -0,0 +1,571 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
//
// Defines a set of functions that simplifies
// kernel mode registration for tracing
//
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WPPINIT_EXPORT
#define WPPINIT_EXPORT
#endif
#ifndef WppDebug
#define WppDebug(a,b)
#endif
WPPINIT_EXPORT
NTSTATUS
WppTraceCallback(
_In_ UCHAR MinorFunction,
_In_opt_ PVOID DataPath,
_In_ ULONG BufferLength,
_Inout_updates_bytes_(BufferLength) PVOID Buffer,
_Inout_ PVOID Context,
_Out_ PULONG Size
);
WPPINIT_EXPORT
VOID
WppInitKm(
_In_opt_ PVOID DriverObject,
_In_ PVOID InitInfo
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, WppTraceCallback)
#pragma alloc_text( PAGE, WppInitKm)
#pragma alloc_text( PAGE, WppCleanupKm)
#endif // ALLOC_PRAGMA
// define annotation record that will carry control information to pdb (in case somebody needs it)
WPP_FORCEINLINE void WPP_CONTROL_ANNOTATION() {
#if !defined(WPP_NO_ANNOTATIONS)
#ifndef WPP_TMC_ANNOT_SUFIX
#ifdef WPP_PUBLIC_TMC
#define WPP_TMC_ANNOT_SUFIX ,L"PUBLIC_TMF:"
#else
#define WPP_TMC_ANNOT_SUFIX
#endif
#endif
# define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) __annotation(L"TMC:", WPP_GUID_WTEXT Guid, _WPPW(WPP_STRINGIZE(Name)) Bits WPP_TMC_ANNOT_SUFIX);
# define WPP_DEFINE_BIT(Name) , _WPPW(#Name)
WPP_CONTROL_GUIDS
# undef WPP_DEFINE_BIT
# undef WPP_DEFINE_CONTROL_GUID
#endif
}
#define WPP_NEXT(Name) ((WPP_TRACE_CONTROL_BLOCK*) \
(WPP_XGLUE(WPP_CTL_, WPP_EVAL(Name)) + 1 == WPP_LAST_CTL ? 0:WPP_MAIN_CB + WPP_XGLUE(WPP_CTL_, WPP_EVAL(Name)) + 1))
WPP_CB_TYPE WPP_MAIN_CB[WPP_LAST_CTL];
__inline void WPP_INIT_CONTROL_ARRAY(WPP_CB_TYPE* Arr) {
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) \
Arr->Control.Callback = NULL; \
Arr->Control.ControlGuid = WPP_XGLUE4(&WPP_, ThisDir, _CTLGUID_, WPP_EVAL(Name)); \
Arr->Control.Next = WPP_NEXT(WPP_EVAL(Name)); \
Arr->Control.RegistryPath= NULL; \
Arr->Control.FlagsLen = WPP_FLAG_LEN; \
Arr->Control.Level = 0; \
Arr->Control.Reserved = 0; \
Arr->Control.Flags[0] = 0; \
++Arr;
#define WPP_DEFINE_BIT(BitName) L" " L ## #BitName
WPP_CONTROL_GUIDS
#undef WPP_DEFINE_BIT
#undef WPP_DEFINE_CONTROL_GUID
}
#undef WPP_INIT_STATIC_DATA
#define WPP_INIT_STATIC_DATA WPP_INIT_CONTROL_ARRAY(WPP_MAIN_CB)
// define WPP_INIT_TRACING. For performance reasons turn off during
// static analysis compilation with Static Driver Verifier (SDV).
#ifndef _SDV_
#define WPP_INIT_TRACING(DriverObject, RegPath, InitInfo) \
{ \
WppDebug(0,("WPP_INIT_TRACING: &WPP_CB[0] %p\n", &WPP_MAIN_CB[0])); \
WPP_INIT_STATIC_DATA; \
( WPP_CONTROL_ANNOTATION(), \
WPP_MAIN_CB[0].Control.RegistryPath = NULL, \
UNREFERENCED_PARAMETER(RegPath), \
WppInitKm( DriverObject, InitInfo ) \
); \
}
#else
#define WPP_INIT_TRACING(DriverObject, RegPath, InitInfo)
#endif
#define WMIREG_FLAG_CALLBACK 0x80000000 // not exposed in DDK
#ifndef WMIREG_FLAG_TRACE_PROVIDER
#define WMIREG_FLAG_TRACE_PROVIDER 0x00010000
#endif
__inline int WppIsEqualGuid(_In_ const GUID* g1, _In_ const GUID* g2)
{
const ULONG* p1 = (const ULONG*)g1;
const ULONG* p2 = (const ULONG*)g2;
return p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2] && p1[3] == p2[3];
}
#define WPP_MAX_COUNT_REGISTRATION_GUID 63
WPPINIT_EXPORT
NTSTATUS
WppTraceCallback(
_In_ UCHAR MinorFunction,
_In_opt_ PVOID DataPath,
_In_ ULONG BufferLength,
_Inout_updates_bytes_(BufferLength) PVOID Buffer,
_Inout_ PVOID Context,
_Out_ PULONG Size
)
/*++
Routine Description:
This function is the callback WMI calls when we register and when our
events are enabled or disabled.
Arguments:
MinorFunction - specifies the type of callback (register, event enable/disable)
DataPath - varies depending on the ActionCode
BufferLength - size of the Buffer parameter
Buffer - in/out buffer where we read from or write to depending on the type
of callback
Context - the pointer private struct WPP_TRACE_CONTROL_BLOCK
Size - output parameter to receive the amount of data written into Buffer
Return Value:
NTSTATUS code indicating success/failure
Comments:
if return value is STATUS_BUFFER_TOO_SMALL and BufferLength >= 4,
then first ulong of buffer contains required size
--*/
{
PWPP_TRACE_CONTROL_BLOCK cntl;
NTSTATUS Status = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(DataPath);
WppDebug(0,("WppTraceCallBack 0x%08X %p\n", MinorFunction, Context));
*Size = 0;
switch(MinorFunction)
{
case IRP_MN_REGINFO:
{
PWMIREGINFOW WmiRegInfo;
PCUNICODE_STRING RegPath;
PWCHAR StringPtr;
ULONG RegistryPathOffset;
ULONG BufferNeeded;
ULONG GuidCount = 0;
//
// Initialize locals
//
cntl = (PWPP_TRACE_CONTROL_BLOCK)Context;
WmiRegInfo = (PWMIREGINFO)Buffer;
RegPath = cntl->RegistryPath;
//
// Count the number of guid to be identified.
//
while(cntl) { GuidCount++; cntl = cntl->Next; }
if (GuidCount > WPP_MAX_COUNT_REGISTRATION_GUID){
Status = STATUS_INVALID_PARAMETER;
break;
}
WppDebug(0,("WppTraceCallBack: GUID count %d\n", GuidCount));
//
// Calculate buffer size need to hold all info.
// Calculate offset to where RegistryPath parm will be copied.
//
if (RegPath == NULL)
{
RegistryPathOffset = 0;
BufferNeeded = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) +
GuidCount * sizeof(WMIREGGUIDW);
} else {
RegistryPathOffset = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid) +
GuidCount * sizeof(WMIREGGUIDW);
BufferNeeded = RegistryPathOffset +
RegPath->Length + sizeof(USHORT);
}
//
// If the provided buffer is large enough, then fill with info.
//
if (BufferNeeded <= BufferLength)
{
ULONG i;
StorMemSet(Buffer, 0, BufferLength);
//
// Fill in the WMIREGINFO
//
WmiRegInfo->BufferSize = BufferNeeded;
WmiRegInfo->RegistryPath = RegistryPathOffset;
WmiRegInfo->GuidCount = GuidCount;
if (RegPath != NULL) {
StringPtr = (PWCHAR)((PUCHAR)Buffer + RegistryPathOffset);
*StringPtr++ = RegPath->Length;
StorMoveMemory(StringPtr, RegPath->Buffer, RegPath->Length);
}
//
// Fill in the WMIREGGUID
//
cntl = (PWPP_TRACE_CONTROL_BLOCK) Context;
for (i=0; i<GuidCount; i++) {
WmiRegInfo->WmiRegGuid[i].Guid = *cntl->ControlGuid;
WmiRegInfo->WmiRegGuid[i].Flags = WMIREG_FLAG_TRACE_CONTROL_GUID |
WMIREG_FLAG_TRACED_GUID;
cntl->Level = 0;
cntl->Flags[0] = 0;
WppDebug(0,("Control GUID::%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
cntl->ControlGuid->Data1,
cntl->ControlGuid->Data2,
cntl->ControlGuid->Data3,
cntl->ControlGuid->Data4[0],
cntl->ControlGuid->Data4[1],
cntl->ControlGuid->Data4[2],
cntl->ControlGuid->Data4[3],
cntl->ControlGuid->Data4[4],
cntl->ControlGuid->Data4[5],
cntl->ControlGuid->Data4[6],
cntl->ControlGuid->Data4[7]
));
cntl = cntl->Next;
}
Status = STATUS_SUCCESS;
*Size = BufferNeeded;
} else {
Status = STATUS_BUFFER_TOO_SMALL;
if (BufferLength >= sizeof(ULONG)) {
*((PULONG)Buffer) = BufferNeeded;
*Size = sizeof(ULONG);
}
}
#ifdef WPP_GLOBALLOGGER
// Check if Global logger is active
cntl = (PWPP_TRACE_CONTROL_BLOCK) Context;
while(cntl) {
StorWppInitGlobalLogger(
cntl->ControlGuid,
(PTRACEHANDLE)&cntl->Logger,
&cntl->Flags[0],
&cntl->Level);
cntl = cntl->Next;
}
#endif //#ifdef WPP_GLOBALLOGGER
break;
}
case IRP_MN_ENABLE_EVENTS:
case IRP_MN_DISABLE_EVENTS:
{
PWNODE_HEADER Wnode;
ULONG Level;
ULONG ReturnLength;
ULONG index;
if (Context == NULL ) {
Status = STATUS_WMI_GUID_NOT_FOUND;
break;
}
if (BufferLength < sizeof(WNODE_HEADER)) {
Status = STATUS_INVALID_PARAMETER;
break;
}
//
// Initialize locals
//
Wnode = (PWNODE_HEADER)Buffer;
//
// Traverse this ProjectControlBlock's ControlBlock list and
// find the "cntl" ControlBlock which matches the Wnode GUID.
//
cntl = (PWPP_TRACE_CONTROL_BLOCK) Context;
index = 0;
while(cntl) {
if (WppIsEqualGuid(cntl->ControlGuid, &Wnode->Guid )) {
break;
}
index++;
cntl = cntl->Next;
}
if (cntl == NULL) {
Status = STATUS_WMI_GUID_NOT_FOUND;
break;
}
//
// Do the requested event action
//
Status = STATUS_SUCCESS;
if (MinorFunction == IRP_MN_DISABLE_EVENTS) {
WppDebug(0,("WppTraceCallBack: DISABLE_EVENTS\n"));
cntl->Level = 0;
cntl->Flags[0] = 0;
cntl->Logger = 0;
} else {
TRACEHANDLE lh;
lh = (TRACEHANDLE)( Wnode->HistoricalContext );
cntl->Logger = lh;
Status = StorWmiQueryTraceInformation( TraceEnableLevelClass,
&Level,
sizeof(Level),
&ReturnLength,
(PVOID)Wnode);
if (Status == STATUS_SUCCESS) {
cntl->Level = (UCHAR)Level;
}
Status = StorWmiQueryTraceInformation( TraceEnableFlagsClass,
&cntl->Flags[0],
sizeof(cntl->Flags[0]),
&ReturnLength,
(PVOID) Wnode );
WppDebug(0,("WppTraceCallBack: ENABLE_EVENTS "
"LoggerId %d, Flags 0x%08X, Level 0x%02X\n",
(USHORT) cntl->Logger,
cntl->Flags[0],
cntl->Level));
}
#ifdef WPP_PRIVATE_ENABLE_CALLBACK
//
// Notify changes to flags, level for GUID
//
WPP_PRIVATE_ENABLE_CALLBACK( cntl->ControlGuid,
cntl->Logger,
(MinorFunction != IRP_MN_DISABLE_EVENTS) ? TRUE:FALSE,
cntl->Flags[0],
cntl->Level );
#endif
break;
}
case IRP_MN_ENABLE_COLLECTION:
case IRP_MN_DISABLE_COLLECTION:
{
Status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_ALL_DATA:
case IRP_MN_QUERY_SINGLE_INSTANCE:
case IRP_MN_CHANGE_SINGLE_INSTANCE:
case IRP_MN_CHANGE_SINGLE_ITEM:
case IRP_MN_EXECUTE_METHOD:
{
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
default:
{
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
}
return(Status);
}
#pragma warning(push)
#pragma warning(disable:4068)
WPPINIT_EXPORT
VOID
WppInitKm(
_In_opt_ PVOID DriverObject,
_In_ PVOID InitInfo
)
/*++
Routine Description:
This function registers a driver with ETW as a provider of trace
events from the defined GUIDs.
Arguments:
DriverObject - Pointer to a driver object. This is required for WppRecorder
and is optional otherwise (not used unless it's for
WppRecorder).
InitInfo - Pointer to STORAGE_TRACE_INIT_INFO.
Remarks:
This function is called by the
WPP_INIT_TRACING(DriverObject, RegPath, InitInfo) macro.
--*/
{
C_ASSERT(WPP_MAX_FLAG_LEN_CHECK);
NTSTATUS Status;
PWPP_TRACE_CONTROL_BLOCK WppReg = NULL;
UNREFERENCED_PARAMETER(DriverObject);
if (WPP_CB != WPP_MAIN_CB) {
WPP_CB = WPP_MAIN_CB;
} else {
//
// WPP_INIT_TRACING already called
//
WppDebug(0,("Warning : WPP_INIT_TRACING already called, ignoring this one"));
return;
}
WppReg = &WPP_CB[0].Control;
WppDebug(0,("WPP Init.\n"));
if (StorInitTracing(InitInfo) == STATUS_SUCCESS) {
WppReg -> Callback = WppTraceCallback;
Status = StorIoWMIRegistrationControl(
WppReg,
WMIREG_ACTION_REGISTER |
WMIREG_FLAG_CALLBACK |
WMIREG_FLAG_TRACE_PROVIDER
);
if (!NT_SUCCESS(Status)) {
WppDebug(0,("StorIoWMIRegistrationControl Status = %08X\n",Status));
}
}
}
WPPINIT_EXPORT
VOID
WppCleanupKm(
_In_ PVOID TraceContext
)
/*++
Routine Description:
This function deregisters a driver from ETW as provider of trace
events.
Arguments:
TraceContext - The STORAGE_TRACE_INIT_INFO.TraceContext value.
Remarks:
This function is called by the WPP_CLEANUP(DriverObject, TraceContext) macro.
--*/
{
StorCleanupTracing(TraceContext);
if (WPP_CB == (WPP_CB_TYPE*)&WPP_CB){
//
// WPP_INIT_TRACING macro has not been called
//
WppDebug(0,("Warning : WPP_CLEANUP already called, or called with out WPP_INIT_TRACING first"));
return;
}
PWPP_TRACE_CONTROL_BLOCK WppReg = &WPP_CB[0].Control;
StorIoWMIRegistrationControl(WppReg,
WMIREG_ACTION_DEREGISTER |
WMIREG_FLAG_CALLBACK );
WPP_CB = (WPP_CB_TYPE*)&WPP_CB;
}
#pragma warning(pop)
#define WPP_SYSTEMCONTROL(PDO)
#define WPP_SYSTEMCONTROL2(PDO, offset)
#ifdef __cplusplus
} // extern "C"
#endif
@@ -0,0 +1,9 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
`INCLUDE km-default.tpl`
@@ -0,0 +1,9 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
`INCLUDE km-default.tpl`
@@ -0,0 +1,133 @@
<?xml version="1.0" standalone="yes"?>
<!--
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
Checksum="`Compiler.Checksum`" Generated file. Do not edit.
File created by `Compiler.Name` compiler version `Compiler.Version`
from template `TemplateFile`
`ENCODING UTF-8`
***************************************************************************
PREVIEW: Behavior of the -man option, the `TemplateFile` template, and the
associated configuration options may change in future versions of tracewpp.
***************************************************************************
-->
<instrumentationManifest
xmlns="http://schemas.microsoft.com/win/2004/08/events"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
>
<instrumentation>
<events>
`FORALL ControlGuid IN ControlGuids`
` FORALL TraceGuid IN ControlGuid.TraceGuids`
<provider
name="`ControlGuid.Name`_`TraceGuid.Normalized`"
controlGuid="{`ControlGuid.Text`}"
guid="{`TraceGuid.Text`}"
symbol="`ControlGuid.Symbol``IF TraceGuid No`_`TraceGuid.No``ENDIF`"
resourceFileName="`Manifest.ResourceFileName`"
messageFileName="`Manifest.MessageFileName`"
>
` IF ControlGuid Levels`
<levels>
` FORALL Level IN ControlGuid.Levels`
<level value="`Level.Value`" name="`Level.Name`" symbol="`Level.Symbol`" />
` ENDFOR Level`
</levels>
` ENDIF ControlGuid Levels`
` IF ControlGuid Keywords`
<keywords>
` FORALL Keyword IN ControlGuid.Keywords`
<keyword mask="`Keyword.Mask`" name="`Keyword.Name`" symbol="`Keyword.Symbol`" />
` ENDFOR Keyword`
</keywords>
` ENDIF ControlGuid Keywords`
` IF TraceGuid Maps`
<maps>
` FORALL Type IN TraceGuid.Types WHERE ItemSet`
<bitMap name="`Type.Name`">
` FORALL Item IN Type.MapItems`
<map value="0x`Item.HexValue`" message="$(string.S`Item.MessageId`)" />
` ENDFOR Item`
</bitMap>
` ENDFOR Type`
` FORALL Type IN TraceGuid.Types WHERE ItemList`
<valueMap name="`Type.Name`">
` FORALL Item IN Type.MapItems`
<map value="`Item.Value`" message="$(string.S`Item.MessageId`)" />
` ENDFOR Item`
</valueMap>
` ENDFOR Type`
</maps>
` ENDIF TraceGuid Maps`
<events>
` FORALL Message IN TraceGuid.Messages`
<event
` IF Message EventName`
name="`Message.XmlEventName`"
` ENDIF Message EventName`
attributes='`Message.Attributes`'
value="`Message.MsgNo`"
` IF Message Version`
version="`Message.Version`"
` ENDIF Message Version`
level="`Message.Level`"
keywords="`Message.Keywords`"
symbol="`Message.Name`"
message="$(string.S`Message.ManifestTextId`)"
` IF Message Arguments`
template="T`Message.TemplateId`"
` ENDIF Message Arguments`
/>
` ENDFOR Message`
</events>
<templates>
` FORALL Template IN TraceGuid.Templates`
<template tid="T`Template.Id`">
` FORALL Argument IN Template.Arguments`
<data
` IF Argument NameSpecified`
name="`Argument.XmlName`"
` ENDIF Argument NameSpecified`
` IF Argument !NameSpecified`
name="A`Argument.No`_`Argument.XmlName`"
` ENDIF Argument !NameSpecified`
inType="`Argument.InType`"
` IF Argument MapName`
map="`Argument.MapName`"
` ENDIF Argument MapName`
` IF Argument OutType`
outType="`Argument.OutType`"
` ENDIF Argument OutType`
` IF Argument Length`
length="`Argument.Length`"
` ENDIF Argument Length`
/>
` ENDFOR Argument`
</template>
` ENDFOR Template`
</templates>
</provider>
` ENDFOR TraceGuid`
`ENDFOR ControlGuid`
</events>
</instrumentation>
<localization>
<resources culture="`Manifest.Culture`">
<stringTable>
`FORALL NameId IN StringTable`
<string
id="S`NameId.Id`"
value="`NameId.XmlName`"
/>
`ENDFOR Message`
</stringTable>
</resources>
</localization>
</instrumentationManifest>
@@ -0,0 +1,23 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// `Compiler.Checksum` Generated file. Do not edit.
// File created by `Compiler.Name` compiler version `Compiler.Version`
// from template `TemplateFile`
`FORALL Guid IN TraceGuids`
`Guid.Text` `Guid.Comment`
`FORALL Msg in Guid.Messages`
#typev `Msg.Name` `Msg.MsgNo` "`Msg.Text`"
{
`FORALL Arg IN Msg.Arguments`
`Arg.Name`, `Arg.MofType` // `Arg.No`
`ENDFOR Arg`
}
`ENDFOR Msg`
`ENDFOR Guid`
@@ -0,0 +1,254 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// Checksum="`Compiler.Checksum`" Generated file. Do not edit.
// File created by `Compiler.Name` compiler version `Compiler.Version`
// from template `TemplateFile`
// ***************************************************************************
// PREVIEW: Behavior of the -man option, the `TemplateFile` template, and the
// associated configuration options may change in future versions of tracewpp.
// ***************************************************************************
#pragma once
// Define the macros (if any) specified on the tracewpp command line.
// -- Begin macro definitions.
`FORALL def IN MacroDefinitions`
#define `def.Name` `def.Alias`
`ENDFOR`
// -- End macro definitions.
// The "`Manifest.HeaderFileName`" file should be generated by running the
// MC.exe tool: mc.exe -um `Manifest.Arguments`
#include "`Manifest.HeaderFileName`"
`IF FOUND WPP_INIT_TRACING`
#ifndef WPP_INIT_TRACING
#define WPP_INIT_TRACING(...) WPP_INIT()
#endif
`ENDIF FOUND WPP_INIT_TRACING`
// WPP_LOG_ALWAYS:
// Called for each event: WPP_LOG_ALWAYS(EX, MSG, arg1, arg2, arg3...) Other()
// If defined, the definition needs to include a trailing comma or semicolon.
// In addition, you will need to define a WPP_EX_[args](args...) macro to
// extract any needed information from the other arguments (e.g. LEVEL).
#ifndef WPP_LOG_ALWAYS
#define WPP_LOG_ALWAYS(...)
#endif
// WPP_DEBUG:
// Called for each enabled event: WPP_DEBUG((MSG, arg1, arg2, arg3...)), Other()
// Potential definition: printf MsgArgs
// Definition should not include any trailing comma or semicolon.
#ifdef WPP_DEBUG
#define WPP_INVOKE_WPP_DEBUG(MsgArgs) WPP_DEBUG(MsgArgs)
#else // WPP_DEBUG
#define WPP_INVOKE_WPP_DEBUG(MsgArgs) (void)0
#endif // WPP_DEBUG
#ifndef WPP_FORCEINLINE
#define WPP_FORCEINLINE __forceinline
#endif
#define WPP_THIS_FILE `SourceFile.CanonicalName`
#define WPP_FLATTEN(...) __VA_ARGS__
#define WPP_INVOKE_MCMACRO(f, args) f args
#define WPP_EVAL(x) x
#define WPP_GLUE5(a, b, c, d, e) a ## b ## c ## d ## e
#define WPP_XGLUE5(a, b, c, d, e) WPP_GLUE5(a, b, c, d, e)
#define WPP_(Id) WPP_XGLUE5(WPP_, Id, _, WPP_THIS_FILE, __LINE__)
// Calls EventRegister_[ProviderName] for each provider in the generated manifest.
#define WPP_INIT() \
{ \
`FORALL ControlGuid IN ControlGuids`
` FORALL TraceGuid IN ControlGuid.TraceGuids`
EventRegister_`ControlGuid.Symbol``IF TraceGuid No`_`TraceGuid.No``ENDIF`(); \
` ENDFOR TraceGuid`
`ENDFOR ControlGuid`
}
// Calls EventUnregister_[ProviderName] for each provider in the generated manifest.
#define WPP_CLEANUP() \
{ \
`FORALL ControlGuid IN ControlGuids`
` FORALL TraceGuid IN ControlGuid.TraceGuids`
EventUnregister_`ControlGuid.Symbol``IF TraceGuid No`_`TraceGuid.No``ENDIF`(); \
` ENDFOR TraceGuid`
`ENDFOR ControlGuid`
}
// WPP_ENABLED helpers
`FORALL ControlGuid IN ControlGuids`
` FORALL TraceGuid IN ControlGuid.TraceGuids WHERE !No`
#define WPP_ENABLED_`ControlGuid.Symbol`(level, keyword) \
(`ControlGuid.Symbol`_Context.IsEnabled && McGenLevelKeywordEnabled(&`ControlGuid.Symbol`_Context, (level), (keyword)))
` ENDFOR TraceGuid`
`ENDFOR ControlGuid`
// Adapters
#ifndef WPP_ADAPTER_PUSTR
#ifdef WPP_CHECK_FOR_NULL_STRING
# define WPP_ADAPTER_PUSTR(x) \
(x) ? (x)->Length/2 : 4, \
(x) ? (x)->Buffer : L"NULL"
#else // WPP_CHECK_FOR_NULL_STRING
# define WPP_ADAPTER_PUSTR(x) (x)->Length/2, (x)->Buffer
#endif // WPP_CHECK_FOR_NULL_STRING
#endif // WPP_ADAPTER_PUSTR
#ifndef WPP_ADAPTER_PCSTR
#ifdef WPP_CHECK_FOR_NULL_STRING
# define WPP_ADAPTER_PCSTR(x) \
(x) ? (x)->Length : 4, \
(x) ? (x)->Buffer : "NULL"
#else // WPP_CHECK_FOR_NULL_STRING
# define WPP_ADAPTER_PCSTR(x) (x)->Length, (x)->Buffer
#endif // WPP_CHECK_FOR_NULL_STRING
#endif // WPP_ADAPTER_PCSTR
#ifndef WPP_ADAPTER_PSID
# define WPP_ADAPTER_PSID(pSid) (const SID*)pSid
#endif // WPP_ADAPTER_PSID
#ifndef WPP_ADAPTER_PVOID
# define WPP_ADAPTER_PVOID(intptr) (const void*)intptr
#endif // WPP_ADAPTER_PVOID
#ifndef WPP_ADAPTER_PFILETIME
# define WPP_ADAPTER_PFILETIME(i64) (const FILETIME*)&i64
#endif // WPP_ADAPTER_PFILETIME
#ifndef WPP_ADAPTER_CCCC
# define WPP_ADAPTER_CCCC(val) (const char*)&val
#endif // WPP_ADAPTER_CCCC
#ifndef WPP_ADAPTER_BIN
# define WPP_ADAPTER_BIN(x) (x).Length, (const unsigned char*)(x).Buffer
#endif // WPP_ADAPTER_BIN
#ifdef __cplusplus
#ifndef WPP_ADAPTER_CPPSTR
#define WPP_ADAPTER_CPPSTR(x) static_cast<USHORT>(x.size()), x.c_str()
#endif // WPP_ADAPTER_CPPSTR
#ifndef WPP_ADAPTER_CPPVEC
#define WPP_ADAPTER_CPPVEC(x) static_cast<USHORT>(x.size()), x.data()
#endif // WPP_ADAPTER_CPPVEC
#endif // __cplusplus
#ifndef WPP_BINARY_def
# define WPP_BINARY_def
typedef struct tagWPP_BINARY
{
_Field_size_bytes_(Length) void const* Buffer;
USHORT Length;
} WPP_BINARY;
#endif // WPP_BINARY_def
#ifndef WPP_BINARY_func
# define WPP_BINARY_func
WPP_FORCEINLINE WPP_BINARY
WppBinary(_In_reads_bytes_(Length) void const* Buffer, USHORT Length)
{
WPP_BINARY data;
data.Buffer = Buffer;
data.Length = Length;
return data;
}
#endif // WPP_BINARY_func
// Functions
`FORALL f IN Funcs WHERE !DoubleP && !MsgArgs && !NoMsg`
#undef `f.Name`
#ifdef __INTELLISENSE__
#define `f.Name`(`f.FixedArgs`MSG, ...) ((void)(MSG, ## __VA_ARGS__))
#else
#define `f.Name` WPP_(CALL)
#endif
`ENDFOR`
`FORALL f IN Funcs WHERE !DoubleP && !MsgArgs && NoMsg`
#undef `f.Name`
#ifdef __INTELLISENSE__
#define `f.Name`(`f.FixedArgs`) ((void)0)
#else
#define `f.Name` WPP_(CALL)
#endif
`ENDFOR`
`FORALL f IN Funcs WHERE DoubleP && !MsgArgs`
#undef `f.Name`
#ifdef __INTELLISENSE__
#define `f.Name`(ARGS) ((void)ARGS)
#else
#define `f.Name`(ARGS) WPP_(CALL) ARGS
#endif
`ENDFOR`
`FORALL f IN Funcs WHERE MsgArgs`
#undef `f.Name`
#ifdef __INTELLISENSE__
#define `f.Name`(`f.FixedArgs`MSGARGS) ((void)(MSGARGS))
#else
#define `f.Name`(`f.FixedArgs`MSGARGS) WPP_(CALL)(`f.FixedArgs`MSGARGS)
#endif
`ENDFOR`
`FORALL r IN Reorder`
#undef WPP_REORDER_`r.Name`
#define WPP_REORDER_`r.Name`(`r.Arguments`) `r.PermutationNoLeadingComma`
`ENDFOR`
// Messages
`FORALL i IN Messages WHERE !MsgArgs`
// `i.Name`
#ifndef WPP`i.GooId`_PRE
# define WPP`i.GooId`_PRE(`i.GooArgs`)
#endif
#ifndef WPP`i.GooId`_POST
# define WPP`i.GooId`_POST(`i.GooArgs`)
#endif
WPP_FORCEINLINE ULONG WPP_MFUNC_`i.Name`(`i.FuncArgDecls`)
{ return WPP_INVOKE_MCMACRO(`Manifest.Prefix``i.Name`_AssumeEnabled, (`i.FuncArgExprs`)); }
#define WPP_CALL_`i.Name`(`i.FixedArgs``i.MacroArgs`) \
WPP_LOG_ALWAYS(WPP_EX`i.GooId`(`i.GooVals`), `i.DbgMacroArgs`) \
WPP`i.GooId`_PRE(`i.GooVals`) \
(( \
MCGEN_EVENT_ENABLED(`i.Name`) \
? WPP_INVOKE_WPP_DEBUG((`i.DbgMacroArgs`)), \
WPP_MFUNC_`i.Name`(`i.MacroExprsNoLeadingComma`) \
: 0 \
)) \
WPP`i.GooId`_POST(`i.GooVals`)
`ENDFOR i IN Messages WHERE !MsgArgs`
`FORALL i IN Messages WHERE MsgArgs`
// `i.Name`
#ifndef WPP`i.GooId`_PRE
# define WPP`i.GooId`_PRE(`i.GooArgs`)
#endif
#ifndef WPP`i.GooId`_POST
# define WPP`i.GooId`_POST(`i.GooArgs`)
#endif
WPP_FORCEINLINE ULONG WPP_MFUNC_`i.Name`(`i.FuncArgDecls`)
{ return WPP_INVOKE_MCMACRO(`Manifest.Prefix``i.Name`_AssumeEnabled, (`i.FuncArgExprs`)); }
#define WPP_CALL_`i.Name`(`i.FixedArgs` MSGARGS) \
WPP_LOG_ALWAYS(WPP_EX`i.GooId`(`i.GooVals`), WPP_FLATTEN MSGARGS) \
WPP`i.GooId`_PRE(`i.GooVals`) \
(( \
MCGEN_EVENT_ENABLED(`i.Name`) \
? WPP_INVOKE_WPP_DEBUG(MSGARGS), \
WPP_MFUNC_`i.Name` WPP_EVAL((`i.SyntheticExprsNoLeadingComma`WPP_REORDER_`i.ReorderSig` MSGARGS)) \
: 0 \
)) \
WPP`i.GooId`_POST(`i.GooVals`)
`ENDFOR i IN Messages WHERE MsgArgs`
@@ -0,0 +1,32 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// `Compiler.Checksum` Generated file. Do not edit.
// File created by `Compiler.Name` compiler version `Compiler.Version`
// from template `TemplateFile`
// PLEASE NOTE:
// Using simple.tpl for production environment without overriding
// WPP_ENABLED and WPP_LOGGER macro is NOT RECOMMENDED.
//
// If WPP_ENABLED is not provided, the logging is always on
// If WPP_LOGGER is not provided, traces always go to the logger named stdout (if it is running)
//
`INCLUDE header.tpl`
`INCLUDE stdout.tpl`
`INCLUDE tracemacro.tpl`
`IF FOUND WPP_INIT_TRACING`
#ifndef WPP_INIT_TRACING
#define WPP_INIT_TRACING(...) ((void)0)
#endif
#ifndef WPP_CLEANUP
#define WPP_CLEANUP(...) ((void)0)
#endif
`ENDIF`
@@ -0,0 +1,41 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
`FORALL f IN Funcs`
#ifndef WPP`f.GooId`_LOGGER
#define WPP`f.GooId`_LOGGER(`f.GooArgs`) // `f.Name`
#endif
`ENDFOR`
#ifndef WPP_LOGGER_ARG
# define WPP_LOGGER_ARG
#endif
#ifndef WPP_GET_LOGGER
#define WPP_GET_LOGGER WppGetLogger()
__inline TRACEHANDLE WppGetLogger()
{
static TRACEHANDLE Logger;
if (Logger) {return Logger;}
return Logger = WppQueryLogger(0);
}
#endif
#define WPP_GLUE(a, b) a ## b
#define _WPPW(x) WPP_GLUE(L, x)
#ifndef WPP_CHECK_INIT
#define WPP_CHECK_INIT
#endif
#ifndef WPP_ENABLED
# define WPP_ENABLED() 1
#endif
#ifndef WPP_LEVEL_ENABLED
# define WPP_LEVEL_ENABLED(LEVEL) 1
#endif
@@ -0,0 +1,289 @@
#
# Default configuration options for tracewpp for users who are using TCHARs
# and have UNICODE defined. This is the same as defaultwpp.ini except that:
#
# - %s is for WCHAR* instead of CHAR*.
# - %S is for CHAR* instead of WCHAR*.
# - %Z is for UNICODE_STRING* instead of ANSI_STRING*.
#
# Refer to the defaultwpp.ini file for additional information about the syntax
# of WPP INI files.
################################
# Default WPP configuration
################################
# our basic arithmetic types
DEFINE_SIMPLE_TYPE( XINT64, signed __int64, ItemLongLongX, "I64x", i, 8, win:HexInt64);
DEFINE_SIMPLE_TYPE( XXINT64,signed __int64, ItemLongLongXX,"I64X", i, 8, win:HexInt64);
DEFINE_SIMPLE_TYPE( OINT64, signed __int64, ItemLongLongO, "I64o", i, 8, win:HexInt64);
DEFINE_SIMPLE_TYPE( SBYTE, signed char, ItemChar, "c", c, 1, win:Int8);
DEFINE_SIMPLE_TYPE( SSHORT, signed short, ItemShort, "hd", h, 2, win:Int16);
DEFINE_SIMPLE_TYPE( SINT, signed int, ItemLong, "d", d, 4, win:Int32);
DEFINE_SIMPLE_TYPE( SLONG, signed long, ItemLong, "ld", l, 4, win:Int32);
DEFINE_SIMPLE_TYPE( SINT64, signed __int64, ItemLongLong, "I64d", i, 8, win:Int64);
DEFINE_SIMPLE_TYPE( UBYTE, unsigned char, ItemChar, "c", C, 1, win:UInt8);
DEFINE_SIMPLE_TYPE( USHORT, unsigned short, ItemShort, "hu", H, 2, win:UInt16);
DEFINE_SIMPLE_TYPE( UINT, unsigned int, ItemLong, "u", D, 4, win:UInt32);
DEFINE_SIMPLE_TYPE( ULONG, unsigned long, ItemLong, "lu", L, 4, win:UInt32);
DEFINE_SIMPLE_TYPE( UINT64, unsigned __int64,ItemULongLong, "I64u", I, 8, win:UInt64);
DEFINE_SIMPLE_TYPE( DOUBLE, double, ItemDouble, "s", g, 8, win:Double);
DEFINE_FLAVOR( UCHAR, UBYTE, ItemUChar, "c", win:UInt8; outType=xs:string);
DEFINE_FLAVOR( SCHAR, SBYTE, ItemChar, "c", win:Int8; outType=xs:string);
# arch dependent types
DEFINE_SIMPLE_TYPE( SLONGPTR, LONG_PTR, ItemPtr, "Id", p, 7, win:Pointer; adapter=WPP_ADAPTER_PVOID; outType=xs:long);
DEFINE_SIMPLE_TYPE( ULONGPTR, ULONG_PTR, ItemPtr, "Iu", P, 7, win:Pointer; adapter=WPP_ADAPTER_PVOID; outType=xs:unsignedLong);
DEFINE_SIMPLE_TYPE( PTR, const void*, ItemPtr, "p", q, 6, win:Pointer);
DEFINE_SIMPLE_TYPE( HANDLE, const void*, ItemPtr, "p", q, 6, win:Pointer);
DEFINE_SIMPLE_TYPE_PTR(GUID, LPCGUID, ItemGuid, "s", _guid_, 4, win:GUID);
# Predefined constants.
# Typically used in the function's prefix or suffix.
DEFINE_SIMPLE_TYPE( COMPNAME,,, "__COMPNAME__",,);
DEFINE_SIMPLE_TYPE( FILE,,, "__FILE__",,);
DEFINE_SIMPLE_TYPE( LINE,,, "__LINE__",,);
DEFINE_SIMPLE_TYPE( SPACE,,, " ",,);
# The following can be used in the prefix or suffix.
DEFINE_SIMPLE_TYPE( FUNC,,, "%!FUNC!",,);
DEFINE_SIMPLE_TYPE( LEVEL,,, "%!LEVEL!",,);
DEFINE_SIMPLE_TYPE( KEYWORDS,,, "%!FLAGS!",,);
DEFINE_SIMPLE_TYPE( STDPREFIX,,, "%0",,); # Only works at start of prefix. Ignored for manifest-based WPP.
DEFINE_SIMPLE_TYPE( MOD,,, "%1!s!",,);
DEFINE_SIMPLE_TYPE( TYP,,, "%2!s!",,);
DEFINE_SIMPLE_TYPE( TID,,, "%3!x!",,);
DEFINE_SIMPLE_TYPE( NOW,,, "%4!s!",,);
DEFINE_SIMPLE_TYPE( SEQ,,, "%7!u!",,);
DEFINE_SIMPLE_TYPE( PID,,, "%8!x!",,);
DEFINE_SIMPLE_TYPE( CPU,,, "%9!u!",,);
# Complex types
# Strings and SID require custom processing
DEFINE_CPLX_TYPE(ASTR, WPP_LOGASTR, LPCSTR, ItemString, "s", s, 1, win:AnsiString);
DEFINE_CPLX_TYPE(ARSTR, WPP_LOGASTR, LPCSTR, ItemRString, "s", s, 1, win:AnsiString);
DEFINE_CPLX_TYPE(ARWSTR,WPP_LOGWSTR, LPCWSTR, ItemRWString,"s", S, 2, win:UnicodeString);
DEFINE_CPLX_TYPE(WSTR, WPP_LOGWSTR, LPCWSTR, ItemWString, "s", S, 2, win:UnicodeString);
DEFINE_CPLX_TYPE(CSTR, WPP_LOGPCSTR, const CSTRING*, ItemPString, "s", z, 1, win:CountedAnsiString; adapter=WPP_ADAPTER_PCSTR);
DEFINE_CPLX_TYPE(USTR, WPP_LOGPUSTR, PCUNICODE_STRING, ItemPWString,"s", Z, 2, win:CountedUnicodeString; adapter=WPP_ADAPTER_PUSTR);
DEFINE_CPLX_TYPE(ANSTR, WPP_LOGPCSTR, const ANSI_STRING*, ItemPString, "s", aZ, 1, win:CountedAnsiString; adapter=WPP_ADAPTER_PCSTR);
DEFINE_CPLX_TYPE(sid, WPP_LOGPSID, PSID, ItemSid, "s", _sid_, 0, win:SID; adapter=WPP_ADAPTER_PSID);
# Raw binary data. Usage: DoTraceMessage(FLAG, "%!BIN!", WppBinary(pointer, size));
DEFINE_CPLX_TYPE(BIN, WPP_LOGCSTR, WPP_BINARY, ItemHexDump, "s", _zb_, 1, win:CountedBinary; adapter=WPP_ADAPTER_BIN);
# C++ string types
DEFINE_CPLX_TYPE(str, WPP_LOGCPPSTR, const std::string&, ItemPString, "s", _str_, 0, win:CountedAnsiString; adapter=WPP_ADAPTER_CPPSTR);
DEFINE_CPLX_TYPE(wstr, WPP_LOGCPPSTR, const std::wstring&, ItemPWString, "s", _wstr_, 0, win:CountedUnicodeString; adapter=WPP_ADAPTER_CPPSTR);
DEFINE_CPLX_TYPE(sv, WPP_LOGCPPVEC, const std::string_view&, ItemPString, "s", _sv_, 0, win:CountedAnsiString; adapter=WPP_ADAPTER_CPPVEC);
DEFINE_CPLX_TYPE(wsv, WPP_LOGCPPVEC, const std::wstring_view&,ItemPWString, "s", _wsv_, 0, win:CountedUnicodeString; adapter=WPP_ADAPTER_CPPVEC);
# Define printf-compatible types
DEFINE_FLAVOR(e, DOUBLE,,);
DEFINE_FLAVOR(E, DOUBLE,,);
DEFINE_FLAVOR(f, DOUBLE,,);
DEFINE_FLAVOR(g, DOUBLE,,);
DEFINE_FLAVOR(G, DOUBLE,,);
DEFINE_FLAVOR(c, SCHAR,,);
DEFINE_FLAVOR(hc, SCHAR,,);
DEFINE_FLAVOR(lc, SSHORT,,);
DEFINE_FLAVOR(wc, SSHORT,,);
DEFINE_FLAVOR(C, SSHORT,,);
DEFINE_FLAVOR(s, WSTR,,); # %s is WIDE with TCHARUNIwpp.ini.
DEFINE_FLAVOR(hs, ASTR,,);
DEFINE_FLAVOR(S, ASTR,,); # %S is ANSI with TCHARUNIwpp.ini.
DEFINE_FLAVOR(ws, WSTR,,);
DEFINE_FLAVOR(ls, WSTR,,);
DEFINE_FLAVOR(hi, SSHORT,,);
DEFINE_FLAVOR(hd, SSHORT,,);
DEFINE_FLAVOR(hu, USHORT,,"u");
DEFINE_FLAVOR(hx, USHORT,,"x", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(hX, USHORT,,"X", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(ho, USHORT,,"o", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(Id, ULONGPTR,,"Id");
DEFINE_FLAVOR(Iu, ULONGPTR,,"Iu");
DEFINE_FLAVOR(Ix, ULONGPTR,,"Ix", win:Pointer; adapter=WPP_ADAPTER_PVOID);
DEFINE_FLAVOR(IX, ULONGPTR,,"IX", win:Pointer; adapter=WPP_ADAPTER_PVOID);
DEFINE_FLAVOR(Io, ULONGPTR,,"Io", win:Pointer; adapter=WPP_ADAPTER_PVOID);
DEFINE_FLAVOR(i, SINT,,);
DEFINE_FLAVOR(d, SINT,,);
DEFINE_FLAVOR(u, UINT,,"u");
DEFINE_FLAVOR(x, UINT,,"x", win:HexInt32);
DEFINE_FLAVOR(X, UINT,,"X", win:HexInt32);
DEFINE_FLAVOR(o, UINT,,"o", win:HexInt32);
DEFINE_FLAVOR(cccc, SINT, ItemChar4, "s", win:AnsiString; length=4; adapter=WPP_ADAPTER_CCCC);
DEFINE_FLAVOR(li, SLONG,,);
DEFINE_FLAVOR(ld, SLONG,,);
DEFINE_FLAVOR(lu, ULONG,,"u");
DEFINE_FLAVOR(lx, ULONG,,"x", win:HexInt32);
DEFINE_FLAVOR(lX, ULONG,,"X", win:HexInt32);
DEFINE_FLAVOR(lo, ULONG,,"o", win:HexInt32);
DEFINE_FLAVOR(I64d, SINT64,,);
DEFINE_FLAVOR(I64u, UINT64,,);
DEFINE_FLAVOR(I64x, XINT64,,"I64x");
DEFINE_FLAVOR(I64X, XXINT64,,"I64X");
DEFINE_FLAVOR(I64o, OINT64,,"I64o");
DEFINE_FLAVOR(lld, SINT64,,);
DEFINE_FLAVOR(llu, UINT64,,);
DEFINE_FLAVOR(llx, XINT64,,"I64x");
DEFINE_FLAVOR(llX, XXINT64,,"I64X");
DEFINE_FLAVOR(llo, OINT64,,"I64o");
DEFINE_FLAVOR(p, PTR,,);
DEFINE_FLAVOR(Z, USTR,,); # %Z is PCUNICODE_STRING with TCHARUNIwpp.ini.
DEFINE_FLAVOR(wZ, USTR,,);
DEFINE_FLAVOR(z, CSTR,,);
DEFINE_FLAVOR(hZ, CSTR,,);
# default formats for those who don't care to provide their own strings
DEFINE_FLAVOR(XBYTE, SBYTE,, "02x", win:UInt8; outType=win:HexInt8);
DEFINE_FLAVOR(OBYTE, SBYTE,, "o", win:UInt8; outType=win:HexInt8);
DEFINE_FLAVOR(XSHORT, SSHORT,, "04hX", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(OSHORT, SSHORT,, "ho", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(XINT, SINT,, "08x", win:HexInt32);
DEFINE_FLAVOR(OINT, SINT,, "o", win:HexInt32);
DEFINE_FLAVOR(XLONG, SLONG,, "08lX", win:HexInt32);
DEFINE_FLAVOR(OLONG, SLONG,, "lo", win:HexInt32);
DEFINE_FLAVOR(XLONGPTR, SLONGPTR,,"Ix", win:Pointer; adapter=WPP_ADAPTER_PVOID);
DEFINE_FLAVOR(OLONGPTR, SLONGPTR,,"Io", win:Pointer; adapter=WPP_ADAPTER_PVOID);
# special formats
DEFINE_FLAVOR(IPADDR, UINT, ItemIPAddr, "s", win:UInt32; outType=win:IPv4);
DEFINE_FLAVOR(PORT, USHORT, ItemPort, "s", win:UInt16; outType=win:Port);
DEFINE_FLAVOR(STATUS, SINT, ItemNTSTATUS, "s", win:HexInt32; outType=win:NTSTATUS);
DEFINE_FLAVOR(WINERROR, UINT, ItemWINERROR, "s", win:UInt32; outType=win:Win32Error);
DEFINE_FLAVOR(HRESULT, SINT, ItemHRESULT, "s", win:Int32; outType=win:HResult);
# Note: The %!NDIS_STATUS! and %!NDIS_OID! types work for for TMF-based WPP but
# do not work well with manifest-based WPP. Manifest-based ETW decoders will
# treat %!NDIS_STATUS! and %!NDIS_OID! items as HexInt32 items.
DEFINE_FLAVOR(NDIS_STATUS, SINT, ItemNDIS_STATUS, "s", win:HexInt32);
DEFINE_FLAVOR(NDIS_OID, UINT, ItemNDIS_OID, "s", win:HexInt32);
DEFINE_FLAVOR(ipaddr,IPADDR,,);
DEFINE_FLAVOR(port,PORT,,);
DEFINE_FLAVOR(status,STATUS,,);
DEFINE_FLAVOR(hresult,HRESULT,,);
DEFINE_FLAVOR(winerr,WINERROR,,);
DEFINE_FLAVOR(guid,GUID,,);
# time related stuff
DEFINE_FLAVOR(TIMESTAMP, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(TIME, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(DATE, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(WAITTIME, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(due, SINT64, ItemWaitTime, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
DEFINE_FLAVOR(delta, SINT64, ItemTimeDelta, "s");
DEFINE_FLAVOR(datetime, SINT64, ItemTimestamp, "s", win:FILETIME; adapter=WPP_ADAPTER_PFILETIME);
# enumeration types
DEFINE_FLAVOR(ItemListByte, SBYTE, ItemListByte, "s", win:UInt8);
DEFINE_FLAVOR(ItemListShort, SSHORT, ItemListShort, "s", win:UInt16);
DEFINE_FLAVOR(ItemListLong, SLONG, ItemListLong, "s", win:UInt32);
DEFINE_FLAVOR(ItemSetByte, UBYTE, ItemSetByte, "s", win:UInt8; outType=win:HexInt8);
DEFINE_FLAVOR(ItemSetShort, USHORT, ItemSetShort, "s", win:UInt16; outType=win:HexInt16);
DEFINE_FLAVOR(ItemSetLong, ULONG, ItemSetLong, "s", win:HexInt32);
# Note: The "ItemEnum" and "ItemFlagsEnum" types work for for TMF-based WPP but
# do not work well with manifest-based WPP. Manifest-based ETW decoders will
# treat types based on "ItemEnum" as UInt32 and will treat types based on
# "ItemFlagsEnum" as HexInt32. For better results, use ItemListLong,
# ItemSetLong, or a "begin_wpp enum" block for your enumeration.
DEFINE_FLAVOR(ItemEnum, ULONG, ItemEnum, "s");
DEFINE_FLAVOR(ItemFlagsEnum, ULONG, ItemFlagsEnum, "s", win:HexInt32);
DEFINE_FLAVOR(CLSID, GUID, ItemCLSID, "s");
DEFINE_FLAVOR(LIBID, GUID, ItemLIBID, "s");
DEFINE_FLAVOR(IID, GUID, ItemIID, "s");
CUSTOM_TYPE(b1, ItemSetByte(1,2,3,4,5,6,7,8) );
CUSTOM_TYPE(b2, ItemSetShort(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) );
CUSTOM_TYPE(b4, ItemSetLong(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32) );
CUSTOM_TYPE(bool, ItemListLong(false,true) );
CUSTOM_TYPE(bool16, ItemListShort(false,true) );
CUSTOM_TYPE(bool8, ItemListByte(false,true) );
CUSTOM_TYPE(BOOLEAN, ItemListByte(FALSE,TRUE) );
CUSTOM_TYPE(irql, ItemListByte(Low,APC,DPC) );
CUSTOM_TYPE(pnpmn, ItemListByte(IRP_MN_START_DEVICE,IRP_MN_QUERY_REMOVE_DEVICE,IRP_MN_REMOVE_DEVICE,IRP_MN_CANCEL_REMOVE_DEVICE,IRP_MN_STOP_DEVICE,IRP_MN_QUERY_STOP_DEVICE,IRP_MN_CANCEL_STOP_DEVICE,IRP_MN_QUERY_DEVICE_RELATIONS,IRP_MN_QUERY_INTERFACE,IRP_MN_QUERY_CAPABILITIES,IRP_MN_QUERY_RESOURCES,IRP_MN_QUERY_RESOURCE_REQUIREMENTS,IRP_MN_QUERY_DEVICE_TEXT,IRP_MN_FILTER_RESOURCE_REQUIREMENTS,IRP_MN_PNP_14,IRP_MN_READ_CONFIG,IRP_MN_WRITE_CONFIG,IRP_MN_EJECT,IRP_MN_SET_LOCK,IRP_MN_QUERY_ID,IRP_MN_QUERY_PNP_DEVICE_STATE,IRP_MN_QUERY_BUS_INFORMATION,IRP_MN_DEVICE_USAGE_NOTIFICATION,IRP_MN_SURPRISE_REMOVAL) );
CUSTOM_TYPE(sysctrl, ItemListByte(IRP_MN_QUERY_ALL_DATA,IRP_MN_QUERY_SINGLE_INSTANCE, IRP_MN_CHANGE_SINGLE_INSTANCE, IRP_MN_CHANGE_SINGLE_ITEM, IRP_MN_ENABLE_EVENTS, IRP_MN_DISABLE_EVENTS, IRP_MN_ENABLE_COLLECTION, IRP_MN_DISABLE_COLLECTION, IRP_MN_REGINFO, IRP_MN_EXECUTE_METHOD, IRP_MN_Reserved_0a, IRP_MN_REGINFO_EX) );
CUSTOM_TYPE(pnpmj, ItemListByte(IRP_MJ_CREATE,IRP_MJ_CREATE_NAMED_PIPE,IRP_MJ_CLOSE,IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_QUERY_INFORMATION,IRP_MJ_SET_INFORMATION,IRP_MJ_QUERY_EA,IRP_MJ_SET_EA,IRP_MJ_FLUSH_BUFFERS,IRP_MJ_QUERY_VOLUME_INFORMATION,IRP_MJ_SET_VOLUME_INFORMATION,IRP_MJ_DIRECTORY_CONTROL,IRP_MJ_FILE_SYSTEM_CONTROL,IRP_MJ_DEVICE_CONTROL,IRP_MJ_INTERNAL_DEVICE_CONTROL,IRP_MJ_SHUTDOWN,IRP_MJ_LOCK_CONTROL,IRP_MJ_CLEANUP,IRP_MJ_CREATE_MAILSLOT,IRP_MJ_QUERY_SECURITY,IRP_MJ_SET_SECURITY,IRP_MJ_POWER,IRP_MJ_SYSTEM_CONTROL,IRP_MJ_DEVICE_CHANGE,IRP_MJ_QUERY_QUOTA,IRP_MJ_SET_QUOTA,IRP_MJ_PNP) );
# Built-in levels (for use with manifests)
DEFINE_BUILTIN_LEVEL(win:LogAlways, 0, WINEVENT_LEVEL_LOG_ALWAYS);
DEFINE_BUILTIN_LEVEL(win:Critical, 1, WINEVENT_LEVEL_CRITICAL, TRACE_LEVEL_CRITICAL);
DEFINE_BUILTIN_LEVEL(win:Error, 2, WINEVENT_LEVEL_ERROR, TRACE_LEVEL_ERROR);
DEFINE_BUILTIN_LEVEL(win:Warning, 3, WINEVENT_LEVEL_WARNING, TRACE_LEVEL_WARNING);
DEFINE_BUILTIN_LEVEL(win:Informational, 4, WINEVENT_LEVEL_INFO, TRACE_LEVEL_INFORMATION);
DEFINE_BUILTIN_LEVEL(win:Verbose, 5, WINEVENT_LEVEL_VERBOSE, TRACE_LEVEL_VERBOSE);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel6, 6, WINEVENT_LEVEL_RESERVED_6);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel7, 7, WINEVENT_LEVEL_RESERVED_7);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel8, 8, WINEVENT_LEVEL_RESERVED_8);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel9, 9, WINEVENT_LEVEL_RESERVED_9);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel10, 10, WINEVENT_LEVEL_RESERVED_10);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel11, 11, WINEVENT_LEVEL_RESERVED_11);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel12, 12, WINEVENT_LEVEL_RESERVED_12);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel13, 13, WINEVENT_LEVEL_RESERVED_13);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel14, 14, WINEVENT_LEVEL_RESERVED_14);
DEFINE_BUILTIN_LEVEL(win:ReservedLevel15, 15, WINEVENT_LEVEL_RESERVED_15);
# Built-in keywords (for use with manifests)
DEFINE_BUILTIN_KEYWORD(win:AnyKeyword, 0x0, WINEVT_KEYWORD_ANY);
DEFINE_BUILTIN_KEYWORD(win:ResponseTime, 0x0001000000000000, WINEVENT_KEYWORD_RESPONSE_TIME);
DEFINE_BUILTIN_KEYWORD(win:WDIContext, 0x0002000000000000, WINEVENT_KEYWORD_WDI_CONTEXT);
DEFINE_BUILTIN_KEYWORD(win:WDIDiag, 0x0004000000000000, WINEVENT_KEYWORD_WDI_DIAG);
DEFINE_BUILTIN_KEYWORD(win:SQM, 0x0008000000000000, WINEVENT_KEYWORD_SQM);
DEFINE_BUILTIN_KEYWORD(win:AuditFailure, 0x0010000000000000, WINEVENT_KEYWORD_AUDIT_FAILURE);
DEFINE_BUILTIN_KEYWORD(win:AuditSuccess, 0x0020000000000000, WINEVENT_KEYWORD_AUDIT_SUCCESS);
DEFINE_BUILTIN_KEYWORD(win:CorrelationHint, 0x0040000000000000, WINEVENT_KEYWORD_CORRELATION_HINT);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword56, 0x0100000000000000, WINEVENT_KEYWORD_RESERVED_56);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword57, 0x0200000000000000, WINEVENT_KEYWORD_RESERVED_57);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword58, 0x0400000000000000, WINEVENT_KEYWORD_RESERVED_58);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword59, 0x0800000000000000, WINEVENT_KEYWORD_RESERVED_59);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword60, 0x1000000000000000, WINEVENT_KEYWORDE_RESERVED_60);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword61, 0x2000000000000000, WINEVENT_KEYWORD_RESERVED_61);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword62, 0x4000000000000000, WINEVENT_KEYWORD_RESERVED_62);
DEFINE_BUILTIN_KEYWORD(win:ReservedKeyword63, 0x8000000000000000, WINEVENT_KEYWORD_RESERVED_63);
# default tracing macros
FUNC DoTraceMessage(LEVEL,MSG,...); # Uses WPP-provided ENABLED/LOGGER macros
FUNC DoDebugTrace(TRACELEVEL,MSG,...); # Requires used-defined ENABLED/LOGGER macros
# default prefix (use traceprt default)
USEPREFIX(*,"%!STDPREFIX!"); # traceprt will add standard prefix
# the source file that calls WPP_INIT_TRACING is given special treatment
WPP_FLAGS(-lookfor:WPP_INIT_TRACING);
@@ -0,0 +1,571 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
// This template expects:
// WPP_THIS_FILE defined (see header.tpl)
// WPP_LOGGER_ARG defined
// WPP_GET_LOGGER defined
// WPP_ENABLED() defined
#ifdef __cplusplus
extern "C" {
#endif
#ifdef WPP_ALREADY_INCLUDED
#undef WPP_LOCAL_TraceGuids
#undef WPP_INVOKE_WPP_DEBUG
#else // WPP_ALREADY_INCLUDED
#ifndef NO_CHECK_FOR_NULL_STRING
#ifndef WPP_CHECK_FOR_NULL_STRING
#define WPP_CHECK_FOR_NULL_STRING
#endif
#endif // NO_CHECK_FOR_NULL_STRING
#define WPP_FLATTEN(...) __VA_ARGS__
#define WPP_GLUE5(a, b, c, d, e) a ## b ## c ## d ## e
#define WPP_XGLUE5(a, b, c, d, e) WPP_GLUE5(a, b, c, d, e)
#define WPP_(Id) WPP_XGLUE5(WPP_, Id, _, WPP_THIS_FILE, __LINE__)
#ifndef WPP_INLINE
#define WPP_INLINE DECLSPEC_NOINLINE __inline
#endif
#ifndef WPP_FORCEINLINE
#define WPP_FORCEINLINE __forceinline
#endif
#endif // WPP_ALREADY_INCLUDED
#ifdef WPP_NO_ANNOTATIONS
#define WPP_ANNOTATE(x)
#else // WPP_NO_ANNOTATIONS
`FORALL Msg IN Messages WHERE MsgIsPrivate`
#ifdef WPP_PUBLIC_`Msg.FlagValue`
#define WPP_PUBLIC_ANNOT_`Msg.Name`
#endif
`ENDFOR`
`FORALL Msg IN Messages WHERE MsgIsPublic`
#define WPP_PUBLIC_ANNOT_`Msg.Name`
`ENDFOR`
#ifdef WPP_EMIT_FUNC_NAME
#define WPP_FUNC_NAME L" FUNC=" _WPPW(__FUNCTION__)
#else // WPP_EMIT_FUNC_NAME
#define WPP_FUNC_NAME
#endif // WPP_EMIT_FUNC_NAME
`FORALL Msg IN Messages`
#ifdef WPP_USER_MSG_GUID
# define WPP_ANNOTATE_`Msg.Name`_FINAL(P, File, Name, ...) __annotation( \
L ## P, \
WPP_GUID_WTEXT WPP_USER_MSG_GUID L"`CurrentDir` // SRC=" _WPPW(File) \
L" MJ=`ENV MAJORCOMP` MN=`ENV MINORCOMP`", \
L"#typev " _WPPW(Name) \
L" `Msg.MsgNo` \"`Msg.Text`\" // `Msg.Indent` `Msg.GooPairs`" \
WPP_FUNC_NAME, \
__VA_ARGS__)
#else // WPP_USER_MSG_GUID
# define WPP_ANNOTATE_`Msg.Name`_FINAL(P, File, Name, ...) __annotation( \
L ## P, \
L"`Msg.Guid` `CurrentDir` // SRC=" _WPPW(File) \
L" MJ=`ENV MAJORCOMP` MN=`ENV MINORCOMP`", \
L"#typev " _WPPW(Name) \
L" `Msg.MsgNo` \"`Msg.Text`\" // `Msg.Indent` `Msg.GooPairs`" \
WPP_FUNC_NAME, \
__VA_ARGS__)
#endif // WPP_USER_MSG_GUID
#ifdef WPP_PUBLIC_ANNOT_`Msg.Name`
# define WPP_ANNOTATE_`Msg.Name` WPP_ANNOTATE_`Msg.Name`_FINAL( \
"TMF:", \
"Unknown_cxx00", \
"Unknown_cxx00", \
L"{"`FORALL Arg IN Msg.Arguments`, \
L"Arg, `Arg.MofType` -- `Arg.No`" `ENDFOR Arg`, \
L"}", \
L"PUBLIC_TMF:")
# ifndef WPP_PUBLIC_TMC
# define WPP_PUBLIC_TMC // Adds "PUBLIC_TMF:" to the control guid annotation
# endif
#else // WPP_PUBLIC_ANNOT_`Msg.Name`
# define WPP_ANNOTATE_`Msg.Name` WPP_ANNOTATE_`Msg.Name`_FINAL( \
"TMF:", \
"`SourceFile.Name`", \
"`Msg.Name`", \
L"{"`FORALL Arg IN Msg.Arguments`, \
L"`Arg.Name`, `Arg.MofType` -- `Arg.No`" `ENDFOR Arg`, \
L"}")
#endif // WPP_PUBLIC_ANNOT_`Msg.Name`
`ENDFOR`
# define WPP_ANNOTATE(x) WPP_ANNOTATE_ ## x,
#endif // WPP_NO_ANNOTATIONS
`IF TraceGuids !Empty`
#ifdef WPP_USER_MSG_GUID
#define WPP_LOCAL_MSG_VAR(Guid) WPP_XGLUE3(WPP_, WPP_GUID_NORM Guid, _Traceguids)
#define WPP_LOCAL_MSG_GUID(Guid) \
extern const __declspec(selectany) GUID WPP_LOCAL_MSG_VAR(Guid)[] = { WPP_GUID_STRUCT Guid }
WPP_LOCAL_MSG_GUID(WPP_USER_MSG_GUID);
#define WPP_LOCAL_TraceGuids WPP_LOCAL_MSG_VAR(WPP_USER_MSG_GUID)
#else // WPP_USER_MSG_GUID
#define WPP_LOCAL_TraceGuids WPP_`FORALL Guid IN TraceGuids``Guid.Normalized`_`ENDFOR`Traceguids
extern const __declspec(selectany) GUID WPP_LOCAL_TraceGuids[] = {`FORALL Guid IN TraceGuids` `Guid.Struct`, `ENDFOR`};
#endif // WPP_USER_MSG_GUID
`ENDIF TraceGuids !Empty`
#ifndef WPP_ALREADY_INCLUDED
#ifndef WPP_TRACE_OPTIONS
enum { WPP_TRACE_OPTIONS =
TRACE_MESSAGE_SEQUENCE |
TRACE_MESSAGE_GUID |
TRACE_MESSAGE_SYSTEMINFO |
TRACE_MESSAGE_TIMESTAMP };
#endif // WPP_TRACE_OPTIONS
#ifndef WPP_LOGPAIR_SEPARATOR
# define WPP_LOGPAIR_SEPARATOR ,
#endif
#ifndef WPP_LOGPAIR_SIZET
# define WPP_LOGPAIR_SIZET SIZE_T
#endif
#ifndef WPP_LOGPAIR
# define WPP_LOGPAIR(_Size, _Addr) (_Addr),((WPP_LOGPAIR_SIZET)(_Size))WPP_LOGPAIR_SEPARATOR
#endif
#define WPP_LOGTYPEVAL(_Type, _Value) WPP_LOGPAIR(sizeof(_Type), &(_Value))
#define WPP_LOGTYPEPTR(_Value) WPP_LOGPAIR(sizeof(*(_Value)), (_Value))
// Marshalling macros.
#ifndef WPP_LOGASTR
# ifdef WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGASTR(_value) WPP_LOGPAIR( \
(_value) ? strlen(_value) + 1 : 5, \
(_value) ? (_value) : "NULL" )
# else // WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGASTR(_value) WPP_LOGPAIR( \
strlen(_value) + 1, \
_value )
# endif // WPP_CHECK_FOR_NULL_STRING
#endif // WPP_LOGASTR
#ifndef WPP_LOGWSTR
# ifdef WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGWSTR(_value) WPP_LOGPAIR( \
((_value) ? wcslen(_value) + 1 : 5) * sizeof(WCHAR), \
(_value) ? (_value) : L"NULL" )
# else // WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGWSTR(_value) WPP_LOGPAIR( \
(wcslen(_value) + 1) * sizeof(WCHAR), \
_value )
# endif // WPP_CHECK_FOR_NULL_STRING
#endif // WPP_LOGWSTR
#ifndef WPP_LOGPGUID
# define WPP_LOGPGUID(_value) WPP_LOGPAIR( sizeof(GUID), (_value) )
#endif // WPP_LOGPGUID
#ifndef WPP_LOGPSID
# ifdef WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGPSID(_value) WPP_LOGPAIR( \
(_value) && WPP_IsValidSid(_value) ? WPP_GetLengthSid(_value) : 5, \
(_value) && WPP_IsValidSid(_value) ? (_value) : (void const*)"NULL")
# else // WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGPSID(_value) WPP_LOGPAIR( \
WPP_GetLengthSid(_value), \
(_value) )
#endif // WPP_CHECK_FOR_NULL_STRING
#endif // WPP_LOGPSID
#ifndef WPP_LOGCSTR
# define WPP_LOGCSTR(_x) \
WPP_LOGPAIR( sizeof(USHORT), &(_x).Length ) \
WPP_LOGPAIR( (USHORT)(_x).Length, (USHORT)(_x).Length ? (_x).Buffer : "" )
#endif // WPP_LOGCSTR
#ifndef WPP_LOGUSTR
# define WPP_LOGUSTR(_x) \
WPP_LOGPAIR( sizeof(USHORT), &(_x).Length ) \
WPP_LOGPAIR( (USHORT)(_x).Length, (USHORT)(_x).Length ? (_x).Buffer : L"" )
#endif // WPP_LOGUSTR
#ifndef WPP_LOGPUSTR
#ifdef WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGPUSTR(_x) \
WPP_LOGPAIR( \
sizeof(USHORT), \
(_x) ? &(_x)->Length : (void const*)L"\x08" ) \
WPP_LOGPAIR( \
(_x) ? (USHORT)(_x)->Length : 0x08, \
(_x) && (USHORT)(_x)->Length ? (_x)->Buffer : L"NULL" )
#else // WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGPUSTR(_x) WPP_LOGUSTR(*(_x))
#endif // WPP_CHECK_FOR_NULL_STRING
#endif // WPP_LOGPUSTR
#ifndef WPP_LOGPCSTR
#ifdef WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGPCSTR(_x) \
WPP_LOGPAIR( \
sizeof(USHORT), \
(_x) ? &(_x)->Length : (void const*)L"\x04" ) \
WPP_LOGPAIR( \
(_x) ? (USHORT)(_x)->Length : 0x04, \
(_x) && (USHORT)(_x)->Length ? (_x)->Buffer : "NULL" )
#else // WPP_CHECK_FOR_NULL_STRING
# define WPP_LOGPCSTR(_x) WPP_LOGCSTR(*(_x))
#endif // WPP_CHECK_FOR_NULL_STRING
#endif // WPP_LOGPCSTR
#ifdef __cplusplus
#ifndef WPP_POINTER_TO_USHORT
struct WppPointerToUshort
{
USHORT m_val;
WPP_FORCEINLINE explicit WppPointerToUshort(USHORT val) : m_val(val) {}
WPP_FORCEINLINE USHORT const* get() const { return &m_val; }
};
#define WPP_POINTER_TO_USHORT(val) (WppPointerToUshort((val)).get())
#endif // WPP_POINTER_TO_USHORT
#ifndef WPP_LOGCPPSTR
#define WPP_LOGCPPSTR(_value) \
WPP_LOGPAIR( \
sizeof(USHORT), \
WPP_POINTER_TO_USHORT((USHORT)((_value).size()*sizeof(*(_value).c_str()))) ) \
WPP_LOGPAIR( \
(USHORT)((_value).size()*sizeof(*(_value).c_str())), \
(_value).c_str() )
#endif // WPP_LOGCPPSTR
#ifndef WPP_LOGCPPVEC
#define WPP_LOGCPPVEC(_value) \
WPP_LOGPAIR( \
sizeof(USHORT), \
WPP_POINTER_TO_USHORT((USHORT)((_value).size()*sizeof(*(_value).data()))) ) \
WPP_LOGPAIR( \
(USHORT)((_value).size()*sizeof(*(_value).data())), \
(_value).data() + ((_value).data() == NULL) )
#endif // WPP_LOGCPPVEC
#endif // __cplusplus
#ifndef WPP_BINARY_def
# define WPP_BINARY_def
typedef struct tagWPP_BINARY
{
_Field_size_bytes_(Length) void const* Buffer;
USHORT Length;
} WPP_BINARY;
#endif // WPP_BINARY_def
#ifndef WPP_BINARY_func
# define WPP_BINARY_func
WPP_FORCEINLINE WPP_BINARY
WppBinary(_In_reads_bytes_(Length) void const* Buffer, USHORT Length)
{
WPP_BINARY data;
data.Buffer = Buffer;
data.Length = Length;
return data;
}
#endif // WPP_BINARY_func
#endif // WPP_ALREADY_INCLUDED
#ifndef WPP_ENABLE_FLAG_BIT
#define WPP_ENABLE_FLAG_BIT(flag) (WPP_CB[((flag) >> 16)].Control).Flags[( (0xFFFF & ((flag)-1) ) / 32)] & (1 << ( ((flag)-1) & 31 ))
#endif
`FORALL i IN TypeSigSet WHERE !UnsafeArgs`
#ifndef WPP_SF_`i.Name`_def
# define WPP_SF_`i.Name`_def
WPP_INLINE void WPP_SF_`i.Name`(WPP_LOGGER_ARG unsigned short id, LPCGUID TraceGuid`i.Arguments`)
{ WPP_TRACE(WPP_GET_LOGGER, WPP_TRACE_OPTIONS, (LPGUID)TraceGuid, id, `i.LogArgs` (void*)0); }
#endif // WPP_SF_`i.Name`_def
#if ENABLE_WPP_RECORDER
#if ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER
//
// Generate the WPP_RECORDER_AND_TRACE_SF_`i.Name` function
//
#ifndef WPP_RECORDER_AND_TRACE_SF_`i.Name`_def
#define WPP_RECORDER_AND_TRACE_SF_`i.Name`_def
WPP_INLINE
VOID
WPP_RECORDER_AND_TRACE_SF_`i.Name`(
WPP_LOGGER_ARG
BOOLEAN wppEnabled,
BOOLEAN recorderEnabled,
PVOID AutoLogContext,
UCHAR level,
ULONG flags,
USHORT id,
LPCGUID traceGuid
`i.Arguments`
)
{
if (wppEnabled)
{
WPP_TRACE( WPP_GET_LOGGER,
WPP_TRACE_OPTIONS,
(LPGUID)traceGuid,
id,
`i.LogArgs` (void*)0);
}
if (recorderEnabled)
{
WPP_RECORDER( AutoLogContext, level, flags, (LPGUID) traceGuid, id, `i.LogArgs` (void*)0 );
}
}
#endif // WPP_RECORDER_AND_TRACE_SF_`i.Name`_def
#else // ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER
//
// Generate the WPP_RECORDER_SP_`i.Name` function
//
#ifndef WPP_RECORDER_SF_`i.Name`_def
#define WPP_RECORDER_SF_`i.Name`_def
WPP_INLINE
VOID
WPP_RECORDER_SF_`i.Name`(
PVOID AutoLogContext,
UCHAR level,
ULONG flags,
USHORT id,
LPCGUID traceGuid
`i.Arguments`
)
{
if (WPP_ENABLE_FLAG_BIT(flags) &&
(WPP_CONTROL(flags).Level >= level))
{
WPP_TRACE(
WPP_CONTROL(flags).Logger,
WPP_TRACE_OPTIONS,
(LPGUID)traceGuid,
id,
`i.LogArgs` (void*)0);
}
WPP_RECORDER(AutoLogContext, level, flags, (LPGUID) traceGuid, id, `i.LogArgs` (void*)0);
}
#endif // WPP_RECORDER_SF_`i.Name`_def
#endif // ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER
#endif // ENABLE_WPP_RECORDER
`ENDFOR`
`FORALL i IN TypeSigSet WHERE UnsafeArgs`
#ifndef WPP_SF_`i.Name`_def
#define WPP_SF_`i.Name`_def
WPP_INLINE void WPP_SF_`i.Name`(WPP_LOGGER_ARG unsigned short id, LPCGUID TraceGuid, ...)
{
va_list ap;
va_start(ap, TraceGuid);
UNREFERENCED_PARAMETER(ap);
{
`i.DeclVars`
WPP_TRACE(
WPP_GET_LOGGER,
WPP_TRACE_OPTIONS,
(LPGUID)TraceGuid,
id,
`i.LogArgs` (void*)0);
}
}
#endif // WPP_SF_`i.Name`_def
`ENDFOR`
// WPP_LOG_ALWAYS:
// Called for each event: WPP_LOG_ALWAYS(EX, MSG, arg1, arg2, arg3...) Other()
// If defined, the definition needs to include a trailing comma or semicolon.
// In addition, you will need to define a WPP_EX_[args](args...) macro to
// extract any needed information from the other arguments (e.g. LEVEL).
#ifndef WPP_LOG_ALWAYS
#define WPP_LOG_ALWAYS(...)
#endif
// WPP_DEBUG:
// Called for each enabled event: WPP_DEBUG((MSG, arg1, arg2, arg3...)), Other()
// Potential definition: printf MsgArgs
// Definition should not include any trailing comma or semicolon.
#ifdef WPP_DEBUG
#define WPP_INVOKE_WPP_DEBUG(MsgArgs) WPP_DEBUG(MsgArgs)
#else // WPP_DEBUG
#define WPP_INVOKE_WPP_DEBUG(MsgArgs) (void)0
#endif // WPP_DEBUG
`FORALL i IN Messages WHERE !MsgArgs`
// WPP_CALL_`i.Name`
#ifndef WPP`i.GooId`_PRE
# define WPP`i.GooId`_PRE(`i.GooArgs`)
#endif
#ifndef WPP`i.GooId`_POST
# define WPP`i.GooId`_POST(`i.GooArgs`)
#endif
#if ENABLE_WPP_RECORDER
#if ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER
#define WPP_CALL_`i.Name`(`i.FixedArgs``i.MacroArgs`) \
WPP_LOG_ALWAYS(WPP_EX`i.GooId`(`i.GooVals`), `i.DbgMacroArgs`) \
WPP`i.GooId`_PRE(`i.GooVals`) \
do {\
WPP_ANNOTATE(`i.Name`) 0; \
BOOLEAN wppEnabled = WPP_CHECK_INIT `i.MsgVal`WPP`i.GooId`_ENABLED(`i.GooVals`); \
BOOLEAN recorderEnabled = WPP_RECORDER_CHECK_INIT `i.MsgVal`WPP_RECORDER`i.GooId`_FILTER(`i.GooVals`); \
if (wppEnabled || recorderEnabled) { \
WPP_INVOKE_WPP_DEBUG((`i.DbgMacroArgs`)); \
WPP_RECORDER_AND_TRACE_SF_`i.TypeSig`( \
WPP`i.GooId`_LOGGER(`i.GooVals`) \
wppEnabled, recorderEnabled, \
WPP_RECORDER`i.GooId`_ARGS(`i.GooVals`), \
`i.MsgNo`, \
WPP_LOCAL_TraceGuids+0`i.MacroExprs`);\
} \
} \
while(0) \
WPP`i.GooId`_POST(`i.GooVals`)
#else // ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER
#define WPP_CALL_`i.Name`(`i.FixedArgs``i.MacroArgs`) \
WPP_LOG_ALWAYS(WPP_EX`i.GooId`(`i.GooVals`), `i.DbgMacroArgs`) \
WPP`i.GooId`_PRE(`i.GooVals`) \
WPP_ANNOTATE(`i.Name`) \
(( \
WPP_RECORDER_CHECK_INIT `i.MsgVal`WPP_RECORDER`i.GooId`_FILTER(`i.GooVals`) \
? WPP_INVOKE_WPP_DEBUG((`i.DbgMacroArgs`)), \
WPP_RECORDER_SF_`i.TypeSig`( \
WPP_RECORDER`i.GooId`_ARGS(`i.GooVals`), \
`i.MsgNo`, \
WPP_LOCAL_TraceGuids+0`i.MacroExprs`), \
1 \
: 0 \
)) \
WPP`i.GooId`_POST(`i.GooVals`)
#endif // ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER
#else // ENABLE_WPP_RECORDER
#define WPP_CALL_`i.Name`(`i.FixedArgs``i.MacroArgs`) \
WPP_LOG_ALWAYS(WPP_EX`i.GooId`(`i.GooVals`), `i.DbgMacroArgs`) \
WPP`i.GooId`_PRE(`i.GooVals`) \
WPP_ANNOTATE(`i.Name`) \
(( \
WPP_CHECK_INIT `i.MsgVal`WPP`i.GooId`_ENABLED(`i.GooVals`) \
? WPP_INVOKE_WPP_DEBUG((`i.DbgMacroArgs`)), \
WPP_SF_`i.TypeSig`( \
WPP`i.GooId`_LOGGER(`i.GooVals`) \
`i.MsgNo`, \
WPP_LOCAL_TraceGuids+0`i.MacroExprs`), \
1 \
: 0 \
)) \
WPP`i.GooId`_POST(`i.GooVals`)
#endif // ENABLE_WPP_RECORDER
`ENDFOR`
`FORALL i IN Messages WHERE MsgArgs`
// WPP_CALL_`i.Name`
#ifndef WPP`i.GooId`_PRE
# define WPP`i.GooId`_PRE(`i.GooArgs`)
#endif
#ifndef WPP`i.GooId`_POST
# define WPP`i.GooId`_POST(`i.GooArgs`)
#endif
#if ENABLE_WPP_RECORDER
#define WPP_CALL_`i.Name`(`i.FixedArgs` MSGARGS) \
WPP_LOG_ALWAYS(WPP_EX`i.GooId`(`i.GooVals`), WPP_FLATTEN MSGARGS) \
WPP`i.GooId`_PRE(`i.GooVals`) \
WPP_ANNOTATE(`i.Name`) \
(( \
WPP_RECORDER_CHECK_INIT `i.MsgVal`WPP_RECORDER`i.GooId`_FILTER(`i.GooVals`) \
? WPP_INVOKE_WPP_DEBUG(MSGARGS), \
WPP_RECORDER_SF_`i.TypeSig`( \
WPP_RECORDER`i.GooId`_ARGS(`i.GooVals`), \
`i.MsgNo`, \
WPP_LOCAL_TraceGuids+0 `i.SyntheticExprs`WPP_R`i.ReorderSig` MSGARGS), \
1 \
: 0 \
)) \
WPP`i.GooId`_POST(`i.GooVals`)
#else // ENABLE_WPP_RECORDER
#define WPP_CALL_`i.Name`(`i.FixedArgs` MSGARGS) \
WPP_LOG_ALWAYS(WPP_EX`i.GooId`(`i.GooVals`), WPP_FLATTEN MSGARGS) \
WPP`i.GooId`_PRE(`i.GooVals`) \
WPP_ANNOTATE(`i.Name`) \
(( \
WPP_CHECK_INIT WPP`i.GooId`_ENABLED(`i.GooVals`) \
? WPP_INVOKE_WPP_DEBUG(MSGARGS), \
WPP_SF_`i.TypeSig`( \
WPP`i.GooId`_LOGGER(`i.GooVals`) \
`i.MsgNo`, \
WPP_LOCAL_TraceGuids+0 `i.SyntheticExprs`WPP_R`i.ReorderSig` MSGARGS),\
1 \
: 0 \
)) \
WPP`i.GooId`_POST(`i.GooVals`)
#endif // ENABLE_WPP_RECORDER
`ENDFOR`
// Functions
`FORALL f IN Funcs WHERE !DoubleP && !MsgArgs && !NoMsg`
#undef `f.Name`
#ifdef __INTELLISENSE__
#define `f.Name`(`f.FixedArgs`MSG, ...) ((void)(MSG, ## __VA_ARGS__))
#else
#define `f.Name` WPP_(CALL)
#endif
`ENDFOR`
`FORALL f IN Funcs WHERE !DoubleP && !MsgArgs && NoMsg`
#undef `f.Name`
#ifdef __INTELLISENSE__
#define `f.Name`(`f.FixedArgs`) ((void)0)
#else
#define `f.Name` WPP_(CALL)
#endif
`ENDFOR`
`FORALL f IN Funcs WHERE DoubleP && !MsgArgs`
#undef `f.Name`
#ifdef __INTELLISENSE__
#define `f.Name`(ARGS) ((void)ARGS)
#else
#define `f.Name`(ARGS) WPP_(CALL) ARGS
#endif
`ENDFOR`
`FORALL f IN Funcs WHERE MsgArgs`
#undef `f.Name`
#ifdef __INTELLISENSE__
#define `f.Name`(`f.FixedArgs`MSGARGS) ((void)(MSGARGS))
#else
#define `f.Name`(`f.FixedArgs`MSGARGS) WPP_(CALL)(`f.FixedArgs`MSGARGS)
#endif
`ENDFOR`
`FORALL r IN Reorder`
#undef WPP_R`r.Name`
#define WPP_R`r.Name`(`r.Arguments`) `r.Permutation`
`ENDFOR`
#ifdef __cplusplus
} // extern "C"
#endif
@@ -0,0 +1,20 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// `Compiler.Checksum` Generated file. Do not edit.
// File created by `Compiler.Name` compiler version `Compiler.Version`
// from template `TemplateFile`
#pragma once
`INCLUDE um-header.tpl`
`INCLUDE control.tpl`
`INCLUDE tracemacro.tpl`
`IF FOUND WPP_INIT_TRACING`
` INCLUDE um-init.tpl`
`ENDIF`
@@ -0,0 +1,222 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
#ifdef WPP_THIS_FILE
// included twice
# define WPP_ALREADY_INCLUDED
# undef WPP_THIS_FILE
#endif // #ifdef WPP_THIS_FILE
#define WPP_THIS_FILE `SourceFile.CanonicalName`
#ifndef WPP_ALREADY_INCLUDED
`* Dump the definitions specified via -D on the command line to WPP *`
`FORALL def IN MacroDefinitions`
#define `def.Name` `def.Alias`
`ENDFOR`
#ifdef BUILD_MINWIN
#include <windowscore.h>
#else
#include <windows.h>
#endif
#include <wmistr.h>
#include <evntrace.h>
#ifndef WPP_TRACE_W2K_COMPATABILITY
#include <sddl.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// LEGACY: This structure was used by Win2k RpcRt4 and cluster tracing
typedef struct _WPP_WIN2K_CONTROL_BLOCK {
TRACEHANDLE Logger;
ULONG Flags;
ULONG Level;
LPCGUID ControlGuid;
} WPP_WIN2K_CONTROL_BLOCK, *PWPP_WIN2K_CONTROL_BLOCK;
#pragma warning(push)
#pragma warning(disable:4201) // nonstandard extension used nameless struct/union
typedef struct _WPP_TRACE_CONTROL_BLOCK
{
struct _WPP_TRACE_CONTROL_BLOCK *Next;
TRACEHANDLE UmRegistrationHandle;
union {
TRACEHANDLE Logger;
PWPP_WIN2K_CONTROL_BLOCK Win2kCb;
PVOID Ptr;
struct _WPP_TRACE_CONTROL_BLOCK *Cb;
};
UCHAR FlagsLen;
UCHAR Level;
USHORT Options;
ULONG Flags[1];
LPCGUID ControlGuid;
#if ENABLE_WPP_RECORDER
PVOID AutoLogContext;
USHORT AutoLogVerboseEnabled;
USHORT AutoLogAttachToMiniDump;
#endif
} WPP_TRACE_CONTROL_BLOCK, *PWPP_TRACE_CONTROL_BLOCK;
#pragma warning(pop)
#ifdef WPP_USE_NTDLL_FUNCTIONS
// Not supported.
#include <wpp_use_ntdll_functions.h>
#endif
#define WPP_IsValidSid IsValidSid
#define WPP_GetLengthSid GetLengthSid
#ifndef WPP_TRACE
#define WPP_TRACE TraceMessage
#endif
#ifndef WPP_UNREGISTER_TRACE_GUIDS
#define WPP_UNREGISTER_TRACE_GUIDS UnregisterTraceGuids
#endif
#ifndef WPP_REGISTER_TRACE_GUIDS
#define WPP_REGISTER_TRACE_GUIDS RegisterTraceGuids
#endif
#ifndef WPP_GET_TRACE_LOGGER_HANDLE
#define WPP_GET_TRACE_LOGGER_HANDLE GetTraceLoggerHandle
#endif
#ifndef WPP_GET_TRACE_ENABLE_LEVEL
#define WPP_GET_TRACE_ENABLE_LEVEL GetTraceEnableLevel
#endif
#ifndef WPP_GET_TRACE_ENABLE_FLAGS
#define WPP_GET_TRACE_ENABLE_FLAGS GetTraceEnableFlags
#endif
enum {
WPP_VER_WIN2K_CB_FORWARD_PTR = 0x01,
WPP_VER_WHISTLER_CB_FORWARD_PTR = 0x02,
WPP_VER_LH_CB_FORWARD_PTR = 0x03
};
#if ENABLE_WPP_RECORDER
#ifndef WPP_RECORDER
#define WPP_RECORDER WppAutoLogTrace
#endif
//
// This setting is only applicable when IFR is enabled.
// Setting this to 1 will allow a WPP trace session to
// capture trace messages as usual i.e it will require the
// user to provide WPP trace ENABLED and LOGGER macro. If
// this is set to 0 by default the IFR trace filter also
// affects which trace messages land in the WPP trace session.
//
#if !defined(ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER)
#define ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER 0
#endif
#if !defined(WPP_RECORDER_LEVEL_FLAGS_ARGS)
#define WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags) WPP_CONTROL(WPP_BIT_ ## flags).AutoLogContext, lvl, WPP_BIT_ ## flags
#define WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl,flags) (lvl < TRACE_LEVEL_VERBOSE || WPP_CONTROL(WPP_BIT_ ## flags).AutoLogVerboseEnabled)
#endif
#if !defined(WPP_RECORDER_FLAGS_LEVEL_ARGS)
#define WPP_RECORDER_FLAGS_LEVEL_ARGS(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_ARGS(lvl, flags)
#define WPP_RECORDER_FLAGS_LEVEL_FILTER(flags, lvl) WPP_RECORDER_LEVEL_FLAGS_FILTER(lvl, flags)
#endif
#if !defined(WPP_RECORDER_LEVEL_ARGS)
#define WPP_RECORDER_LEVEL_ARGS(lvl) WPP_CONTROL(WPP_BIT_ ## lvl).AutoLogContext, 0, WPP_BIT_ ## lvl
#define WPP_RECORDER_LEVEL_FILTER(lvl) (WPP_CONTROL(WPP_BIT_ ## lvl).AutoLogVerboseEnabled)
#endif
NTSTATUS
WppAutoLogTrace(
_In_ PVOID AutoLogContext,
_In_ UCHAR MessageLevel,
_In_ ULONG MessageFlags,
_In_ LPGUID MessageGuid,
_In_ USHORT MessageNumber,
_In_ ...
);
#endif // ENABLE_WPP_RECORDER
//
// WPP_INIT_TRACING and WPP_CLEANUP macros are defined differently for kernel
// mode and user mode. In order to support mode-agnostic WDF drivers,
// WPP_INIT_TRACING and WPP_CLEANUP macros for UMDF 2.x user-mode drivers are
// being updated to be same as kernel mode macros. This difference is based
// upon the macro WPP_MACRO_USE_KM_VERSION_FOR_UM.
//
#ifdef WPP_MACRO_USE_KM_VERSION_FOR_UM
VOID WppCleanupUm( VOID );
#define WPP_CLEANUP(DrvObj) WppCleanupUm()
#else
VOID WppCleanupUm( VOID );
#define WPP_CLEANUP() WppCleanupUm()
#endif
#define WppLoadTracingSupport
//
// For getting private callback, implement a function with the signature below.
// To register the function: #define WPP_PRIVATE_ENABLE_CALLBACK MyPrivateCallback
// If multiple control guids are used, be sure to compare Guid to the one of interest.
//
#if defined(WPP_PRIVATE_ENABLE_CALLBACK)
typedef
VOID
(NTAPI *PFN_WPP_PRIVATE_ENABLE_CALLBACK)(
_In_ LPCGUID Guid,
_In_ TRACEHANDLE Logger,
_In_ BOOLEAN Enable,
_In_ ULONG Flags,
_In_ UCHAR Level
);
#endif
//
// For generating CAPTURE_STATE callback (Win7+), implement a function with the signature
// below. To register the function: #define WPP_CAPTURE_STATE_CALLBACK MyCaptureStateCallback
// If multiple control guids are used, be sure to compare Guid to the one of interest.
//
#if defined(WPP_CAPTURE_STATE_CALLBACK)
typedef
VOID
(NTAPI *PFN_WPP_CAPTURE_STATE_CALLBACK)(
_In_ LPCGUID Guid,
_In_ TRACEHANDLE Logger,
_In_ ULONG Flags,
_In_ UCHAR Level
);
#endif
#ifdef __cplusplus
} // extern "C"
#endif
#endif // #ifndef WPP_ALREADY_INCLUDED
@@ -0,0 +1,677 @@
`**********************************************************************`
`* This is an include template file for the tracewpp preprocessor. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
// template `TemplateFile`
//
// Defines a set of functions that simplifies
// user mode registration for tracing
//
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WPPINIT_EXPORT
#define WPPINIT_EXPORT
#endif
#ifndef WppDebug
#define WppDebug(a,b)
#endif
#define __WARNING_BANNED_LEGACY_INSTRUMENTATION_API_USAGE 28735
#if ENABLE_WPP_RECORDER
#ifdef WPP_MACRO_USE_KM_VERSION_FOR_UM
WPPINIT_EXPORT
VOID
__cdecl
WppAutoLogStart(
_In_ WPP_CB_TYPE * WppCb,
_In_ PDRIVER_OBJECT DrvObj,
_In_ PCUNICODE_STRING RegPath
);
#else
WPPINIT_EXPORT
VOID
__cdecl
WppAutoLogStart(
_In_ WPP_CB_TYPE * WppCb,
_In_ PVOID DrvObj,
_In_ PCUNICODE_STRING RegPath
);
#endif // WPP_MACRO_USE_KM_VERSION_FOR_UM
WPPINIT_EXPORT
VOID
__cdecl
WppAutoLogStop(
_In_ WPP_CB_TYPE * WppCb
);
#endif // ENABLE_WPP_RECORDER
// define annotation record that will carry control information to pdb (in case somebody needs it)
WPP_FORCEINLINE void WPP_CONTROL_ANNOTATION() {
#if !defined(WPP_NO_ANNOTATIONS)
#ifndef WPP_TMC_ANNOT_SUFIX
#ifdef WPP_PUBLIC_TMC
#define WPP_TMC_ANNOT_SUFIX ,L"PUBLIC_TMF:"
#else
#define WPP_TMC_ANNOT_SUFIX
#endif
#endif
# define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) __annotation(L"TMC:", WPP_GUID_WTEXT Guid, _WPPW(WPP_STRINGIZE(Name)) Bits WPP_TMC_ANNOT_SUFIX);
# define WPP_DEFINE_BIT(Name) , _WPPW(#Name)
WPP_CONTROL_GUIDS
# undef WPP_DEFINE_BIT
# undef WPP_DEFINE_CONTROL_GUID
#endif
}
LPCGUID WPP_REGISTRATION_GUIDS[WPP_LAST_CTL];
WPP_CB_TYPE WPP_MAIN_CB[WPP_LAST_CTL];
#define WPP_NEXT(Name) ((WPP_TRACE_CONTROL_BLOCK*) \
(WPP_XGLUE(WPP_CTL_, WPP_EVAL(Name)) + 1 == WPP_LAST_CTL ? 0:WPP_MAIN_CB + WPP_XGLUE(WPP_CTL_, WPP_EVAL(Name)) + 1))
#if ENABLE_WPP_RECORDER
#define INIT_WPP_RECORDER(Arr) \
Arr->Control.AutoLogContext = NULL; \
Arr->Control.AutoLogVerboseEnabled = 0x0; \
Arr->Control.AutoLogAttachToMiniDump = 0x0;
#else
#define INIT_WPP_RECORDER(Arr)
#endif
__inline void WPP_INIT_CONTROL_ARRAY(WPP_CB_TYPE* Arr) {
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) \
Arr->Control.Ptr = NULL; \
Arr->Control.Next = WPP_NEXT(WPP_EVAL(Name)); \
Arr->Control.FlagsLen = WPP_FLAG_LEN; \
Arr->Control.Level = 0; \
Arr->Control.Options = 0; \
Arr->Control.Flags[0] = 0; \
INIT_WPP_RECORDER(Arr) \
++Arr;
#define WPP_DEFINE_BIT(BitName) L" " L ## #BitName
WPP_CONTROL_GUIDS
#undef WPP_DEFINE_BIT
#undef WPP_DEFINE_CONTROL_GUID
}
#undef WPP_INIT_STATIC_DATA
#define WPP_INIT_STATIC_DATA WPP_INIT_CONTROL_ARRAY(WPP_MAIN_CB)
__inline void WPP_INIT_GUID_ARRAY(LPCGUID* Arr) {
#define WPP_DEFINE_CONTROL_GUID(Name,Guid,Bits) \
WPP_XGLUE4(*Arr = &WPP_, ThisDir, _CTLGUID_, WPP_EVAL(Name)); \
++Arr;
WPP_CONTROL_GUIDS
#undef WPP_DEFINE_CONTROL_GUID
}
VOID WppInitUm(_In_opt_ LPCWSTR AppName);
//
// WPP_INIT_TRACING and WPP_CLEANUP macros are defined differently for kernel
// mode and user mode. In order to support mode-agnostic WDF drivers,
// WPP_INIT_TRACING and WPP_CLEANUP macros for UMDF 2.x user-mode drivers are
// being updated to be same as kernel mode macros. This difference is based
// upon the macro WPP_MACRO_USE_KM_VERSION_FOR_UM.
//
#ifdef WPP_MACRO_USE_KM_VERSION_FOR_UM
VOID WppInitUmDriver(
_In_ PDRIVER_OBJECT DrvObject,
_In_ PCUNICODE_STRING RegPath
);
VOID WppInitUm(_In_opt_ LPCWSTR AppName);
#ifndef WPP_MACRO_USE_KM_VERSION_FOR_UM_IGNORE_VALIDATION
//
// To reduce confusion due to this breaking change, we have overloaded
// WPP_INIT_TRACING with some macro wizardry to notify the developer
// if (s)he is using the deprecated single argument version.
//
// Example of how this works:
//
// 1) WPP_INIT_TRACING is called with two parameters, X and Y.
// 2) FX_WPP_COUNT_ARGUMENTS is called, but due to a bug with VC++ __VA_ARGS__ remains as a single token.
// 3) FX_WPP_EXPAND_ARGUMENTS expands the argument list to (X, Y, 2, 1, 0)
// 4) FX_WPP_DETERMINE_MACRO_NAME puts X into _1_, Y into _2_, 2 into Count (the value we want),
// and the rest into "..." which are discarded. Count is then combined with WPP_INIT_TRACING.
// 5) WPP_GLUE combines "WPP_INIT_TRACING2" with "(X, Y)" giving us our function call: WPP_INIT_TRACING2(X,Y)
//
#define FX_WPP_DETERMINE_MACRO_NAME(_1_, _2_, Count, ...) WPP_INIT_TRACING##Count
#define FX_WPP_EXPAND_ARGUMENTS(Args) FX_WPP_DETERMINE_MACRO_NAME Args
#define FX_WPP_COUNT_ARGUMENTS(...) FX_WPP_EXPAND_ARGUMENTS((__VA_ARGS__, 2, 1, 0))
#define WPP_INIT_TRACING(...) WPP_GLUE(FX_WPP_COUNT_ARGUMENTS(__VA_ARGS__),(__VA_ARGS__))
//
// _pragma(message("...")) doesn't work with newline characters. "ERROR..." is an
// undocumented keyword in visual studio that causes an error, but this is ignored by razzle.
// Instead we use an undeclared identifier.
//
#define WPP_INIT_TRACING1(AppName) \
__pragma(message("ERROR: This version of WPP_INIT_TRACING has been deprecated from UMDF 2.15 onwards")) \
__pragma(message("WPP_INIT_TRACING( ")) \
__pragma(message(" _In_ PDRIVER_OBJECT DriverObject, ")) \
__pragma(message(" _In_ PUNICODE_STRING RegistryPath ")) \
__pragma(message("); ")) \
__pragma(message("WPP_CLEANUP( ")) \
__pragma(message(" _In_ PDRIVER_OBJECT DriverObject ")) \
__pragma(message(");" )) \
__pragma(message("Please refer to the MSDN documentation on WPP tracing for more information.")) \
WPP_INIT_TRACING_FUNCTION_IS_DEPRECATED_PLEASE_REFER_TO_BUILD_LOG_FOR_MORE_INFORMATION;
#define WPP_INIT_TRACING2(DrvObj, RegPath) \
WppLoadTracingSupport; \
(WPP_CONTROL_ANNOTATION(),WPP_INIT_STATIC_DATA, \
WPP_INIT_GUID_ARRAY((LPCGUID*)&WPP_REGISTRATION_GUIDS), \
WPP_CB= WPP_MAIN_CB, \
WppInitUmDriver(DrvObj, RegPath))
#else
#define WPP_INIT_TRACING(DrvObj, RegPath) \
WppLoadTracingSupport; \
(WPP_CONTROL_ANNOTATION(),WPP_INIT_STATIC_DATA, \
WPP_INIT_GUID_ARRAY((LPCGUID*)&WPP_REGISTRATION_GUIDS), \
WPP_CB= WPP_MAIN_CB, \
WppInitUmDriver(DrvObj, RegPath))
#endif // WPP_MACRO_USE_KM_VERSION_FOR_UM_IGNORE_VALIDATION
#else
#define WPP_INIT_TRACING(AppName) \
WppLoadTracingSupport; \
(WPP_CONTROL_ANNOTATION(),WPP_INIT_STATIC_DATA, \
WPP_INIT_GUID_ARRAY((LPCGUID*)&WPP_REGISTRATION_GUIDS), \
WPP_CB= WPP_MAIN_CB, \
WppInitUm(AppName))
#endif // WPP_MACRO_USE_KM_VERSION_FOR_UM
void WPP_Set_Dll_CB(
PWPP_TRACE_CONTROL_BLOCK Control,
VOID * DllControlBlock,
USHORT Flags)
{
if (*(PVOID*)DllControlBlock != DllControlBlock){
Control->Ptr = DllControlBlock;
} else {
if (Flags == WPP_VER_WHISTLER_CB_FORWARD_PTR ){
memset(Control, 0, sizeof(WPP_TRACE_CONTROL_BLOCK));
*(PWPP_TRACE_CONTROL_BLOCK*)DllControlBlock = Control;
Control->Options = WPP_VER_LH_CB_FORWARD_PTR;
}
}
}
#define WPP_SET_FORWARD_PTR(CTL, FLAGS, PTR) (\
(WPP_MAIN_CB[WPP_CTRL_NO(WPP_BIT_ ## CTL )].Control.Options = (FLAGS)));\
WPP_Set_Dll_CB(&WPP_MAIN_CB[WPP_CTRL_NO(WPP_BIT_ ## CTL )].Control,(PTR),(USHORT)FLAGS)
#define DEFAULT_LOGGER_NAME L"stdout"
#if !defined(WPPINIT_STATIC)
# define WPPINIT_STATIC
#endif
#define WPP_GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#define WPP_GUID_ELEMENTS(p) \
p->Data1, p->Data2, p->Data3,\
p->Data4[0], p->Data4[1], p->Data4[2], p->Data4[3],\
p->Data4[4], p->Data4[5], p->Data4[6], p->Data4[7]
#define WPP_MAX_LEVEL 255
#define WPP_MAX_FLAGS 0xFFFFFFFF
#if defined (WPP_GLOBALLOGGER)
__inline
TRACEHANDLE
WppQueryLogger(
_In_opt_ PCWSTR LoggerName
)
{
ULONG Status;
EVENT_TRACE_PROPERTIES LoggerInfo;
ZeroMemory(&LoggerInfo, sizeof(LoggerInfo));
LoggerInfo.Wnode.BufferSize = sizeof(LoggerInfo);
LoggerInfo.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
Status = ControlTraceW(0, LoggerName ? LoggerName : L"stdout", &LoggerInfo, EVENT_TRACE_CONTROL_QUERY);
if (Status == ERROR_SUCCESS || Status == ERROR_MORE_DATA) {
return (TRACEHANDLE) LoggerInfo.Wnode.HistoricalContext;
}
return 0;
}
#define WPP_REG_GLOBALLOGGER_FLAGS L"Flags"
#define WPP_REG_GLOBALLOGGER_LEVEL L"Level"
#define WPP_REG_GLOBALLOGGER_START L"Start"
#define WPP_TEXTGUID_LEN 38
#define WPP_REG_GLOBALLOGGER_KEY L"SYSTEM\\CurrentControlSet\\Control\\Wmi\\GlobalLogger"
WPPINIT_STATIC
void WppIntToHex(
_Out_writes_(digits) PWCHAR Buf,
unsigned int value,
int digits
)
{
static LPCWSTR hexDigit = L"0123456789abcdef";
while (--digits >= 0) {
Buf[digits] = hexDigit[ value & 15 ];
value /= 16;
}
}
WPPINIT_EXPORT
void WppInitGlobalLogger(
IN LPCGUID ControlGuid,
IN PTRACEHANDLE LoggerHandle,
OUT PULONG Flags,
_Out_writes_(sizeof(UCHAR)) PUCHAR Level )
{
WCHAR GuidBuf[WPP_TEXTGUID_LEN];
ULONG CurrentFlags = 0;
ULONG CurrentLevel = 0;
DWORD Start = 0;
DWORD DataSize ;
ULONG Status ;
HKEY GloblaLoggerHandleKey;
HKEY ValueHandleKey ;
WppDebug(0,("WPP checking Global Logger %S",WPP_REG_GLOBALLOGGER_KEY));
if ((Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
(LPWSTR)WPP_REG_GLOBALLOGGER_KEY,
0,
KEY_READ,
&GloblaLoggerHandleKey
)) != ERROR_SUCCESS) {
WppDebug(0,("GlobalLogger key does not exist (0x%08X)",Status));
return ;
}
DataSize = sizeof(DWORD);
Status = RegQueryValueExW(GloblaLoggerHandleKey,
(LPWSTR)WPP_REG_GLOBALLOGGER_START,
0,
NULL,
(LPBYTE)&Start,
&DataSize);
if (Status != ERROR_SUCCESS || Start == 0 ) {
WppDebug(0,("Global Logger not started (0x%08X)",Status));
goto Cleanup;
}
WppDebug(0,("Global Logger exists and is set to be started"));
{
static LPCWSTR hexDigit = L"0123456789abcdef";
int i;
WppIntToHex(GuidBuf, ControlGuid->Data1, 8);
GuidBuf[8] = '-';
WppIntToHex(&GuidBuf[9], ControlGuid->Data2, 4);
GuidBuf[13] = '-';
WppIntToHex(&GuidBuf[14], ControlGuid->Data3, 4);
GuidBuf[18] = '-';
GuidBuf[19] = hexDigit[(ControlGuid->Data4[0] & 0xF0) >> 4];
GuidBuf[20] = hexDigit[ControlGuid->Data4[0] & 0x0F ];
GuidBuf[21] = hexDigit[(ControlGuid->Data4[1] & 0xF0) >> 4];
GuidBuf[22] = hexDigit[ControlGuid->Data4[1] & 0x0F ];
GuidBuf[23] = '-';
for( i=2; i < 8 ; i++ ){
GuidBuf[i*2+20] = hexDigit[(ControlGuid->Data4[i] & 0xF0) >> 4];
GuidBuf[i*2+21] = hexDigit[ControlGuid->Data4[i] & 0x0F ];
}
GuidBuf[36] = 0;
}
//
// Perform the query
//
if ((Status = RegOpenKeyExW(GloblaLoggerHandleKey,
(LPWSTR)GuidBuf,
0,
KEY_READ,
&ValueHandleKey
)) != ERROR_SUCCESS) {
WppDebug(0,("Global Logger Key not set for this Control Guid %S (0x%08X)",GuidBuf,Status));
goto Cleanup;
}
// Get the Flags Parameter
DataSize = sizeof(DWORD);
Status = RegQueryValueExW(ValueHandleKey,
(LPWSTR)WPP_REG_GLOBALLOGGER_FLAGS,
0,
NULL,
(LPBYTE)&CurrentFlags,
&DataSize);
if (Status != ERROR_SUCCESS || CurrentFlags == 0 ) {
WppDebug(0,("GlobalLogger for %S Flags not set (0x%08X)",GuidBuf,Status));
}
// Get the levels Parameter
DataSize = sizeof(DWORD);
Status = RegQueryValueExW(ValueHandleKey,
(LPWSTR)WPP_REG_GLOBALLOGGER_LEVEL,
0,
NULL,
(LPBYTE)&CurrentLevel,
&DataSize);
if (Status != ERROR_SUCCESS || CurrentLevel == 0 ) {
WppDebug(0,("GlobalLogger for %S Level not set (0x%08X)",GuidBuf,Status));
}
if (Start==1) {
if ((*LoggerHandle= WppQueryLogger( L"GlobalLogger")) != (TRACEHANDLE)NULL) {
*Flags = CurrentFlags & 0x7FFFFFFF ;
*Level = (UCHAR)(CurrentLevel & 0xFF) ;
WppDebug(0,("WPP Enabled via Global Logger Flags=0x%08X Level=0x%02X",CurrentFlags,CurrentLevel));
} else {
WppDebug(0,("GlobalLogger set for start but not running (Flags=0x%08X Level=0x%02X)",CurrentFlags,CurrentLevel));
}
}
RegCloseKey(ValueHandleKey);
Cleanup:
RegCloseKey(GloblaLoggerHandleKey);
}
#endif //#ifdef WPP_GLOBALLOGGER
#ifdef WPP_MANAGED_CPP
#pragma managed(push, off)
#endif
ULONG
__stdcall
WppControlCallback(
IN WMIDPREQUESTCODE RequestCode,
IN PVOID Context,
_Inout_ ULONG *InOutBufferSize,
_Inout_ PVOID Buffer
)
{
PWPP_TRACE_CONTROL_BLOCK Ctx = (PWPP_TRACE_CONTROL_BLOCK)Context;
TRACEHANDLE Logger;
UCHAR Level;
DWORD Flags;
*InOutBufferSize = 0;
switch (RequestCode)
{
case WMI_ENABLE_EVENTS:
{
Logger = WPP_GET_TRACE_LOGGER_HANDLE( Buffer );
Level = WPP_GET_TRACE_ENABLE_LEVEL(Logger);
Flags = WPP_GET_TRACE_ENABLE_FLAGS(Logger);
WppDebug(1, ("[WppInit] WMI_ENABLE_EVENTS Ctx %p Flags %x"
" Lev %d Logger %I64x\n",
Ctx, Flags, Level, Logger) );
break;
}
case WMI_DISABLE_EVENTS:
{
Logger = 0;
Flags = 0;
Level = 0;
WppDebug(1, ("[WppInit] WMI_DISABLE_EVENTS Ctx 0x%08p\n", Ctx));
break;
}
#ifdef WPP_CAPTURE_STATE_CALLBACK
case WMI_CAPTURE_STATE:
{
Logger = WPP_GET_TRACE_LOGGER_HANDLE(Buffer);
Level = WPP_GET_TRACE_ENABLE_LEVEL(Logger);
Flags = WPP_GET_TRACE_ENABLE_FLAGS(Logger);
WPP_CAPTURE_STATE_CALLBACK(Ctx->ControlGuid,
Logger,
Flags,
Level);
return ERROR_SUCCESS;
}
#endif
default:
{
return ERROR_INVALID_PARAMETER;
}
}
if (Ctx->Options & WPP_VER_WHISTLER_CB_FORWARD_PTR && Ctx->Cb) {
Ctx = Ctx->Cb; // use forwarding address
}
Ctx->Logger = Logger;
Ctx->Level = Level;
Ctx->Flags[0] = Flags;
#ifdef WPP_PRIVATE_ENABLE_CALLBACK
WPP_PRIVATE_ENABLE_CALLBACK(Ctx->ControlGuid,
Logger,
(RequestCode != WMI_DISABLE_EVENTS) ? TRUE : FALSE,
Flags,
Level);
#endif
return(ERROR_SUCCESS);
}
#ifdef WPP_MANAGED_CPP
#pragma managed(pop)
#endif
#pragma warning(push)
#pragma warning(disable:4068)
#ifdef WPP_MACRO_USE_KM_VERSION_FOR_UM
WPPINIT_EXPORT
VOID WppInitUmDriver(
_In_ PDRIVER_OBJECT DrvObject,
_In_ PCUNICODE_STRING RegPath
)
{
WppInitUm(L"UMDF Driver");
#if ENABLE_WPP_RECORDER
WppAutoLogStart(&WPP_CB[0], DrvObject, RegPath);
#else
UNREFERENCED_PARAMETER(DrvObject);
UNREFERENCED_PARAMETER(RegPath);
#endif // ENABLE_WPP_RECORDER
}
#endif // WPP_MACRO_USE_KM_VERSION_FOR_UM
WPPINIT_EXPORT
VOID WppInitUm(_In_opt_ LPCWSTR AppName)
{
C_ASSERT(WPP_MAX_FLAG_LEN_CHECK);
PWPP_TRACE_CONTROL_BLOCK Control = &WPP_CB[0].Control;
TRACE_GUID_REGISTRATION TraceRegistration;
LPCGUID * RegistrationGuids = (LPCGUID *)&WPP_REGISTRATION_GUIDS;
LPCGUID ControlGuid;
ULONG Status;
#ifdef WPP_MOF_RESOURCENAME
#ifdef WPP_DLL
HMODULE hModule = NULL;
#endif
WCHAR ImagePath[MAX_PATH] = {UNICODE_NULL} ;
WCHAR WppMofResourceName[] = WPP_MOF_RESOURCENAME ;
#else
UNREFERENCED_PARAMETER(AppName);
#endif //#ifdef WPP_MOF_RESOURCENAME
WppDebug(1, ("Registering %ws\n", AppName) );
for(; Control; Control = Control->Next) {
ControlGuid = *RegistrationGuids++;
TraceRegistration.Guid = ControlGuid;
TraceRegistration.RegHandle = 0;
Control->ControlGuid = ControlGuid;
WppDebug(1,(WPP_GUID_FORMAT " %ws : %d\n",
WPP_GUID_ELEMENTS(ControlGuid),
AppName,
Control->FlagsLen));
#ifdef WPP_MOF_RESOURCENAME
if (AppName != NULL) {
#ifdef WPP_DLL
if ((hModule = GetModuleHandleW(AppName)) != NULL) {
Status = GetModuleFileNameW(hModule, ImagePath, MAX_PATH) ;
ImagePath[MAX_PATH-1] = '\0';
if (Status == 0) {
WppDebug(1,("RegisterTraceGuids => GetModuleFileName(DLL) Failed 0x%08X\n",GetLastError()));
}
} else {
WppDebug(1,("RegisterTraceGuids => GetModuleHandleW failed for %ws (0x%08X)\n",AppName,GetLastError()));
}
#else // #ifdef WPP_DLL
Status = GetModuleFileNameW(NULL,ImagePath,MAX_PATH);
if (Status == 0) {
WppDebug(1,("GetModuleFileName(EXE) Failed 0x%08X\n",GetLastError()));
}
#endif // #ifdef WPP_DLL
}
WppDebug(1,("registerTraceGuids => registering with WMI, App=%ws, Mof=%ws, ImagePath=%ws\n",AppName,WppMofResourceName,ImagePath));
#pragma prefast(suppress:__WARNING_BANNED_LEGACY_INSTRUMENTATION_API_USAGE, "WPP generated, requires legacy providers");
Status = RegisterTraceGuidsW( // Always use Unicode
#else // ifndef WPP_MOF_RESOURCENAME
#pragma prefast(suppress:__WARNING_BANNED_LEGACY_INSTRUMENTATION_API_USAGE, "WPP generated, requires legacy providers");
Status = WPP_REGISTER_TRACE_GUIDS(
#endif // ifndef WPP_MOF_RESOURCENAME
WppControlCallback,
Control, // Context for the callback
ControlGuid,
1,
&TraceRegistration,
#ifndef WPP_MOF_RESOURCENAME
0, //ImagePath,
0, //ResourceName,
#else // #ifndef WPP_MOF_RESOURCENAME
ImagePath,
WppMofResourceName,
#endif // #ifndef WPP_MOF_RESOURCENAME
&Control->UmRegistrationHandle
);
if (Status != ERROR_SUCCESS) {
WppDebug(1, ("RegisterTraceGuid failed %d\n", Status) );
}
#if defined (WPP_GLOBALLOGGER)
//
// Check if Global logger is active if we have not been immediately activated
//
if (Control->Logger == (TRACEHANDLE)NULL) {
WppInitGlobalLogger( ControlGuid, (PTRACEHANDLE)&Control->Logger, &Control->Flags[0], &Control->Level);
}
#endif //#if defined (WPP_GLOBALLOGGER)
}
#if ENABLE_WPP_RECORDER
#ifndef WPP_MACRO_USE_KM_VERSION_FOR_UM
UNICODE_STRING AppNameStr;
if (NULL != AppName) {
RtlInitUnicodeString( &AppNameStr, AppName);
}
WppAutoLogStart(&WPP_CB[0], NULL, AppName ? &AppNameStr : NULL);
#endif
WPP_RECORDER_INITIALIZED = WPP_MAIN_CB;
#endif
}
WPPINIT_EXPORT
VOID WppCleanupUm( VOID )
{
PWPP_TRACE_CONTROL_BLOCK Control;
if (WPP_CB == (WPP_CB_TYPE*)&WPP_CB){
//
// WPP_INIT_TRACING macro has not been called
//
return;
}
WppDebug(1, ("Cleanup\n") );
Control = &WPP_CB[0].Control;
for(; Control; Control = Control->Next) {
WppDebug(1,("UnRegistering %I64x\n", Control->UmRegistrationHandle) );
if (Control->UmRegistrationHandle) {
#pragma prefast(suppress:__WARNING_BANNED_LEGACY_INSTRUMENTATION_API_USAGE, "WPP generated, requires legacy providers");
WPP_UNREGISTER_TRACE_GUIDS(Control->UmRegistrationHandle);
Control->UmRegistrationHandle = (TRACEHANDLE)NULL ;
}
}
#if ENABLE_WPP_RECORDER
WppAutoLogStop(&WPP_CB[0]);
WPP_RECORDER_INITIALIZED = (WPP_CB_TYPE*) &WPP_RECORDER_INITIALIZED;
#endif
WPP_CB = (WPP_CB_TYPE*)&WPP_CB;
}
#pragma warning(pop)
#ifdef __cplusplus
} // extern "C"
#endif
@@ -0,0 +1,9 @@
`**********************************************************************`
`* This is a template file for the tracewpp preprocessor. *`
`* If you need to use a custom version of this file in your project, *`
`* please clone it from this one and point WPP to it by specifying *`
`* -gen:{yourfile}*.tmh on the RUN_WPP line in your sources file. *`
`* *`
`* Copyright (c) Microsoft Corporation. All rights reserved. *`
`**********************************************************************`
`INCLUDE um-default.tpl`
@@ -0,0 +1 @@
@WPP_ARGS@
@@ -0,0 +1,72 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "wpptrace.h"
#include "wpptrace.tmh"
#if MFT_CODEC_H264ENC
TRACELOGGING_DEFINE_PROVIDER( // defines g_hProvider
g_hEtwProvider, // Name of the provider handle
"h264enc.etw", // Human-readable name for the provider
// 0000e264-0dc9-401d-b9b8-05e4eca4977e
( 0x0000e264, 0x0dc9, 0x401d, 0xb9, 0xb8, 0x05, 0xe4, 0xec, 0xa4, 0x97, 0x7e ) );
#elif MFT_CODEC_H265ENC
TRACELOGGING_DEFINE_PROVIDER( // defines g_hProvider
g_hEtwProvider, // Name of the provider handle
"h265enc.etw", // Human-readable name for the provider
// 0000e265-0dc9-401d-b9b8-05e4eca4977e
( 0x0000e265, 0x0dc9, 0x401d, 0xb9, 0xb8, 0x05, 0xe4, 0xec, 0xa4, 0x97, 0x7e ) );
#elif MFT_CODEC_AV1ENC
TRACELOGGING_DEFINE_PROVIDER( // defines g_hProvider
g_hEtwProvider, // Name of the provider handle
"av1enc.etw", // Human-readable name for the provider
// 0000eaa1-0dc9-401d-b9b8-05e4eca4977e
( 0x0000eaa1, 0x0dc9, 0x401d, 0xb9, 0xb8, 0x05, 0xe4, 0xec, 0xa4, 0x97, 0x7e ) );
#else
#error MFT_CODEC_xxx must be defined
#endif
void
WppInit()
{
TraceLoggingRegister( g_hEtwProvider );
WPP_INIT_TRACING( L"MFEncoder" );
MFE_INFO( "MFEncoder trace is enabled." );
}
void
WppClean()
{
MFE_INFO( "MFEncoder trace is shutdown." );
WPP_CLEANUP();
TraceLoggingUnregister( g_hEtwProvider );
}
@@ -0,0 +1,108 @@
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#pragma once
#include <windows.h>
#include <TraceLoggingProvider.h>
#if MFT_CODEC_H264ENC
#define DEFINE_MFE_WPP_GUID ( 264, 0dc9, 401d, b9b8, 05e4eca4977e )
#elif MFT_CODEC_H265ENC
#define DEFINE_MFE_WPP_GUID ( 265, 0dc9, 401d, b9b8, 05e4eca4977e )
#elif MFT_CODEC_AV1ENC
#define DEFINE_MFE_WPP_GUID ( aa1, 0dc9, 401d, b9b8, 05e4eca4977e )
#else
#error MFT_CODEC_xxx must be defined
#endif
#define WPP_CONTROL_GUIDS WPP_DEFINE_CONTROL_GUID( CTRLGUID_MFE, DEFINE_MFE_WPP_GUID, WPP_DEFINE_BIT( MFE_ALL ) )
#define WPP_FLAG_LEVEL_LOGGER( flag, level ) WPP_LEVEL_LOGGER( flag )
#define WPP_FLAG_LEVEL_ENABLED( flag, level ) ( WPP_LEVEL_ENABLED( flag ) && WPP_CONTROL( WPP_BIT_##flag ).Level >= level )
#define WPP_LEVEL_FLAGS_LOGGER( lvl, flags ) WPP_LEVEL_LOGGER( flags )
#define WPP_LEVEL_FLAGS_ENABLED( lvl, flags ) ( WPP_LEVEL_ENABLED( flags ) && WPP_CONTROL( WPP_BIT_##flags ).Level >= lvl )
// begin_wpp config
//
// FUNC MFE_INFO{FLAG=MFE_ALL,LEVEL=TRACE_LEVEL_INFORMATION}(MSG, ...);
// FUNC MFE_ERROR{FLAG=MFE_ALL,LEVEL=TRACE_LEVEL_ERROR}(MSG, ...);
// FUNC MFE_WARNING{FLAG=MFE_ALL,LEVEL=TRACE_LEVEL_WARNING}(MSG, ...);
// FUNC MFE_VERBOSE{FLAG=MFE_ALL,LEVEL=TRACE_LEVEL_VERBOSE}(MSG, ...);
//
// end_wpp
//
// TraceLogging ETW
//
TRACELOGGING_DECLARE_PROVIDER( g_hEtwProvider );
#if MFT_CODEC_H264ENC
#define ETW_MODULE_STR "H264Enc"
#elif MFT_CODEC_H265ENC
#define ETW_MODULE_STR "H265Enc"
#elif MFT_CODEC_AV1ENC
#define ETW_MODULE_STR "AV1Enc"
#else
#error MFT_CODEC_xxx must be defined
#endif
#define HMFT_ETW_EVENT_START( EventId, this ) \
if( g_hEtwProvider ) \
{ \
TraceLoggingWrite( g_hEtwProvider, \
EventId, \
TraceLoggingOpcode( EVENT_TRACE_TYPE_START ), \
TraceLoggingPointer( this, ETW_MODULE_STR ) ); \
}
#define HMFT_ETW_EVENT_STOP( EventId, this ) \
if( g_hEtwProvider ) \
{ \
TraceLoggingWrite( g_hEtwProvider, \
EventId, \
TraceLoggingOpcode( EVENT_TRACE_TYPE_STOP ), \
TraceLoggingPointer( this, ETW_MODULE_STR ) ); \
}
#define HMFT_ETW_EVENT_INFO( EventId, this ) \
if( g_hEtwProvider ) \
{ \
TraceLoggingWrite( g_hEtwProvider, \
EventId, \
TraceLoggingOpcode( EVENT_TRACE_TYPE_INFO ), \
TraceLoggingPointer( this, ETW_MODULE_STR ) ); \
}