Bug 1236112 - Block on d3d9 video frames to complete before returning them from the decoder. r=cpearce
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 09 Mar 2016 10:34:49 +1300
changeset 328621 6d8001b49fea6e73ddc1d3b7940840c21515b5cf
parent 328620 7d6fb17b4b32f8df992700f2ee643bee59305197
child 328622 7d9d6c06bf9ed5ebb30815c15306069d6fecf11a
push id1146
push userCallek@gmail.com
push dateMon, 25 Jul 2016 16:35:44 +0000
treeherdermozilla-release@a55778f9cd5a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1236112
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1236112 - Block on d3d9 video frames to complete before returning them from the decoder. r=cpearce
dom/media/MediaDecoderStateMachine.cpp
dom/media/platforms/wmf/DXVA2Manager.cpp
gfx/layers/D3D9SurfaceImage.cpp
gfx/layers/D3D9SurfaceImage.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -43,16 +43,17 @@
 #include "MediaDecoder.h"
 #include "MediaDecoderReader.h"
 #include "MediaDecoderStateMachine.h"
 #include "MediaShutdownManager.h"
 #include "MediaTimer.h"
 #include "TimeUnits.h"
 #include "VideoSegment.h"
 #include "VideoUtils.h"
+#include "gfxPrefs.h"
 
 namespace mozilla {
 
 using namespace mozilla::dom;
 using namespace mozilla::layers;
 using namespace mozilla::media;
 
 #define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead
@@ -2419,17 +2420,17 @@ MediaDecoderStateMachine::Reset()
 }
 
 void
 MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Update corrupt-frames statistics
