From 107cd6aa7dc5fa838634f5add8edd4f69a7346a7 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Thu, 20 Aug 2015 11:37:26 -0400 Subject: [PATCH] Bug 1196411 - Disable DXVA on 60fps 1080p videos for AMD cards that can't decode quick enough. r=jya --- dom/media/platforms/wmf/DXVA2Manager.cpp | 93 ++++++++++++++++++- dom/media/platforms/wmf/DXVA2Manager.h | 2 +- .../platforms/wmf/WMFVideoMFTManager.cpp | 8 +- dom/media/platforms/wmf/WMFVideoMFTManager.h | 1 + 4 files changed, 98 insertions(+), 6 deletions(-) diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 323081fb8c0e..5d70fcd754ea 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -37,6 +37,35 @@ const GUID MF_XVP_PLAYBACK_MODE = DEFINE_GUID(MF_LOW_LATENCY, 0x9c27891a, 0xed7a, 0x40e1, 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee); +// R600, R700, Evergreen and Cayman AMD cards. These support DXVA via UVD3 or earlier, and don't +// handle 1080p60 well. +static const DWORD sAMDPreUVD4[] = { + 0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x94c0, 0x94c1, 0x94c3, 0x94c4, 0x94c5, + 0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, 0x94cc, 0x94cd, 0x9580, 0x9581, 0x9583, 0x9586, 0x9587, 0x9588, + 0x9589, 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f, 0x9500, 0x9501, 0x9504, 0x9505, 0x9506, 0x9507, + 0x9508, 0x9509, 0x950f, 0x9511, 0x9515, 0x9517, 0x9519, 0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7, + 0x95c9, 0x95cc, 0x95cd, 0x95ce, 0x95cf, 0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599, + 0x959b, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, 0x9616, 0x9710, 0x9711, 0x9712, 0x9713, 0x9714, + 0x9715, 0x9440, 0x9441, 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e, 0x9450, 0x9452, + 0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a, 0x946b, 0x947a, 0x947b, 0x9480, 0x9487, 0x9488, + 0x9489, 0x948a, 0x948f, 0x9490, 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x9540, 0x9541, 0x9542, + 0x954e, 0x954f, 0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x94a0, 0x94a1, 0x94a3, 0x94b1, 0x94b3, 0x94b4, + 0x94b5, 0x94b9, 0x68e0, 0x68e1, 0x68e4, 0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa, + 0x68fe, 0x68c0, 0x68c1, 0x68c7, 0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, 0x68a0, 0x68a1, 0x68a8, + 0x68a9, 0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, 0x68bf, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d, + 0x6898, 0x6899, 0x689b, 0x689e, 0x689c, 0x689d, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, 0x9807, 0x9808, + 0x9809, 0x980a, 0x9640, 0x9641, 0x9647, 0x9648, 0x964a, 0x964b, 0x964c, 0x964e, 0x964f, 0x9642, 0x9643, + 0x9644, 0x9645, 0x9649, 0x6720, 0x6721, 0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, 0x6729, + 0x6738, 0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, 0x6745, 0x6746, 0x6747, 0x6748, 0x6749, + 0x674a, 0x6750, 0x6751, 0x6758, 0x6759, 0x675b, 0x675d, 0x675f, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849, + 0x6850, 0x6858, 0x6859, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, 0x6766, 0x6767, 0x6768, 0x6770, + 0x6771, 0x6772, 0x6778, 0x6779, 0x677b, 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707, + 0x6708, 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x9900, 0x9901, 0x9903, 0x9904, 0x9905, 0x9906, + 0x9907, 0x9908, 0x9909, 0x990a, 0x990b, 0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918, + 0x9919, 0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998, 0x9999, 0x999a, 0x999b, + 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4 +}; + namespace mozilla { using layers::Image; @@ -63,7 +92,7 @@ public: ImageContainer* aContainer, Image** aOutImage) override; - virtual bool SupportsConfig(IMFMediaType* aType) override; + virtual bool SupportsConfig(IMFMediaType* aType, float aFramerate) override; private: nsRefPtr mD3D9; @@ -73,6 +102,7 @@ private: nsRefPtr mDecoderService; UINT32 mResetToken; bool mFirstFrame; + bool mIsAMDPreUVD4; }; void GetDXVA2ExtendedFormatFromMFMediaType(IMFMediaType *pType, @@ -145,12 +175,21 @@ static const GUID DXVA2_ModeH264_E = { // decoder MFT provided by windows (CLSID_CMSH264DecoderMFT) uses, so we can use it to determine // if the MFT will use software fallback or not. bool -D3D9DXVA2Manager::SupportsConfig(IMFMediaType* aType) +D3D9DXVA2Manager::SupportsConfig(IMFMediaType* aType, float aFramerate) { DXVA2_VideoDesc desc; HRESULT hr = ConvertMFTypeToDXVAType(aType, &desc); NS_ENSURE_TRUE(SUCCEEDED(hr), false); + // AMD cards with UVD3 or earlier perform poorly trying to decode 1080p60 in hardware, + // so use software instead. Pick 45 as an arbitrary upper bound for the framerate we can + // handle. + if (mIsAMDPreUVD4 && + (desc.SampleWidth >= 1920 || desc.SampleHeight >= 1088) && + aFramerate > 45) { + return false; + } + UINT configCount; DXVA2_ConfigPictureDecode* configs = nullptr; hr = mDecoderService->GetDecoderConfigurations(DXVA2_ModeH264_E, &desc, nullptr, &configCount, &configs); @@ -181,6 +220,7 @@ D3D9DXVA2Manager::SupportsConfig(IMFMediaType* aType) D3D9DXVA2Manager::D3D9DXVA2Manager() : mResetToken(0) , mFirstFrame(true) + , mIsAMDPreUVD4(false) { MOZ_COUNT_CTOR(D3D9DXVA2Manager); MOZ_ASSERT(NS_IsMainThread()); @@ -316,6 +356,19 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason) return E_FAIL; } + D3DADAPTER_IDENTIFIER9 adapter; + hr = d3d9Ex->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &adapter); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + if (adapter.VendorId = 0x1022) { + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) { + if (adapter.DeviceId == sAMDPreUVD4[i]) { + mIsAMDPreUVD4 = true; + break; + } + } + } + mDecoderService = decoderService; mResetToken = resetToken; @@ -412,7 +465,7 @@ public: virtual bool IsD3D11() override { return true; } - virtual bool SupportsConfig(IMFMediaType* aType) override; + virtual bool SupportsConfig(IMFMediaType* aType, float aFramerate) override; private: HRESULT CreateFormatConverter(); @@ -428,10 +481,11 @@ private: uint32_t mWidth; uint32_t mHeight; UINT mDeviceManagerToken; + bool mIsAMDPreUVD4; }; bool -D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType) +D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType, float aFramerate) { RefPtr videoDevice; HRESULT hr = mDevice->QueryInterface(static_cast(byRef(videoDevice))); @@ -449,6 +503,15 @@ D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType) desc.OutputFormat = DXGI_FORMAT_NV12; + // AMD cards with UVD3 or earlier perform poorly trying to decode 1080p60 in hardware, + // so use software instead. Pick 45 as an arbitrary upper bound for the framerate we can + // handle. + if (mIsAMDPreUVD4 && + (desc.SampleWidth >= 1920 || desc.SampleHeight >= 1088) && + aFramerate > 45) { + return false; + } + UINT configCount = 0; hr = videoDevice->GetVideoDecoderConfigCount(&desc, &configCount); NS_ENSURE_TRUE(SUCCEEDED(hr), false); @@ -471,6 +534,7 @@ D3D11DXVA2Manager::D3D11DXVA2Manager() : mWidth(0) , mHeight(0) , mDeviceManagerToken(0) + , mIsAMDPreUVD4(false) { } @@ -552,6 +616,27 @@ D3D11DXVA2Manager::Init(nsACString& aFailureReason) return E_FAIL; } + RefPtr dxgiDevice; + hr = mDevice->QueryInterface(static_cast(byRef(dxgiDevice))); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + nsRefPtr adapter; + hr = dxgiDevice->GetAdapter(adapter.StartAssignment()); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + DXGI_ADAPTER_DESC adapterDesc; + hr = adapter->GetDesc(&adapterDesc); + NS_ENSURE_TRUE(SUCCEEDED(hr), hr); + + if (adapterDesc.VendorId = 0x1022) { + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) { + if (adapterDesc.DeviceId == sAMDPreUVD4[i]) { + mIsAMDPreUVD4 = true; + break; + } + } + } + mTextureClientAllocator = new D3D11RecycleAllocator(layers::ImageBridgeChild::GetSingleton(), mDevice); mTextureClientAllocator->SetMaxPoolSize(5); diff --git a/dom/media/platforms/wmf/DXVA2Manager.h b/dom/media/platforms/wmf/DXVA2Manager.h index cb361a297627..c44d1859fdf5 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.h +++ b/dom/media/platforms/wmf/DXVA2Manager.h @@ -44,7 +44,7 @@ public: virtual ~DXVA2Manager(); - virtual bool SupportsConfig(IMFMediaType* aType) = 0; + virtual bool SupportsConfig(IMFMediaType* aType, float aFramerate) = 0; protected: Mutex mLock; diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index 386f44e14348..742bd9dfe104 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -307,6 +307,8 @@ WMFVideoMFTManager::Input(MediaRawData* aSample) &mLastInput); NS_ENSURE_TRUE(SUCCEEDED(hr) && mLastInput != nullptr, hr); + mLastDuration = aSample->mDuration; + // Forward sample data to the decoder. return mDecoder->Input(mLastInput); } @@ -330,7 +332,11 @@ WMFVideoMFTManager::MaybeToggleDXVA(IMFMediaType* aType) return false; } - if (mDXVA2Manager->SupportsConfig(aType)) { + // Assume the current samples duration is representative for the + // entire video. + float framerate = 1000000.0 / mLastDuration; + + if (mDXVA2Manager->SupportsConfig(aType, framerate)) { if (!mUseHwAccel) { // DXVA disabled, but supported for this resolution ULONG_PTR manager = ULONG_PTR(mDXVA2Manager->GetDXVADeviceManager()); diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.h b/dom/media/platforms/wmf/WMFVideoMFTManager.h index 467b70a63c32..8a209b49b69c 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.h +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h @@ -72,6 +72,7 @@ private: nsAutoPtr mDXVA2Manager; RefPtr mLastInput; + float mLastDuration; const bool mDXVAEnabled; const layers::LayersBackend mLayersBackend;