tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DXVA2Manager.cpp (51765B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifdef MOZ_AV1
      8 #  include "AOMDecoder.h"
      9 #endif
     10 #include <d3d11.h>
     11 
     12 #include "DXVA2Manager.h"
     13 #include "DriverCrashGuard.h"
     14 #include "GfxDriverInfo.h"
     15 #include "ImageContainer.h"
     16 #include "MFTDecoder.h"
     17 #include "MediaTelemetryConstants.h"
     18 #include "PerformanceRecorder.h"
     19 #include "VPXDecoder.h"
     20 #include "VideoUtils.h"
     21 #include "WMFUtils.h"
     22 #include "gfxCrashReporterUtils.h"
     23 #include "gfxWindowsPlatform.h"
     24 #include "mfapi.h"
     25 #include "mozilla/AppShutdown.h"
     26 #include "mozilla/Assertions.h"
     27 #include "mozilla/ClearOnShutdown.h"
     28 #include "mozilla/StaticMutex.h"
     29 #include "mozilla/StaticPrefs_media.h"
     30 #include "mozilla/gfx/DeviceManagerDx.h"
     31 #include "mozilla/glean/DomMediaPlatformsWmfMetrics.h"
     32 #include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h"
     33 #include "mozilla/layers/D3D11ShareHandleImage.h"
     34 #include "mozilla/layers/D3D11ZeroCopyTextureImage.h"
     35 #include "mozilla/layers/FenceD3D11.h"
     36 #include "mozilla/layers/ImageBridgeChild.h"
     37 #include "mozilla/layers/TextureD3D11.h"
     38 #include "mozilla/layers/TextureForwarder.h"
     39 #include "mozilla/layers/VideoProcessorD3D11.h"
     40 #include "mozilla/mscom/EnsureMTA.h"
     41 #include "nsPrintfCString.h"
     42 #include "nsThreadUtils.h"
     43 
     44 const GUID MF_XVP_PLAYBACK_MODE = {
     45    0x3c5d293f,
     46    0xad67,
     47    0x4e29,
     48    {0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9}};
     49 
     50 DEFINE_GUID(MF_LOW_LATENCY, 0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27,
     51            0x27, 0xa0, 0x24, 0xee);
     52 
     53 // R600, R700, Evergreen and Cayman AMD cards. These support DXVA via UVD3 or
     54 // earlier, and don't handle 1080p60 well.
     55 static const DWORD sAMDPreUVD4[] = {
     56    // clang-format off
     57  0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x94c0, 0x94c1, 0x94c3, 0x94c4, 0x94c5,
     58  0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, 0x94cc, 0x94cd, 0x9580, 0x9581, 0x9583, 0x9586, 0x9587, 0x9588,
     59  0x9589, 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f, 0x9500, 0x9501, 0x9504, 0x9505, 0x9506, 0x9507,
     60  0x9508, 0x9509, 0x950f, 0x9511, 0x9515, 0x9517, 0x9519, 0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7,
     61  0x95c9, 0x95cc, 0x95cd, 0x95ce, 0x95cf, 0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599,
     62  0x959b, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, 0x9616, 0x9710, 0x9711, 0x9712, 0x9713, 0x9714,
     63  0x9715, 0x9440, 0x9441, 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e, 0x9450, 0x9452,
     64  0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a, 0x946b, 0x947a, 0x947b, 0x9480, 0x9487, 0x9488,
     65  0x9489, 0x948a, 0x948f, 0x9490, 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x9540, 0x9541, 0x9542,
     66  0x954e, 0x954f, 0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x94a0, 0x94a1, 0x94a3, 0x94b1, 0x94b3, 0x94b4,
     67  0x94b5, 0x94b9, 0x68e0, 0x68e1, 0x68e4, 0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa,
     68  0x68fe, 0x68c0, 0x68c1, 0x68c7, 0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, 0x68a0, 0x68a1, 0x68a8,
     69  0x68a9, 0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, 0x68bf, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d,
     70  0x6898, 0x6899, 0x689b, 0x689e, 0x689c, 0x689d, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, 0x9807, 0x9808,
     71  0x9809, 0x980a, 0x9640, 0x9641, 0x9647, 0x9648, 0x964a, 0x964b, 0x964c, 0x964e, 0x964f, 0x9642, 0x9643,
     72  0x9644, 0x9645, 0x9649, 0x6720, 0x6721, 0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, 0x6729,
     73  0x6738, 0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, 0x6745, 0x6746, 0x6747, 0x6748, 0x6749,
     74  0x674a, 0x6750, 0x6751, 0x6758, 0x6759, 0x675b, 0x675d, 0x675f, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849,
     75  0x6850, 0x6858, 0x6859, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, 0x6766, 0x6767, 0x6768, 0x6770,
     76  0x6771, 0x6772, 0x6778, 0x6779, 0x677b, 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707,
     77  0x6708, 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x9900, 0x9901, 0x9903, 0x9904, 0x9905, 0x9906,
     78  0x9907, 0x9908, 0x9909, 0x990a, 0x990b, 0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918,
     79  0x9919, 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, 0x9999, 0x999a, 0x999b,
     80  0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4
     81    // clang-format on
     82 };
     83 
     84 // List of NVidia Telsa GPU known to have broken NV12 rendering.
     85 static const DWORD sNVIDIABrokenNV12[] = {
     86    // clang-format off
     87  0x0191, 0x0193, 0x0194, 0x0197, 0x019d, 0x019e, // G80
     88  0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, // G84
     89  0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f,
     90  0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, // G86
     91  0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
     92  0x0410, 0x0600, 0x0601, 0x0602, 0x0603, 0x0604, 0x0605, 0x0606, 0x0607, 0x0608, // G92
     93  0x0609, 0x060a, 0x060b, 0x060c, 0x060f, 0x0610, 0x0611, 0x0612, 0x0613, 0x0614,
     94  0x0615, 0x0617, 0x0618, 0x0619, 0x061a, 0x061b, 0x061c, 0x061d, 0x061e, 0x061f, // G94
     95  0x0621, 0x0622, 0x0623, 0x0625, 0x0626, 0x0627, 0x0628, 0x062a, 0x062b, 0x062c,
     96  0x062d, 0x062e, 0x0631, 0x0635, 0x0637, 0x0638, 0x063a,
     97  0x0640, 0x0641, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064a, // G96
     98  0x064b, 0x064c, 0x0651, 0x0652, 0x0653, 0x0654, 0x0655, 0x0656, 0x0658, 0x0659,
     99  0x065a, 0x065b, 0x065c, 0x065f,
    100  0x06e0, 0x06e1, 0x06e2, 0x06e3, 0x06e4, 0x06e6, 0x06e7, 0x06e8, 0x06e9, 0x06ea, // G98
    101  0x06eb, 0x06ec, 0x06ef, 0x06f1, 0x06f8, 0x06f9, 0x06fa, 0x06fb, 0x06fd, 0x06ff,
    102  0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e6, 0x05e7, 0x05e9, 0x05ea, 0x05eb, 0x05ed, // G200
    103  0x05ee, 0x05ef,
    104  0x0840, 0x0844, 0x0845, 0x0846, 0x0847, 0x0848, 0x0849, 0x084a, 0x084b, 0x084c, // MCP77
    105  0x084d, 0x084f,
    106  0x0860, 0x0861, 0x0862, 0x0863, 0x0864, 0x0865, 0x0866, 0x0867, 0x0868, 0x0869, // MCP79
    107  0x086a, 0x086c, 0x086d, 0x086e, 0x086f, 0x0870, 0x0871, 0x0872, 0x0873, 0x0874,
    108  0x0876, 0x087a, 0x087d, 0x087e, 0x087f,
    109  0x0ca0, 0x0ca2, 0x0ca3, 0x0ca2, 0x0ca4, 0x0ca5, 0x0ca7, 0x0ca9, 0x0cac, 0x0caf, // GT215
    110  0x0cb0, 0x0cb1, 0x0cbc,
    111  0x0a20, 0x0a22, 0x0a23, 0x0a26, 0x0a27, 0x0a28, 0x0a29, 0x0a2a, 0x0a2b, 0x0a2c, // GT216
    112  0x0a2d, 0x0a32, 0x0a34, 0x0a35, 0x0a38, 0x0a3c,
    113  0x0a60, 0x0a62, 0x0a63, 0x0a64, 0x0a65, 0x0a66, 0x0a67, 0x0a68, 0x0a69, 0x0a6a, // GT218
    114  0x0a6c, 0x0a6e, 0x0a6f, 0x0a70, 0x0a71, 0x0a72, 0x0a73, 0x0a74, 0x0a75, 0x0a76,
    115  0x0a78, 0x0a7a, 0x0a7c, 0x10c0, 0x10c3, 0x10c5, 0x10d8
    116    // clang-format on
    117 };
    118 
    119 extern mozilla::LazyLogModule sPDMLog;
    120 #define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
    121 #define LOGV(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__))
    122 
    123 namespace mozilla {
    124 
    125 using layers::D3D11RecycleAllocator;
    126 using layers::D3D11ShareHandleImage;
    127 using layers::Image;
    128 using layers::ImageContainer;
    129 using namespace layers;
    130 using namespace gfx;
    131 
    132 StaticRefPtr<ID3D11Device> sDevice;
    133 StaticMutex sDeviceMutex;
    134 
    135 void GetDXVA2ExtendedFormatFromMFMediaType(IMFMediaType* pType,
    136                                           DXVA2_ExtendedFormat* pFormat) {
    137  // Get the interlace mode.
    138  MFVideoInterlaceMode interlace = MFVideoInterlaceMode(MFGetAttributeUINT32(
    139      pType, MF_MT_INTERLACE_MODE, MFVideoInterlace_Unknown));
    140 
    141  if (interlace == MFVideoInterlace_MixedInterlaceOrProgressive) {
    142    pFormat->SampleFormat = DXVA2_SampleFieldInterleavedEvenFirst;
    143  } else {
    144    pFormat->SampleFormat = UINT(interlace);
    145  }
    146 
    147  pFormat->VideoChromaSubsampling = MFGetAttributeUINT32(
    148      pType, MF_MT_VIDEO_CHROMA_SITING, MFVideoChromaSubsampling_Unknown);
    149  pFormat->NominalRange = MFGetAttributeUINT32(pType, MF_MT_VIDEO_NOMINAL_RANGE,
    150                                               MFNominalRange_Unknown);
    151  pFormat->VideoTransferMatrix = MFGetAttributeUINT32(
    152      pType, MF_MT_YUV_MATRIX, MFVideoTransferMatrix_Unknown);
    153  pFormat->VideoLighting = MFGetAttributeUINT32(pType, MF_MT_VIDEO_LIGHTING,
    154                                                MFVideoLighting_Unknown);
    155  pFormat->VideoPrimaries = MFGetAttributeUINT32(pType, MF_MT_VIDEO_PRIMARIES,
    156                                                 MFVideoPrimaries_Unknown);
    157  pFormat->VideoTransferFunction = MFGetAttributeUINT32(
    158      pType, MF_MT_TRANSFER_FUNCTION, MFVideoTransFunc_Unknown);
    159 }
    160 
    161 HRESULT ConvertMFTypeToDXVAType(IMFMediaType* pType, DXVA2_VideoDesc* pDesc) {
    162  ZeroMemory(pDesc, sizeof(*pDesc));
    163 
    164  // The D3D format is the first DWORD of the subtype GUID.
    165  GUID subtype = GUID_NULL;
    166  HRESULT hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
    167  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    168  pDesc->Format = (D3DFORMAT)subtype.Data1;
    169 
    170  UINT32 width = 0;
    171  UINT32 height = 0;
    172  hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
    173  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    174  NS_ENSURE_TRUE(width <= MAX_VIDEO_WIDTH, E_FAIL);
    175  NS_ENSURE_TRUE(height <= MAX_VIDEO_HEIGHT, E_FAIL);
    176  pDesc->SampleWidth = width;
    177  pDesc->SampleHeight = height;
    178 
    179  UINT32 fpsNumerator = 0;
    180  UINT32 fpsDenominator = 0;
    181  if (SUCCEEDED(MFGetAttributeRatio(pType, MF_MT_FRAME_RATE, &fpsNumerator,
    182                                    &fpsDenominator))) {
    183    pDesc->InputSampleFreq.Numerator = fpsNumerator;
    184    pDesc->InputSampleFreq.Denominator = fpsDenominator;
    185 
    186    GetDXVA2ExtendedFormatFromMFMediaType(pType, &pDesc->SampleFormat);
    187    pDesc->OutputFrameFreq = pDesc->InputSampleFreq;
    188    if ((pDesc->SampleFormat.SampleFormat ==
    189         DXVA2_SampleFieldInterleavedEvenFirst) ||
    190        (pDesc->SampleFormat.SampleFormat ==
    191         DXVA2_SampleFieldInterleavedOddFirst)) {
    192      pDesc->OutputFrameFreq.Numerator *= 2;
    193    }
    194  }
    195 
    196  return S_OK;
    197 }
    198 
    199 // All GUIDs other than Intel ClearVideo can be found here:
    200 // https://docs.microsoft.com/en-us/windows/win32/medfound/direct3d-12-video-guids
    201 // VLD = Variable-length decoder, FGT = Film grain technology
    202 static const GUID DXVA2_ModeH264_VLD_NoFGT = {
    203    0x1b81be68,
    204    0xa0c7,
    205    0x11d3,
    206    {0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5}};
    207 
    208 // Also known as DXVADDI_Intel_ModeH264_E here:
    209 // https://www.intel.com/content/dam/develop/external/us/en/documents/h264-avc-x4500-acceration-esardell-157713.pdf
    210 // Named based on the fact that this is only supported on older ClearVideo
    211 // Intel decoding hardware.
    212 static const GUID DXVA2_Intel_ClearVideo_ModeH264_VLD_NoFGT = {
    213    0x604F8E68,
    214    0x4951,
    215    0x4c54,
    216    {0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6}};
    217 
    218 // VP8 profiles
    219 static const GUID DXVA2_ModeVP8_VLD = {
    220    0x90b899ea,
    221    0x3a62,
    222    0x4705,
    223    {0x88, 0xb3, 0x8d, 0xf0, 0x4b, 0x27, 0x44, 0xe7}};
    224 
    225 // VP9 profiles
    226 static const GUID DXVA2_ModeVP9_VLD_Profile0 = {
    227    0x463707f8,
    228    0xa1d0,
    229    0x4585,
    230    {0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e}};
    231 
    232 static const GUID DXVA2_ModeVP9_VLD_10bit_Profile2 = {
    233    0xa4c749ef,
    234    0x6ecf,
    235    0x48aa,
    236    {0x84, 0x48, 0x50, 0xa7, 0xa1, 0x16, 0x5f, 0xf7}};
    237 
    238 // AV1 profiles
    239 static const GUID DXVA2_ModeAV1_VLD_Profile0 = {
    240    0xb8be4ccb,
    241    0xcf53,
    242    0x46ba,
    243    {0x8d, 0x59, 0xd6, 0xb8, 0xa6, 0xda, 0x5d, 0x2a}};
    244 
    245 static const GUID DXVA2_ModeAV1_VLD_Profile1 = {
    246    0x6936ff0f,
    247    0x45b1,
    248    0x4163,
    249    {0x9c, 0xc1, 0x64, 0x6e, 0xf6, 0x94, 0x61, 0x08}};
    250 
    251 static const GUID DXVA2_ModeAV1_VLD_Profile2 = {
    252    0x0c5f2aa1,
    253    0xe541,
    254    0x4089,
    255    {0xbb, 0x7b, 0x98, 0x11, 0x0a, 0x19, 0xd7, 0xc8}};
    256 
    257 static const GUID DXVA2_ModeAV1_VLD_12bit_Profile2 = {
    258    0x17127009,
    259    0xa00f,
    260    0x4ce1,
    261    {0x99, 0x4e, 0xbf, 0x40, 0x81, 0xf6, 0xf3, 0xf0}};
    262 
    263 static const GUID DXVA2_ModeAV1_VLD_12bit_Profile2_420 = {
    264    0x2d80bed6,
    265    0x9cac,
    266    0x4835,
    267    {0x9e, 0x91, 0x32, 0x7b, 0xbc, 0x4f, 0x9e, 0xe8}};
    268 
    269 // D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN
    270 static const GUID DXVA2_ModeHEVC_VLD_MAIN = {
    271    0x5b11d51b,
    272    0x2f4c,
    273    0x4452,
    274    {0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0}};
    275 
    276 // D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10
    277 static const GUID DXVA2_ModeHEVC_VLD_MAIN10 = {
    278    0x107af0e0,
    279    0xef1a,
    280    0x4d19,
    281    {0xab, 0xa8, 0x67, 0xa1, 0x63, 0x07, 0x3d, 0x13}};
    282 
    283 static const char* DecoderGUIDToStr(const GUID& aGuid) {
    284  if (aGuid == DXVA2_ModeH264_VLD_NoFGT) {
    285    return "H264";
    286  }
    287  if (aGuid == DXVA2_Intel_ClearVideo_ModeH264_VLD_NoFGT) {
    288    return "Intel H264";
    289  }
    290  if (aGuid == DXVA2_ModeVP8_VLD) {
    291    return "VP8";
    292  }
    293  if (aGuid == DXVA2_ModeVP9_VLD_Profile0) {
    294    return "VP9 Profile0";
    295  }
    296  if (aGuid == DXVA2_ModeVP9_VLD_10bit_Profile2) {
    297    return "VP9 10bits Profile2";
    298  }
    299  if (aGuid == DXVA2_ModeAV1_VLD_Profile0) {
    300    return "AV1 Profile0";
    301  }
    302  if (aGuid == DXVA2_ModeAV1_VLD_Profile1) {
    303    return "AV1 Profile1";
    304  }
    305  if (aGuid == DXVA2_ModeAV1_VLD_Profile2) {
    306    return "AV1 Profile2";
    307  }
    308  if (aGuid == DXVA2_ModeAV1_VLD_12bit_Profile2) {
    309    return "AV1 12bits Profile2";
    310  }
    311  if (aGuid == DXVA2_ModeAV1_VLD_12bit_Profile2_420) {
    312    return "AV1 12bits Profile2 420";
    313  }
    314  if (aGuid == DXVA2_ModeHEVC_VLD_MAIN) {
    315    return "HEVC main";
    316  }
    317  if (aGuid == DXVA2_ModeHEVC_VLD_MAIN10) {
    318    return "HEVC main10";
    319  }
    320  return "none";
    321 }
    322 
    323 // Count of the number of DXVAManager's we've created. This is also the
    324 // number of videos we're decoding with DXVA. Use on main thread only.
    325 static Atomic<uint32_t> sDXVAVideosCount(0);
    326 
    327 // This class's functions are not thread-safe, please use them carefully.
    328 // TODO : make this class better in bug1932998.
    329 class D3D11DXVA2Manager : public DXVA2Manager {
    330 public:
    331  D3D11DXVA2Manager();
    332  virtual ~D3D11DXVA2Manager();
    333 
    334  HRESULT Init(layers::KnowsCompositor* aKnowsCompositor,
    335               nsACString& aFailureReason, ID3D11Device* aDevice);
    336  HRESULT InitInternal(layers::KnowsCompositor* aKnowsCompositor,
    337                       nsACString& aFailureReason, ID3D11Device* aDevice);
    338 
    339  IUnknown* GetDXVADeviceManager() override;
    340 
    341  // Copies a region (aRegion) of the video frame stored in aVideoSample
    342  // into an image which is returned by aOutImage.
    343  HRESULT CopyToImage(IMFSample* aVideoSample, const gfx::IntRect& aRegion,
    344                      Image** aOutImage) override;
    345  HRESULT CopyToImage(ID3D11Texture2D* aVideoSample, UINT aSurfaceIndex,
    346                      const gfx::IntRect& aRegion,
    347                      layers::Image** aOutImage) override;
    348 
    349  HRESULT WrapTextureWithImage(IMFSample* aVideoSample,
    350                               const gfx::IntRect& aRegion,
    351                               layers::Image** aOutImage) override;
    352 
    353  HRESULT WrapTextureWithImage(D3D11TextureWrapper* aTextureWrapper,
    354                               const gfx::IntRect& aRegion,
    355                               layers::Image** aOutImage) override;
    356 
    357  HRESULT ConfigureForSize(IMFMediaType* aInputType,
    358                           gfx::YUVColorSpace aColorSpace,
    359                           gfx::ColorRange aColorRange,
    360                           gfx::ColorDepth aColorDepth,
    361                           gfx::TransferFunction aTransferFunction,
    362                           uint32_t aWidth, uint32_t aHeight) override;
    363  HRESULT ConfigureForSize(gfx::SurfaceFormat aSurfaceFormat,
    364                           gfx::YUVColorSpace aColorSpace,
    365                           gfx::ColorRange aColorRange,
    366                           gfx::ColorDepth aColorDepth,
    367                           gfx::TransferFunction aTransferFunction,
    368                           uint32_t aWidth, uint32_t aHeight) override;
    369 
    370  bool IsD3D11() override { return true; }
    371 
    372  bool SupportsConfig(const VideoInfo& aInfo, IMFMediaType* aInputType,
    373                      IMFMediaType* aOutputType) override;
    374 
    375  void BeforeShutdownVideoMFTDecoder() override;
    376 
    377  bool SupportsZeroCopyNV12Texture() override {
    378    if (mZeroCopyUsageInfo->SupportsZeroCopyNV12Texture() &&
    379        (mDevice != DeviceManagerDx::Get()->GetCompositorDevice())) {
    380      mZeroCopyUsageInfo->DisableZeroCopyNV12Texture();
    381    }
    382    return mZeroCopyUsageInfo->SupportsZeroCopyNV12Texture();
    383  }
    384 
    385  ID3D11Device* GetD3D11Device() override { return mDevice; }
    386 
    387 private:
    388  HRESULT CreateOutputSample(RefPtr<IMFSample>& aSample,
    389                             ID3D11Texture2D* aTexture);
    390 
    391  // This is used for check whether hw decoding is possible before using MFT for
    392  // decoding.
    393  bool CanCreateDecoder(const D3D11_VIDEO_DECODER_DESC& aDesc) const;
    394 
    395  void RefreshIMFSampleWrappers();
    396  void ReleaseAllIMFSamples();
    397 
    398  struct InputTextureInfo {
    399    InputTextureInfo(ID3D11Texture2D* aTexture, UINT aIndex,
    400                     const gfx::IntRect& aRegion)
    401        : mTexture(aTexture), mIndex(aIndex), mRegion(aRegion) {};
    402    ID3D11Texture2D* mTexture;
    403    const UINT mIndex;
    404    const gfx::IntRect mRegion;
    405  };
    406  HRESULT CopyTextureToImage(const InputTextureInfo& aInTexture,
    407                             Image** aOutImage);
    408 
    409  VideoProcessorD3D11* GetOrCreateVideoProcessor();
    410 
    411  RefPtr<ID3D11Device> mDevice;
    412  RefPtr<ID3D11DeviceContext> mContext;
    413  RefPtr<IMFDXGIDeviceManager> mDXGIDeviceManager;
    414  RefPtr<MFTDecoder> mTransform;
    415  RefPtr<D3D11RecycleAllocator> mTextureClientAllocator;
    416  RefPtr<layers::KnowsCompositor> mKnowsCompositor;
    417  RefPtr<ID3D11VideoDecoder> mDecoder;
    418  RefPtr<layers::SyncObjectClient> mSyncObject;
    419  RefPtr<VideoProcessorD3D11> mProcessor;
    420  uint32_t mWidth = 0;
    421  uint32_t mHeight = 0;
    422  UINT mDeviceManagerToken = 0;
    423  RefPtr<IMFMediaType> mInputType;
    424  GUID mInputSubType;
    425  gfx::YUVColorSpace mYUVColorSpace;
    426  gfx::ColorRange mColorRange = gfx::ColorRange::LIMITED;
    427  gfx::ColorDepth mColorDepth = gfx::ColorDepth::COLOR_8;
    428  gfx::TransferFunction mTransferFunction = gfx::TransferFunction::BT709;
    429  gfx::SurfaceFormat mSurfaceFormat;
    430  std::list<ThreadSafeWeakPtr<layers::IMFSampleWrapper>> mIMFSampleWrappers;
    431  RefPtr<layers::ZeroCopyUsageInfo> mZeroCopyUsageInfo;
    432  uint32_t mVendorID = 0;
    433  RefPtr<layers::FenceD3D11> mWriteFence;
    434 };
    435 
    436 bool D3D11DXVA2Manager::SupportsConfig(const VideoInfo& aInfo,
    437                                       IMFMediaType* aInputType,
    438                                       IMFMediaType* aOutputType) {
    439  D3D11_VIDEO_DECODER_DESC desc = {GUID_NULL, 0, 0, DXGI_FORMAT_UNKNOWN};
    440 
    441  HRESULT hr = MFGetAttributeSize(aInputType, MF_MT_FRAME_SIZE,
    442                                  &desc.SampleWidth, &desc.SampleHeight);
    443  NS_ENSURE_TRUE(SUCCEEDED(hr), false);
    444  NS_ENSURE_TRUE(desc.SampleWidth <= MAX_VIDEO_WIDTH, false);
    445  NS_ENSURE_TRUE(desc.SampleHeight <= MAX_VIDEO_HEIGHT, false);
    446 
    447  GUID subtype;
    448  hr = aInputType->GetGUID(MF_MT_SUBTYPE, &subtype);
    449  NS_ENSURE_TRUE(SUCCEEDED(hr), false);
    450 
    451  if (subtype == MFVideoFormat_H264) {
    452    // IsUnsupportedResolution is only used to work around an AMD H264 issue.
    453    const float framerate = [&]() {
    454      UINT32 numerator;
    455      UINT32 denominator;
    456      if (SUCCEEDED(MFGetAttributeRatio(aInputType, MF_MT_FRAME_RATE,
    457                                        &numerator, &denominator))) {
    458        return static_cast<float>(numerator) / denominator;
    459      }
    460      return 30.0f;
    461    }();
    462    NS_ENSURE_FALSE(
    463        IsUnsupportedResolution(desc.SampleWidth, desc.SampleHeight, framerate),
    464        false);
    465    NS_ENSURE_TRUE(aInfo.mColorDepth == ColorDepth::COLOR_8, false);
    466 
    467    RefPtr<ID3D11VideoDevice> videoDevice;
    468    hr = mDevice->QueryInterface(
    469        static_cast<ID3D11VideoDevice**>(getter_AddRefs(videoDevice)));
    470 
    471    GUID guids[] = {DXVA2_ModeH264_VLD_NoFGT,
    472                    DXVA2_Intel_ClearVideo_ModeH264_VLD_NoFGT};
    473    for (const GUID& guid : guids) {
    474      BOOL supported = false;
    475      hr = videoDevice->CheckVideoDecoderFormat(&guid, DXGI_FORMAT_NV12,
    476                                                &supported);
    477      if (SUCCEEDED(hr) && supported) {
    478        desc.Guid = guid;
    479        break;
    480      }
    481    }
    482  } else if (subtype == MFVideoFormat_VP80) {
    483    NS_ENSURE_TRUE(aInfo.mColorDepth == ColorDepth::COLOR_8, false);
    484    desc.Guid = DXVA2_ModeVP8_VLD;
    485  } else if (subtype == MFVideoFormat_VP90) {
    486    NS_ENSURE_TRUE(aInfo.mColorDepth == ColorDepth::COLOR_8 ||
    487                       aInfo.mColorDepth == ColorDepth::COLOR_10,
    488                   false);
    489    uint8_t profile;
    490 
    491    if (aInfo.mExtraData && !aInfo.mExtraData->IsEmpty()) {
    492      VPXDecoder::VPXStreamInfo vp9Info;
    493      VPXDecoder::ReadVPCCBox(vp9Info, aInfo.mExtraData);
    494      profile = vp9Info.mProfile;
    495    } else {
    496      // If no vpcC is present, we can't know the profile, which limits the
    497      // subsampling mode, but 4:2:0 is most supported so default to profiles 0
    498      // and 2:
    499      // Profile 0 = 8bit, 4:2:0
    500      // Profile 2 = 10/12bit, 4:2:0
    501      profile = aInfo.mColorDepth == ColorDepth::COLOR_8 ? 0 : 2;
    502    }
    503 
    504    switch (profile) {
    505      case 0:
    506        desc.Guid = DXVA2_ModeVP9_VLD_Profile0;
    507        break;
    508      case 2:
    509        desc.Guid = DXVA2_ModeVP9_VLD_10bit_Profile2;
    510        break;
    511      default:
    512        break;
    513    }
    514  } else if (subtype == MFVideoFormat_AV1) {
    515    uint8_t profile;
    516    bool yuv420;
    517 
    518    if (aInfo.mExtraData && !aInfo.mExtraData->IsEmpty()) {
    519      AOMDecoder::AV1SequenceInfo av1Info;
    520      bool hadSeqHdr;
    521      AOMDecoder::ReadAV1CBox(aInfo.mExtraData, av1Info, hadSeqHdr);
    522      profile = av1Info.mProfile;
    523      yuv420 = av1Info.mSubsamplingX && av1Info.mSubsamplingY;
    524    } else {
    525      // If no av1C is present, we can't get profile or subsampling mode. 4:2:0
    526      // subsampling is most likely to be supported in hardware, so set av1Info
    527      // accordingly.
    528      // 8bit/10bit = Main profile, 4:2:0
    529      // 12bit = Professional, 4:2:0
    530      profile = aInfo.mColorDepth == ColorDepth::COLOR_12 ? 2 : 0;
    531      yuv420 = true;
    532    }
    533 
    534    switch (profile) {
    535      case 0:
    536        desc.Guid = DXVA2_ModeAV1_VLD_Profile0;
    537        break;
    538      case 1:
    539        desc.Guid = DXVA2_ModeAV1_VLD_Profile1;
    540        break;
    541      case 2:
    542        MOZ_ASSERT(aInfo.mColorDepth < ColorDepth::COLOR_16);
    543        if (aInfo.mColorDepth == ColorDepth::COLOR_12) {
    544          if (yuv420) {
    545            desc.Guid = DXVA2_ModeAV1_VLD_12bit_Profile2_420;
    546          } else {
    547            desc.Guid = DXVA2_ModeAV1_VLD_12bit_Profile2;
    548          }
    549        } else {
    550          desc.Guid = DXVA2_ModeAV1_VLD_Profile2;
    551        }
    552        break;
    553      default:
    554        break;
    555    }
    556  } else if (subtype == MFVideoFormat_HEVC) {
    557    RefPtr<ID3D11VideoDevice> videoDevice;
    558    hr = mDevice->QueryInterface(
    559        static_cast<ID3D11VideoDevice**>(getter_AddRefs(videoDevice)));
    560    GUID guids[] = {DXVA2_ModeHEVC_VLD_MAIN, DXVA2_ModeHEVC_VLD_MAIN10};
    561    for (const GUID& guid : guids) {
    562      BOOL supported = false;
    563      hr = videoDevice->CheckVideoDecoderFormat(&guid, DXGI_FORMAT_NV12,
    564                                                &supported);
    565      if (SUCCEEDED(hr) && supported) {
    566        desc.Guid = guid;
    567        break;
    568      }
    569    }
    570  }
    571  LOG("Select %s GUID", DecoderGUIDToStr(desc.Guid));
    572 
    573  hr = aOutputType->GetGUID(MF_MT_SUBTYPE, &subtype);
    574  if (SUCCEEDED(hr)) {
    575    if (subtype == MFVideoFormat_NV12) {
    576      desc.OutputFormat = DXGI_FORMAT_NV12;
    577    } else if (subtype == MFVideoFormat_P010) {
    578      desc.OutputFormat = DXGI_FORMAT_P010;
    579    } else if (subtype == MFVideoFormat_P016) {
    580      desc.OutputFormat = DXGI_FORMAT_P016;
    581    } else if (subtype == MFVideoFormat_A2R10G10B10) {
    582      desc.OutputFormat = DXGI_FORMAT_R10G10B10A2_UNORM;
    583    } else if (subtype == MFVideoFormat_A16B16G16R16F) {
    584      desc.OutputFormat = DXGI_FORMAT_R16G16B16A16_FLOAT;
    585    }
    586  }
    587 
    588  if (desc.Guid == GUID_NULL || desc.OutputFormat == DXGI_FORMAT_UNKNOWN) {
    589    return false;
    590  }
    591 
    592  return CanCreateDecoder(desc);
    593 }
    594 
    595 D3D11DXVA2Manager::D3D11DXVA2Manager()
    596    : mZeroCopyUsageInfo(new layers::ZeroCopyUsageInfo) {}
    597 
    598 D3D11DXVA2Manager::~D3D11DXVA2Manager() {}
    599 
    600 IUnknown* D3D11DXVA2Manager::GetDXVADeviceManager() {
    601  MutexAutoLock lock(mLock);
    602  return mDXGIDeviceManager;
    603 }
    604 HRESULT
    605 D3D11DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
    606                        nsACString& aFailureReason, ID3D11Device* aDevice) {
    607  if (aDevice) {
    608    return InitInternal(aKnowsCompositor, aFailureReason, aDevice);
    609  }
    610 
    611  HRESULT hr;
    612  ScopedGfxFeatureReporter reporter("DXVA2D3D11");
    613 
    614  hr = InitInternal(aKnowsCompositor, aFailureReason, aDevice);
    615  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    616 
    617  if (layers::ImageBridgeChild::GetSingleton() || !aKnowsCompositor) {
    618    // There's no proper KnowsCompositor for ImageBridge currently (and it
    619    // implements the interface), so just use that if it's available.
    620    mTextureClientAllocator = new D3D11RecycleAllocator(
    621        layers::ImageBridgeChild::GetSingleton().get(), mDevice,
    622        gfx::SurfaceFormat::NV12);
    623 
    624    if (ImageBridgeChild::GetSingleton() &&
    625        StaticPrefs::media_wmf_use_sync_texture_AtStartup() &&
    626        mDevice != DeviceManagerDx::Get()->GetCompositorDevice()) {
    627      // We use a syncobject to avoid the cost of the mutex lock when
    628      // compositing, and because it allows color conversion ocurring directly
    629      // from this texture DXVA does not seem to accept IDXGIKeyedMutex textures
    630      // as input.
    631      mSyncObject = layers::SyncObjectClient::CreateSyncObjectClient(
    632          layers::ImageBridgeChild::GetSingleton()
    633              ->GetTextureFactoryIdentifier()
    634              .mSyncHandle,
    635          mDevice);
    636    }
    637  } else {
    638    mTextureClientAllocator = new D3D11RecycleAllocator(
    639        aKnowsCompositor, mDevice, gfx::SurfaceFormat::NV12);
    640    mKnowsCompositor = aKnowsCompositor;
    641    if (StaticPrefs::media_wmf_use_sync_texture_AtStartup()) {
    642      // We use a syncobject to avoid the cost of the mutex lock when
    643      // compositing, and because it allows color conversion ocurring directly
    644      // from this texture DXVA does not seem to accept IDXGIKeyedMutex textures
    645      // as input.
    646      mSyncObject = layers::SyncObjectClient::CreateSyncObjectClient(
    647          aKnowsCompositor->GetTextureFactoryIdentifier().mSyncHandle, mDevice);
    648    }
    649  }
    650  mTextureClientAllocator->SetMaxPoolSize(5);
    651 
    652  glean::media::decoder_backend_used.AccumulateSingleSample(
    653      uint32_t(media::MediaDecoderBackend::WMFDXVA2D3D11));
    654 
    655  reporter.SetSuccessful();
    656 
    657  return S_OK;
    658 }
    659 
    660 HRESULT
    661 D3D11DXVA2Manager::InitInternal(layers::KnowsCompositor* aKnowsCompositor,
    662                                nsACString& aFailureReason,
    663                                ID3D11Device* aDevice) {
    664  HRESULT hr;
    665 
    666  mDevice = aDevice;
    667 
    668  if (!mDevice) {
    669    DeviceManagerDx::DeviceFlagSet flags;
    670    if (aKnowsCompositor && aKnowsCompositor->UsingHardwareWebRender()) {
    671      flags += DeviceManagerDx::DeviceFlag::isHardwareWebRenderInUse;
    672    }
    673    mDevice = gfx::DeviceManagerDx::Get()->CreateDecoderDevice(flags);
    674    if (!mDevice) {
    675      aFailureReason.AssignLiteral("Failed to create D3D11 device for decoder");
    676      return E_FAIL;
    677    }
    678  }
    679 
    680  auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get();
    681  const bool useFence =
    682      fencesHolderMap && layers::FenceD3D11::IsSupported(mDevice);
    683  if (useFence) {
    684    mWriteFence = layers::FenceD3D11::Create(mDevice);
    685  }
    686 
    687  RefPtr<ID3D10Multithread> mt;
    688  hr = mDevice->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
    689  NS_ENSURE_TRUE(SUCCEEDED(hr) && mt, hr);
    690  mt->SetMultithreadProtected(TRUE);
    691 
    692  mDevice->GetImmediateContext(getter_AddRefs(mContext));
    693 
    694  hr = wmf::MFCreateDXGIDeviceManager(&mDeviceManagerToken,
    695                                      getter_AddRefs(mDXGIDeviceManager));
    696  if (!SUCCEEDED(hr)) {
    697    aFailureReason =
    698        nsPrintfCString("MFCreateDXGIDeviceManager failed with code %lX", hr);
    699    return hr;
    700  }
    701 
    702  hr = mDXGIDeviceManager->ResetDevice(mDevice, mDeviceManagerToken);
    703  if (!SUCCEEDED(hr)) {
    704    aFailureReason = nsPrintfCString(
    705        "IMFDXGIDeviceManager::ResetDevice failed with code %lX", hr);
    706    return hr;
    707  }
    708 
    709  // TODO(https://bugzilla.mozilla.org/show_bug.cgi?id=2008874)
    710  // The IMFTransform interface used by MFTDecoder is documented to require to
    711  // run on an MTA thread.
    712  // https://msdn.microsoft.com/en-us/library/windows/desktop/ee892371(v=vs.85).aspx#components
    713  // The main thread (where this function is called) is STA, not MTA.
    714  RefPtr<MFTDecoder> mft;
    715  mozilla::mscom::EnsureMTA([&]() -> void {
    716    mft = new MFTDecoder();
    717    hr = mft->Create(MFT_CATEGORY_VIDEO_PROCESSOR, MFVideoFormat_NV12,
    718                     MFVideoFormat_ARGB32);
    719 
    720    if (!SUCCEEDED(hr)) {
    721      aFailureReason = nsPrintfCString(
    722          "MFTDecoder::Create of Video Processor MFT for color conversion "
    723          "failed with code %lX",
    724          hr);
    725      return;
    726    }
    727 
    728    hr = mft->SendMFTMessage(MFT_MESSAGE_SET_D3D_MANAGER,
    729                             ULONG_PTR(mDXGIDeviceManager.get()));
    730    if (!SUCCEEDED(hr)) {
    731      aFailureReason = nsPrintfCString(
    732          "MFTDecoder::SendMFTMessage(MFT_MESSAGE_"
    733          "SET_D3D_MANAGER) failed with code %lX",
    734          hr);
    735      return;
    736    }
    737  });
    738 
    739  if (!SUCCEEDED(hr)) {
    740    return hr;
    741  }
    742  mTransform = mft;
    743 
    744  RefPtr<IDXGIDevice> dxgiDevice;
    745  hr = mDevice->QueryInterface(
    746      static_cast<IDXGIDevice**>(getter_AddRefs(dxgiDevice)));
    747  if (!SUCCEEDED(hr)) {
    748    aFailureReason =
    749        nsPrintfCString("QI to IDXGIDevice failed with code %lX", hr);
    750    return hr;
    751  }
    752 
    753  RefPtr<IDXGIAdapter> adapter;
    754  hr = dxgiDevice->GetAdapter(adapter.StartAssignment());
    755  if (!SUCCEEDED(hr)) {
    756    aFailureReason =
    757        nsPrintfCString("IDXGIDevice::GetAdapter failed with code %lX", hr);
    758    return hr;
    759  }
    760 
    761  DXGI_ADAPTER_DESC adapterDesc;
    762  hr = adapter->GetDesc(&adapterDesc);
    763  if (!SUCCEEDED(hr)) {
    764    aFailureReason =
    765        nsPrintfCString("IDXGIAdapter::GetDesc failed with code %lX", hr);
    766    return hr;
    767  }
    768 
    769  mVendorID = adapterDesc.VendorId;
    770 
    771  if ((adapterDesc.VendorId == 0x1022 || adapterDesc.VendorId == 0x1002) &&
    772      !StaticPrefs::media_wmf_skip_blacklist()) {
    773    for (const auto& model : sAMDPreUVD4) {
    774      if (adapterDesc.DeviceId == model) {
    775        mIsAMDPreUVD4 = true;
    776        break;
    777      }
    778    }
    779  }
    780 
    781  if (!IsD3D11() || !XRE_IsGPUProcess() ||
    782      (mDevice != DeviceManagerDx::Get()->GetCompositorDevice())) {
    783    mZeroCopyUsageInfo->DisableZeroCopyNV12Texture();
    784  }
    785 
    786  return S_OK;
    787 }
    788 
    789 HRESULT
    790 D3D11DXVA2Manager::CreateOutputSample(RefPtr<IMFSample>& aSample,
    791                                      ID3D11Texture2D* aTexture) {
    792  RefPtr<IMFSample> sample;
    793  HRESULT hr = wmf::MFCreateSample(getter_AddRefs(sample));
    794  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    795 
    796  RefPtr<IMFMediaBuffer> buffer;
    797  hr = wmf::MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), aTexture, 0,
    798                                      FALSE, getter_AddRefs(buffer));
    799  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    800 
    801  hr = sample->AddBuffer(buffer);
    802  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    803 
    804  aSample = sample;
    805  return S_OK;
    806 }
    807 
    808 HRESULT
    809 D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
    810                               const gfx::IntRect& aRegion, Image** aOutImage) {
    811  NS_ENSURE_TRUE(aVideoSample, E_POINTER);
    812  NS_ENSURE_TRUE(aOutImage, E_POINTER);
    813  MOZ_ASSERT(mTextureClientAllocator);
    814 
    815  // Retrieve the DXGI_FORMAT for the current video sample.
    816  RefPtr<IMFMediaBuffer> buffer;
    817  HRESULT hr = aVideoSample->GetBufferByIndex(0, getter_AddRefs(buffer));
    818  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    819 
    820  RefPtr<IMFDXGIBuffer> dxgiBuf;
    821  hr = buffer->QueryInterface((IMFDXGIBuffer**)getter_AddRefs(dxgiBuf));
    822  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    823 
    824  RefPtr<ID3D11Texture2D> inputTexture;
    825  hr = dxgiBuf->GetResource(__uuidof(ID3D11Texture2D),
    826                            getter_AddRefs(inputTexture));
    827  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    828 
    829  UINT index;
    830  dxgiBuf->GetSubresourceIndex(&index);
    831 
    832  InputTextureInfo info(inputTexture, index, aRegion);
    833  return CopyTextureToImage(info, aOutImage);
    834 }
    835 
    836 HRESULT D3D11DXVA2Manager::CopyToImage(ID3D11Texture2D* aInputTexture,
    837                                       UINT aSurfaceIndex,
    838                                       const gfx::IntRect& aRegion,
    839                                       layers::Image** aOutImage) {
    840  InputTextureInfo info(aInputTexture, aSurfaceIndex, aRegion);
    841  return CopyTextureToImage(info, aOutImage);
    842 }
    843 
    844 HRESULT D3D11DXVA2Manager::WrapTextureWithImage(IMFSample* aVideoSample,
    845                                                const gfx::IntRect& aRegion,
    846                                                layers::Image** aOutImage) {
    847  NS_ENSURE_TRUE(aVideoSample, E_POINTER);
    848  NS_ENSURE_TRUE(aOutImage, E_POINTER);
    849 
    850  RefPtr<IMFMediaBuffer> buffer;
    851  HRESULT hr = aVideoSample->GetBufferByIndex(0, getter_AddRefs(buffer));
    852  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    853 
    854  RefPtr<IMFDXGIBuffer> dxgiBuf;
    855  hr = buffer->QueryInterface((IMFDXGIBuffer**)getter_AddRefs(dxgiBuf));
    856  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    857 
    858  RefPtr<ID3D11Texture2D> texture;
    859  hr = dxgiBuf->GetResource(__uuidof(ID3D11Texture2D), getter_AddRefs(texture));
    860  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
    861 
    862  D3D11_TEXTURE2D_DESC desc;
    863  texture->GetDesc(&desc);
    864 
    865  UINT arrayIndex;
    866  dxgiBuf->GetSubresourceIndex(&arrayIndex);
    867 
    868  RefreshIMFSampleWrappers();
    869 
    870  auto format = [&]() {
    871    if (desc.Format == DXGI_FORMAT_P010) {
    872      return gfx::SurfaceFormat::P010;
    873    }
    874    if (desc.Format == DXGI_FORMAT_P016) {
    875      return gfx::SurfaceFormat::P016;
    876    }
    877    MOZ_ASSERT(desc.Format == DXGI_FORMAT_NV12);
    878    return gfx::SurfaceFormat::NV12;
    879  }();
    880 
    881  RefPtr<D3D11TextureIMFSampleImage> image = new D3D11TextureIMFSampleImage(
    882      aVideoSample, texture, arrayIndex, gfx::IntSize(mWidth, mHeight), aRegion,
    883      format, ToColorSpace2(mYUVColorSpace), mColorRange, mColorDepth);
    884  image->AllocateTextureClient(mKnowsCompositor, mZeroCopyUsageInfo,
    885                               mWriteFence);
    886 
    887  RefPtr<IMFSampleWrapper> wrapper = image->GetIMFSampleWrapper();
    888  ThreadSafeWeakPtr<IMFSampleWrapper> weak(wrapper);
    889  mIMFSampleWrappers.push_back(weak);
    890 
    891  image.forget(aOutImage);
    892 
    893  return S_OK;
    894 }
    895 
    896 HRESULT D3D11DXVA2Manager::WrapTextureWithImage(
    897    D3D11TextureWrapper* aTextureWrapper, const gfx::IntRect& aRegion,
    898    layers::Image** aOutImage) {
    899  NS_ENSURE_TRUE(aOutImage, E_POINTER);
    900  RefPtr<D3D11TextureAVFrameImage> image = new D3D11TextureAVFrameImage(
    901      aTextureWrapper, gfx::IntSize(mWidth, mHeight), aRegion,
    902      ToColorSpace2(mYUVColorSpace), mColorRange, mColorDepth);
    903  image->AllocateTextureClient(mKnowsCompositor, mZeroCopyUsageInfo,
    904                               mWriteFence);
    905  image.forget(aOutImage);
    906  return S_OK;
    907 }
    908 
    909 void D3D11DXVA2Manager::RefreshIMFSampleWrappers() {
    910  for (auto it = mIMFSampleWrappers.begin(); it != mIMFSampleWrappers.end();) {
    911    auto wrapper = RefPtr<IMFSampleWrapper>(*it);
    912    if (!wrapper) {
    913      // wrapper is already destroyed.
    914      it = mIMFSampleWrappers.erase(it);
    915      continue;
    916    }
    917    it++;
    918  }
    919 }
    920 
    921 void D3D11DXVA2Manager::ReleaseAllIMFSamples() {
    922  for (auto it = mIMFSampleWrappers.begin(); it != mIMFSampleWrappers.end();
    923       it++) {
    924    RefPtr<IMFSampleWrapper> wrapper = RefPtr<IMFSampleWrapper>(*it);
    925    if (wrapper) {
    926      wrapper->ClearVideoSample();
    927    }
    928  }
    929 }
    930 
    931 void D3D11DXVA2Manager::BeforeShutdownVideoMFTDecoder() {
    932  ReleaseAllIMFSamples();
    933 }
    934 
    935 // Glossary of RGB formats for display:
    936 // DXGI_FORMAT_B8G8R8A8_UNORM     <-> MFVideoFormat_ARGB32
    937 // DXGI_FORMAT_R16G16B16A16_FLOAT <-> MFVideoFormat_A16B16G16R16F
    938 // DXGI_FORMAT_R10G10B10A2_UNORM  <-> MFVideoFormat_A2R10G10B10
    939 // (Yes MFVideoFormat_A2R10G10B10 is actually R10G10B10A2)
    940 //
    941 // YUV formats for decoder output:
    942 // DXGI_FORMAT_NV12               <-> MFVideoFormat_NV12
    943 // DXGI_FORMAT_YV12               <-> MFVideoFormat_YV12
    944 // DXGI_FORMAT_P010               <-> MFVideoFormat_P010
    945 // DXGI_FORMAT_P016               <-> MFVideoFormat_P016
    946 //
    947 // Format pairings for SDR colorspaces:
    948 // {DXGI_FORMAT_NV12, DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709}
    949 // {DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709}
    950 //
    951 // Format pairings for HDR colorspaces:
    952 // {DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020}
    953 // {DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709}
    954 //
    955 // A few notes:
    956 // * NV12 can be directly displayed as an overlay, whereas all other
    957 //   formats need to be converted to RGB for display.
    958 // * YV12 is only used for SW decode (and we have no SurfaceFormat to represent
    959 //   it, gfx::SurfaceFormat::YUV420 has a different plane order).
    960 // * P010 and P016 are for HDR video, testing these as an overlay showed that
    961 //   they do not seem to honor the HDR G2084 transfer function so we can
    962 //   consider them simply not displayable.
    963 // * If a video has alpha channel the decoder would have to output RGBA because
    964 //   Windows has no enums for YUV with alpha, we don't currently support RGBA
    965 //   output from decoders so alpha is not currently relevant.
    966 // * Windows seems to do some magic HDR tonemapping on SDR displays without even
    967 //   telling it to do anything, it's not clear what we can rely on about this,
    968 //   but testing in the wild is probably the best answer for now.
    969 
    970 // Convert a Media Foundation subtype GUID to a gfx::SurfaceFormat.
    971 static gfx::SurfaceFormat SurfaceFormatFromSubType(const GUID& aSubType) {
    972  // We can't use a switch on subType because GUID is a struct.
    973  if (aSubType == MFVideoFormat_ARGB32) {
    974    return gfx::SurfaceFormat::B8G8R8A8;
    975  }
    976  if (aSubType == MFVideoFormat_A16B16G16R16F) {
    977    return gfx::SurfaceFormat::R16G16B16A16F;
    978  }
    979  if (aSubType == MFVideoFormat_A2R10G10B10) {
    980    return gfx::SurfaceFormat::R10G10B10X2_UINT32;
    981  }
    982  if (aSubType == MFVideoFormat_NV12) {
    983    return gfx::SurfaceFormat::NV12;
    984  }
    985  if (aSubType == MFVideoFormat_YUY2) {
    986    return gfx::SurfaceFormat::YUY2;
    987  }
    988  if (aSubType == MFVideoFormat_P010) {
    989    return gfx::SurfaceFormat::P010;
    990  }
    991  if (aSubType == MFVideoFormat_P016) {
    992    return gfx::SurfaceFormat::P016;
    993  }
    994  MOZ_ASSERT_UNREACHABLE("Unknown subtype");
    995  return gfx::SurfaceFormat::UNKNOWN;
    996 }
    997 
    998 HRESULT
    999 D3D11DXVA2Manager::ConfigureForSize(IMFMediaType* aInputType,
   1000                                    gfx::YUVColorSpace aColorSpace,
   1001                                    gfx::ColorRange aColorRange,
   1002                                    gfx::ColorDepth aColorDepth,
   1003                                    gfx::TransferFunction aTransferFunction,
   1004                                    uint32_t aWidth, uint32_t aHeight) {
   1005  GUID subType = {0};
   1006  HRESULT hr = aInputType->GetGUID(MF_MT_SUBTYPE, &subType);
   1007  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1008 
   1009  // The aInputType subType here is one of the following:
   1010  // * MFVideoFormat_NV12
   1011  // * MFVideoFormat_YV12
   1012  // * MFVideoFormat_P010
   1013  // * MFVideoFormat_P016
   1014 
   1015  if (subType == mInputSubType && aWidth == mWidth && aHeight == mHeight &&
   1016      mYUVColorSpace == aColorSpace && mColorRange == aColorRange &&
   1017      mColorDepth == aColorDepth && mTransferFunction == aTransferFunction) {
   1018    // If the media type hasn't changed, don't reconfigure.
   1019    return S_OK;
   1020  }
   1021 
   1022  // Create a copy of our input type.
   1023  RefPtr<IMFMediaType> inputType;
   1024  hr = wmf::MFCreateMediaType(getter_AddRefs(inputType));
   1025  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1026  hr = aInputType->CopyAllItems(inputType);
   1027  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1028 
   1029  hr = MFSetAttributeSize(inputType, MF_MT_FRAME_SIZE, aWidth, aHeight);
   1030  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1031 
   1032  RefPtr<IMFAttributes> attr;
   1033  mozilla::mscom::EnsureMTA(
   1034      [&]() -> void { attr = mTransform->GetAttributes(); });
   1035  NS_ENSURE_TRUE(attr != nullptr, E_FAIL);
   1036 
   1037  hr = attr->SetUINT32(MF_XVP_PLAYBACK_MODE, TRUE);
   1038  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1039 
   1040  hr = attr->SetUINT32(MF_LOW_LATENCY, FALSE);
   1041  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1042 
   1043  RefPtr<IMFMediaType> outputType;
   1044  hr = wmf::MFCreateMediaType(getter_AddRefs(outputType));
   1045  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1046 
   1047  hr = outputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
   1048  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1049 
   1050  // Pick an RGB format based on the required color depth.
   1051  if (aColorDepth > gfx::ColorDepth::COLOR_10) {
   1052    hr = outputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_A16B16G16R16F);
   1053    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1054  } else if (aColorDepth > gfx::ColorDepth::COLOR_8) {
   1055    hr = outputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_A2R10G10B10);
   1056    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1057  } else {
   1058    hr = outputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_ARGB32);
   1059    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1060  }
   1061 
   1062  // TODO(https://bugzilla.mozilla.org/show_bug.cgi?id=2008874)
   1063  hr = E_FAIL;
   1064  mozilla::mscom::EnsureMTA([&]() -> void {
   1065    hr = mTransform->SetMediaTypes(
   1066        inputType, outputType, MFVideoFormat_ARGB32,
   1067        [aWidth, aHeight](IMFMediaType* aOutput) {
   1068          HRESULT hr = aOutput->SetUINT32(MF_MT_INTERLACE_MODE,
   1069                                          MFVideoInterlace_Progressive);
   1070          NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1071          hr = aOutput->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
   1072          NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1073          hr = MFSetAttributeSize(aOutput, MF_MT_FRAME_SIZE, aWidth, aHeight);
   1074          NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1075 
   1076          return S_OK;
   1077        });
   1078  });
   1079  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1080 
   1081  const bool isSizeChanged = (mWidth != aWidth) || (mHeight != aHeight);
   1082  mWidth = aWidth;
   1083  mHeight = aHeight;
   1084  mInputType = inputType;
   1085  mInputSubType = subType;
   1086  mYUVColorSpace = aColorSpace;
   1087  mColorRange = aColorRange;
   1088  mColorDepth = aColorDepth;
   1089  mTransferFunction = aTransferFunction;
   1090  if (mTextureClientAllocator) {
   1091    mSurfaceFormat = SurfaceFormatFromSubType(subType);
   1092    mTextureClientAllocator->SetPreferredSurfaceFormat(mSurfaceFormat);
   1093  }
   1094  // Reconfig video processor as well
   1095  if (isSizeChanged && mProcessor) {
   1096    hr = mProcessor->Init(gfx::IntSize(mWidth, mHeight));
   1097    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   1098  }
   1099  LOG("Configured D3D11DXVA2Manager, size=[%u,%u], colorSpace=%hhu, "
   1100      "colorRange=%hhu, colorDepth=%hhu, transferFunction=%hhu",
   1101      mWidth, mHeight, static_cast<uint8_t>(mYUVColorSpace),
   1102      static_cast<uint8_t>(mColorRange), static_cast<uint8_t>(mColorDepth),
   1103      static_cast<uint8_t>(mTransferFunction));
   1104  return S_OK;
   1105 }
   1106 
   1107 HRESULT
   1108 D3D11DXVA2Manager::ConfigureForSize(gfx::SurfaceFormat aSurfaceFormat,
   1109                                    gfx::YUVColorSpace aColorSpace,
   1110                                    gfx::ColorRange aColorRange,
   1111                                    gfx::ColorDepth aColorDepth,
   1112                                    gfx::TransferFunction aTransferFunction,
   1113                                    uint32_t aWidth, uint32_t aHeight) {
   1114  if (aWidth == mWidth && aHeight == mHeight && mYUVColorSpace == aColorSpace &&
   1115      mColorRange == aColorRange && aSurfaceFormat == mSurfaceFormat &&
   1116      mColorDepth == aColorDepth && mTransferFunction == aTransferFunction) {
   1117    // No need to reconfigure if nothing changes.
   1118    return S_OK;
   1119  }
   1120 
   1121  const bool isSizeChanged = (mWidth != aWidth) || (mHeight != aHeight);
   1122  mWidth = aWidth;
   1123  mHeight = aHeight;
   1124  mYUVColorSpace = aColorSpace;
   1125  mColorRange = aColorRange;
   1126  mColorDepth = aColorDepth;
   1127  mSurfaceFormat = aSurfaceFormat;
   1128  mTransferFunction = aTransferFunction;
   1129  if (mTextureClientAllocator) {
   1130    // mSurfaceFormat here is one of the following:
   1131    // * SurfaceFormat::NV12
   1132    // * SurfaceFormat::YV12
   1133    // * SurfaceFormat::P010
   1134    // * SurfaceFormat::P016
   1135    mTextureClientAllocator->SetPreferredSurfaceFormat(mSurfaceFormat);
   1136  }
   1137  // Reconfig video processor as well
   1138  if (isSizeChanged && mProcessor) {
   1139    mProcessor->Init(gfx::IntSize(mWidth, mHeight));
   1140  }
   1141  LOG("Configured D3D11DXVA2Manager, size=[%u,%u], colorSpace=%hhu, "
   1142      "colorRange=%hhu, colorDepth=%hhu, transferFunction=%hhu, "
   1143      "surfaceFormat=%hhd",
   1144      mWidth, mHeight, static_cast<uint8_t>(mYUVColorSpace),
   1145      static_cast<uint8_t>(mColorRange), static_cast<uint8_t>(mColorDepth),
   1146      static_cast<uint8_t>(mTransferFunction),
   1147      static_cast<uint8_t>(mSurfaceFormat));
   1148  return S_OK;
   1149 }
   1150 
   1151 bool D3D11DXVA2Manager::CanCreateDecoder(
   1152    const D3D11_VIDEO_DECODER_DESC& aDesc) const {
   1153  RefPtr<ID3D11VideoDevice> videoDevice;
   1154  HRESULT hr = mDevice->QueryInterface(
   1155      static_cast<ID3D11VideoDevice**>(getter_AddRefs(videoDevice)));
   1156  if (FAILED(hr)) {
   1157    LOG("Failed to query ID3D11VideoDevice!");
   1158    return false;
   1159  }
   1160 
   1161  UINT configCount = 0;
   1162  hr = videoDevice->GetVideoDecoderConfigCount(&aDesc, &configCount);
   1163  if (FAILED(hr)) {
   1164    LOG("Failed to get decoder config count!");
   1165    return false;
   1166  }
   1167 
   1168  for (UINT i = 0; i < configCount; i++) {
   1169    D3D11_VIDEO_DECODER_CONFIG config;
   1170    hr = videoDevice->GetVideoDecoderConfig(&aDesc, i, &config);
   1171    if (SUCCEEDED(hr)) {
   1172      RefPtr<ID3D11VideoDecoder> decoder;
   1173      hr = videoDevice->CreateVideoDecoder(&aDesc, &config,
   1174                                           decoder.StartAssignment());
   1175      return decoder != nullptr;
   1176    }
   1177  }
   1178  return false;
   1179 }
   1180 
   1181 /* static */
   1182 DXVA2Manager* DXVA2Manager::CreateD3D11DXVA(
   1183    layers::KnowsCompositor* aKnowsCompositor, nsACString& aFailureReason,
   1184    ID3D11Device* aDevice, DXVA2Usage aUsage) {
   1185  // DXVA processing takes up a lot of GPU resources, so limit the number of
   1186  // videos we use DXVA with at any one time.
   1187  uint32_t dxvaLimit = StaticPrefs::media_wmf_dxva_max_videos();
   1188 
   1189  if (sDXVAVideosCount == dxvaLimit && aUsage == DXVA2Usage::Playback) {
   1190    aFailureReason.AssignLiteral("Too many DXVA videos playing");
   1191    return nullptr;
   1192  }
   1193 
   1194  UniquePtr<D3D11DXVA2Manager> manager(new D3D11DXVA2Manager());
   1195  HRESULT hr = manager->Init(aKnowsCompositor, aFailureReason, aDevice);
   1196  NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
   1197 
   1198  return manager.release();
   1199 }
   1200 
   1201 DXVA2Manager::DXVA2Manager() : mLock("DXVA2Manager") { ++sDXVAVideosCount; }
   1202 
   1203 DXVA2Manager::~DXVA2Manager() { --sDXVAVideosCount; }
   1204 
   1205 bool DXVA2Manager::IsUnsupportedResolution(const uint32_t& aWidth,
   1206                                           const uint32_t& aHeight,
   1207                                           const float& aFramerate) const {
   1208  // AMD cards with UVD3 or earlier perform poorly trying to decode 1080p60 in
   1209  // hardware, so use software instead. Pick 45 as an arbitrary upper bound for
   1210  // the framerate we can handle.
   1211  return !StaticPrefs::media_wmf_amd_highres_enabled() && mIsAMDPreUVD4 &&
   1212         (aWidth >= 1920 || aHeight >= 1088) && aFramerate > 45;
   1213 }
   1214 
   1215 /* static */
   1216 bool DXVA2Manager::IsNV12Supported(uint32_t aVendorID, uint32_t aDeviceID,
   1217                                   const nsAString& aDriverVersionString) {
   1218  if (aVendorID == 0x1022 || aVendorID == 0x1002) {
   1219    // AMD
   1220    // Block old cards regardless of driver version.
   1221    for (const auto& model : sAMDPreUVD4) {
   1222      if (aDeviceID == model) {
   1223        return false;
   1224      }
   1225    }
   1226    // AMD driver earlier than 21.19.411.0 have bugs in their handling of NV12
   1227    // surfaces.
   1228    uint64_t driverVersion;
   1229    if (!widget::ParseDriverVersion(aDriverVersionString, &driverVersion) ||
   1230        driverVersion < widget::V(21, 19, 411, 0)) {
   1231      return false;
   1232    }
   1233  } else if (aVendorID == 0x10DE) {
   1234    // NVidia
   1235    for (const auto& model : sNVIDIABrokenNV12) {
   1236      if (aDeviceID == model) {
   1237        return false;
   1238      }
   1239    }
   1240  }
   1241  return true;
   1242 }
   1243 
   1244 HRESULT D3D11DXVA2Manager::CopyTextureToImage(
   1245    const InputTextureInfo& aInTexture, Image** aOutImage) {
   1246  MOZ_DIAGNOSTIC_ASSERT(aInTexture.mTexture);
   1247 
   1248  D3D11_TEXTURE2D_DESC inDesc;
   1249  aInTexture.mTexture->GetDesc(&inDesc);
   1250 
   1251  LOG("CopyTextureToImage, inDesc.Format=%d, mYUVColorSpace=%d, "
   1252      "mColorRange=%d, mColorDepth=%d",
   1253      inDesc.Format, static_cast<int>(mYUVColorSpace),
   1254      static_cast<int>(mColorRange), static_cast<int>(mColorDepth));
   1255 
   1256  RefPtr<D3D11ShareHandleImage> image = new D3D11ShareHandleImage(
   1257      gfx::IntSize(mWidth, mHeight), aInTexture.mRegion,
   1258      ToColorSpace2(mYUVColorSpace), mColorRange, mColorDepth);
   1259 
   1260  if (!image->AllocateTexture(mTextureClientAllocator, mDevice)) {
   1261    LOG("Failed to allocate texture!");
   1262    return E_FAIL;
   1263  }
   1264 
   1265  RefPtr<TextureClient> client =
   1266      image->GetTextureClient(ImageBridgeChild::GetSingleton().get());
   1267  if (!client) {
   1268    LOG("Failed to get texture client!");
   1269    return E_FAIL;
   1270  }
   1271 
   1272  RefPtr<ID3D11Texture2D> texture = image->GetTexture();
   1273  D3D11_TEXTURE2D_DESC outDesc;
   1274  texture->GetDesc(&outDesc);
   1275 
   1276  LOGV("CopyTexture, inTextureFormat=%d, outTextureFormat=%d", inDesc.Format,
   1277       outDesc.Format);
   1278 
   1279  RefPtr<IDXGIKeyedMutex> mutex;
   1280  texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
   1281 
   1282  HRESULT hr;
   1283  {
   1284    AutoTextureLock(mutex, hr, 2000);
   1285    if (mutex && (FAILED(hr) || hr == WAIT_TIMEOUT || hr == WAIT_ABANDONED)) {
   1286      LOG("Failed to require texture lock");
   1287      return hr;
   1288    }
   1289 
   1290    if (!mutex && mDevice != DeviceManagerDx::Get()->GetCompositorDevice() &&
   1291        !mSyncObject) {
   1292      LOG("No sync object!");
   1293      return E_FAIL;
   1294    }
   1295 
   1296    UINT height = std::min(inDesc.Height, outDesc.Height);
   1297    PerformanceRecorder<PlaybackStage> perfRecorder(
   1298        MediaStage::CopyDecodedVideo, height);
   1299    // The D3D11TextureClientAllocator may return a different texture format
   1300    // than preferred. In which case the destination texture will be BGRA32.
   1301    // Eg. when NV12 is blocked by Gfx.
   1302    if (outDesc.Format == inDesc.Format) {
   1303      // Our video frame is stored in a non-sharable ID3D11Texture2D. We need
   1304      // to create a copy of that frame as a sharable resource, save its share
   1305      // handle, and put that handle into the rendering pipeline.
   1306      UINT width = std::min(inDesc.Width, outDesc.Width);
   1307      D3D11_BOX srcBox = {0, 0, 0, width, height, 1};
   1308      mContext->CopySubresourceRegion(texture, 0, 0, 0, 0, aInTexture.mTexture,
   1309                                      aInTexture.mIndex, &srcBox);
   1310    } else {
   1311      // Convert YUV to RGB.
   1312      auto* processor = GetOrCreateVideoProcessor();
   1313      if (!processor) {
   1314        LOG("Failed to get a video processor");
   1315        return E_FAIL;
   1316      }
   1317      VideoProcessorD3D11::InputTextureInfo info(ToColorSpace2(mYUVColorSpace),
   1318                                                 mColorRange, aInTexture.mIndex,
   1319                                                 aInTexture.mTexture);
   1320      if (!processor->CallVideoProcessorBlt(info, texture.get())) {
   1321        LOG("Failed on CallVideoProcessorBlt!");
   1322        return E_FAIL;
   1323      }
   1324    }
   1325    perfRecorder.Record();
   1326  }
   1327 
   1328  auto* textureData = client->GetInternalData()->AsD3D11TextureData();
   1329  auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get();
   1330  MOZ_ASSERT(textureData);
   1331  const bool useFence =
   1332      textureData && textureData->mFencesHolderId.isSome() && fencesHolderMap;
   1333  if (useFence) {
   1334    textureData->IncrementAndSignalWriteFence();
   1335  } else if (!mutex &&
   1336             mDevice != DeviceManagerDx::Get()->GetCompositorDevice() &&
   1337             mSyncObject) {
   1338    static StaticMutex sMutex MOZ_UNANNOTATED;
   1339    // Ensure that we only ever attempt to synchronise via the sync object
   1340    // serially as when using the same D3D11 device for multiple video decoders
   1341    // it can lead to deadlocks.
   1342    StaticMutexAutoLock lock(sMutex);
   1343    // It appears some race-condition may allow us to arrive here even when
   1344    // mSyncObject is null. It's better to avoid that crash.
   1345    client->SyncWithObject(mSyncObject);
   1346    if (!mSyncObject->Synchronize(true)) {
   1347      return DXGI_ERROR_DEVICE_RESET;
   1348    }
   1349  }
   1350 
   1351  image.forget(aOutImage);
   1352  return S_OK;
   1353 }
   1354 
   1355 VideoProcessorD3D11* D3D11DXVA2Manager::GetOrCreateVideoProcessor() {
   1356  if (mProcessor) {
   1357    return mProcessor;
   1358  }
   1359  mProcessor = VideoProcessorD3D11::Create(mDevice);
   1360  if (!mProcessor) {
   1361    LOG("Failed to create video processor D3D11");
   1362    return nullptr;
   1363  }
   1364  HRESULT hr = mProcessor->Init(gfx::IntSize(mWidth, mHeight));
   1365  if (FAILED(hr)) {
   1366    mProcessor = nullptr;
   1367    LOG("Failed to init video processor D3D11, hr=%lx", hr);
   1368  }
   1369  return mProcessor;
   1370 }
   1371 
   1372 }  // namespace mozilla
   1373 
   1374 #undef LOG
   1375 #undef LOGV