-  if (aData->mImage && !aData->mImage->IsValid()) {
+  if (aData->mImage && !aData->mImage->IsValid() && !gfxPrefs::HardwareVideoDecodingForceEnabled()) {
     FrameStatistics& frameStats = *mFrameStats;
     frameStats.NotifyCorruptFrame();
     // If more than 10% of the last 30 frames have been corrupted, then try disabling
     // hardware acceleration. We use 10 as the corrupt value because RollingMean<>
     // only supports integer types.
     mCorruptFrames.insert(10);
     if (mReader->VideoIsHardwareAccelerated() &&
         frameStats.GetPresentedFrames() > 60 &&
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -418,22 +418,50 @@ D3D9DXVA2Manager::CopyToImage(IMFSample*
 
   RefPtr<IDirect3DSurface9> surface;
   hr = wmf::MFGetService(buffer,
                          MR_BUFFER_SERVICE,
                          IID_IDirect3DSurface9,
                          getter_AddRefs(surface));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
-  RefPtr<D3D9SurfaceImage> image = new D3D9SurfaceImage(mFirstFrame);
+  RefPtr<D3D9SurfaceImage> image = new D3D9SurfaceImage();
   hr = image->AllocateAndCopy(mTextureClientAllocator, surface, aRegion);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
+  // Flush the draw command now, so that by the time we come to draw this
+  // image, we're less likely to need to wait for the draw operation to
+  // complete.
+  RefPtr<IDirect3DQuery9> query;
+  hr = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, getter_AddRefs(query));
+  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+  hr = query->Issue(D3DISSUE_END);
+  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+
+  bool valid = false;
+  int iterations = 0;
+  while (iterations < (mFirstFrame ? 100 : 10)) {
+    hr = query->GetData(nullptr, 0, D3DGETDATA_FLUSH);
+    if (hr == S_FALSE) {
+      Sleep(1);
+      iterations++;
+      continue;
+    }
+    if (hr == S_OK) {
+      valid = true;
+    }
+    break;
+  }
+
   mFirstFrame = false;
 
+  if (!valid) {
+    image->Invalidate();
+  }
+
   image.forget(aOutImage);
   return S_OK;
 }
 
 // Count of the number of DXVAManager's we've created. This is also the
 // number of videos we're decoding with DXVA. Use on main thread only.
 static uint32_t sDXVAVideosCount = 0;
 
--- a/gfx/layers/D3D9SurfaceImage.cpp
+++ b/gfx/layers/D3D9SurfaceImage.cpp
@@ -10,21 +10,20 @@
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/gfx/Types.h"
 
 namespace mozilla {
 namespace layers {
 
 
-D3D9SurfaceImage::D3D9SurfaceImage(bool aIsFirstFrame)
+D3D9SurfaceImage::D3D9SurfaceImage()
   : Image(nullptr, ImageFormat::D3D9_RGB32_TEXTURE)
   , mSize(0, 0)
-  , mValid(false)
-  , mIsFirstFrame(aIsFirstFrame)
+  , mValid(true)
 {}
 
 D3D9SurfaceImage::~D3D9SurfaceImage()
 {
 }
 
 HRESULT
 D3D9SurfaceImage::AllocateAndCopy(D3D9RecycleAllocator* aAllocator,
@@ -68,62 +67,21 @@ D3D9SurfaceImage::AllocateAndCopy(D3D9Re
   if (!textureSurface) {
     return E_FAIL;
   }
 
   RECT src = { aRegion.x, aRegion.y, aRegion.x+aRegion.width, aRegion.y+aRegion.height };
   hr = device->StretchRect(surface, &src, textureSurface, nullptr, D3DTEXF_NONE);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
-  // Flush the draw command now, so that by the time we come to draw this
-  // image, we're less likely to need to wait for the draw operation to
-  // complete.
-  RefPtr<IDirect3DQuery9> query;
-  hr = device->CreateQuery(D3DQUERYTYPE_EVENT, getter_AddRefs(query));
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-  hr = query->Issue(D3DISSUE_END);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-
   mTextureClient = textureClient;
   mSize = aRegion.Size();
-  mQuery = query;
   return S_OK;
 }
 
-bool
-D3D9SurfaceImage::IsValid()
-{
-  EnsureSynchronized();
-  return mValid;
-}
-
-void
-D3D9SurfaceImage::EnsureSynchronized()
-{
-  RefPtr<IDirect3DQuery9> query = mQuery;
-  if (!query) {
-    // Not setup, or already synchronized.
-    return;
-  }
-  int iterations = 0;
-  while (iterations < (mIsFirstFrame ? 100 : 10)) {
-    HRESULT hr = query->GetData(nullptr, 0, D3DGETDATA_FLUSH);
-    if (hr == S_FALSE) {
-      Sleep(1);
-      iterations++;
-      continue;
-    }
-    if (hr == S_OK) {
-      mValid = true;
-    }
-    break;
-  }
-  mQuery = nullptr;
-}
-
 const D3DSURFACE_DESC&
 D3D9SurfaceImage::GetDesc() const
 {
   return static_cast<DXGID3D9TextureData*>(mTextureClient->GetInternalData())->GetDesc();
 }
 
 gfx::IntSize
 D3D9SurfaceImage::GetSize()
@@ -131,36 +89,32 @@ D3D9SurfaceImage::GetSize()
   return mSize;
 }
 
 TextureClient*
 D3D9SurfaceImage::GetTextureClient(CompositableClient* aClient)
 {
   MOZ_ASSERT(mTextureClient);
   MOZ_ASSERT(mTextureClient->GetAllocator() == aClient->GetForwarder());
-  EnsureSynchronized();
   return mTextureClient;
 }
 
 already_AddRefed<gfx::SourceSurface>
 D3D9SurfaceImage::GetAsSourceSurface()
 {
   if (!mTextureClient) {
     return nullptr;
   }
 
   HRESULT hr;
   RefPtr<gfx::DataSourceSurface> surface = gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8X8);
   if (NS_WARN_IF(!surface)) {
     return nullptr;
   }
 
-  // Ensure that the texture is ready to be used.
-  EnsureSynchronized();
-
   DXGID3D9TextureData* texData = static_cast<DXGID3D9TextureData*>(mTextureClient->GetInternalData());
   // Readback the texture from GPU memory into system memory, so that
   // we can copy it into the Cairo image. This is expensive.
   RefPtr<IDirect3DSurface9> textureSurface = texData->GetD3D9Surface();
   if (!textureSurface) {
     return nullptr;
   }
 
--- a/gfx/layers/D3D9SurfaceImage.h
+++ b/gfx/layers/D3D9SurfaceImage.h
@@ -42,43 +42,39 @@ protected:
 };
 
 // Image class that wraps a IDirect3DSurface9. This class copies the image
 // passed into SetData(), so that it can be accessed from other D3D devices.
 // This class also manages the synchronization of the copy, to ensure the
 // resource is ready to use.
 class D3D9SurfaceImage : public Image {
 public:
-  explicit D3D9SurfaceImage(bool aIsFirstFrame);
+  explicit D3D9SurfaceImage();
   virtual ~D3D9SurfaceImage();
 
   HRESULT AllocateAndCopy(D3D9RecycleAllocator* aAllocator,
                           IDirect3DSurface9* aSurface,
                           const gfx::IntRect& aRegion);
 
   // Returns the description of the shared surface.
   const D3DSURFACE_DESC& GetDesc() const;
 
   gfx::IntSize GetSize() override;
 
   virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
 
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) override;
 
-  virtual bool IsValid() override;
+  virtual bool IsValid() override { return mValid; }
+
+  void Invalidate() { mValid = false; }
 
 private:
 
-  // Blocks the calling thread until the copy operation started in SetData()
-  // is complete, whereupon the texture is safe to use.
-  void EnsureSynchronized();
-
   gfx::IntSize mSize;
-  RefPtr<IDirect3DQuery9> mQuery;
   RefPtr<TextureClient> mTextureClient;
   bool mValid;
-  bool mIsFirstFrame;
 };
 
 } // namepace layers
 } // namespace mozilla
 
 #endif // GFX_D3DSURFACEIMAGE_H