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