Bug 1131638 - Discard DXVA frames that don't complete YUV->RGB conversion. r=cpearce
authorAnthony Jones <ajones@mozilla.com>
Fri, 20 Feb 2015 16:27:42 +1300
changeset 231525 78b34d0e414a24a32dcbc76996e52adcfd24d665
parent 231524 ae1bfc4588519172cc151c07b23a3eee09cb7cb9
child 231526 d08d7a1a55bae44082e7e7218338099abff07549
push id28353
push usercbook@mozilla.com
push dateTue, 03 Mar 2015 12:54:59 +0000
treeherdermozilla-central@985070813323 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1131638
milestone39.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 1131638 - Discard DXVA frames that don't complete YUV->RGB conversion. r=cpearce
dom/media/VideoFrameContainer.cpp
gfx/layers/D3D9SurfaceImage.cpp
gfx/layers/D3D9SurfaceImage.h
gfx/layers/ImageContainer.h
--- a/dom/media/VideoFrameContainer.cpp
+++ b/dom/media/VideoFrameContainer.cpp
@@ -28,16 +28,20 @@ VideoFrameContainer::VideoFrameContainer
 
 VideoFrameContainer::~VideoFrameContainer()
 {}
 
 void VideoFrameContainer::SetCurrentFrame(const gfxIntSize& aIntrinsicSize,
                                           Image* aImage,
                                           TimeStamp aTargetTime)
 {
+  if (!aImage->IsValid()) {
+    return;
+  }
+
   MutexAutoLock lock(mMutex);
 
   if (aIntrinsicSize != mIntrinsicSize) {
     mIntrinsicSize = aIntrinsicSize;
     mIntrinsicSizeChanged = true;
   }
 
   gfx::IntSize oldFrameSize = mImageContainer->GetCurrentSize();
--- a/gfx/layers/D3D9SurfaceImage.cpp
+++ b/gfx/layers/D3D9SurfaceImage.cpp
@@ -8,20 +8,26 @@
 #include "mozilla/layers/TextureD3D9.h"
 #include "mozilla/layers/CompositableClient.h"
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/gfx/Types.h"
 
 namespace mozilla {
 namespace layers {
 
+// Maximum number of ms we're willing to wait for
+// the YUV -> RGB conversion to take before marking
+// the texture as invalid.
+static const uint32_t kMaxWaitSyncMs = 5;
+
 
 D3D9SurfaceImage::D3D9SurfaceImage()
   : Image(nullptr, ImageFormat::D3D9_RGB32_TEXTURE)
   , mSize(0, 0)
+  , mIsValid(true)
 {}
 
 D3D9SurfaceImage::~D3D9SurfaceImage()
 {
   if (mTexture) {
     gfxWindowsPlatform::sD3D9SurfaceImageUsed -= mSize.width * mSize.height * 4;
   }
 }
@@ -131,56 +137,47 @@ D3D9SurfaceImage::SetData(const Data& aD
 
   // Stash the surface description for later use.
   textureSurface->GetDesc(&mDesc);
 
   RECT src = { region.x, region.y, region.x+region.width, region.y+region.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, byRef(query));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
   hr = query->Issue(D3DISSUE_END);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   mTexture = texture;
   mShareHandle = shareHandle;
   mSize = gfx::IntSize(region.width, region.height);
-  mQuery = query;
 
+  int iterations = 0;
+  while (true) {
+    HRESULT hr = query->GetData(nullptr, 0, D3DGETDATA_FLUSH);
+    if (hr == S_FALSE) {
+      Sleep(1);
+      iterations++;
+      continue;
+    }
+    if (FAILED(hr) || iterations >= kMaxWaitSyncMs) {
+      mIsValid = false;
+    }
+    break;
+  }
+  
   return S_OK;
 }
 
-void
-D3D9SurfaceImage::EnsureSynchronized()
+bool
+D3D9SurfaceImage::IsValid()
 {
-  RefPtr<IDirect3DQuery9> query = mQuery;
-  if (!query) {
-    // Not setup, or already synchronized.
-    return;
-  }
-  int iterations = 0;
-  while (iterations < 10 && S_FALSE == query->GetData(nullptr, 0, D3DGETDATA_FLUSH)) {
-    Sleep(1);
-    iterations++;
-  }
-  mQuery = nullptr;
-}
-
-HANDLE
-D3D9SurfaceImage::GetShareHandle()
-{
-  // Ensure the image has completed its synchronization,
-  // and safe to used by the caller on another device.
-  EnsureSynchronized();
-  return mShareHandle;
+  return mIsValid;
 }
 
 const D3DSURFACE_DESC&
 D3D9SurfaceImage::GetDesc() const
 {
   return mDesc;
 }
 
@@ -188,17 +185,16 @@ gfx::IntSize
 D3D9SurfaceImage::GetSize()
 {
   return mSize;
 }
 
 TextureClient*
 D3D9SurfaceImage::GetTextureClient(CompositableClient* aClient)
 {
-  EnsureSynchronized();
   if (!mTextureClient) {
     RefPtr<SharedTextureClientD3D9> textureClient =
       new SharedTextureClientD3D9(aClient->GetForwarder(),
                                   gfx::SurfaceFormat::B8G8R8X8,
                                   TextureFlags::DEFAULT);
     textureClient->InitWith(mTexture, mShareHandle, mDesc);
     mTextureClient = textureClient;
   }
@@ -211,19 +207,16 @@ D3D9SurfaceImage::GetAsSourceSurface()
   NS_ENSURE_TRUE(mTexture, 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();
-
   // 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;
   hr = mTexture->GetSurfaceLevel(0, byRef(textureSurface));
   NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
 
   RefPtr<IDirect3DDevice9> device;
   hr = mTexture->GetDevice(byRef(device));
--- a/gfx/layers/D3D9SurfaceImage.h
+++ b/gfx/layers/D3D9SurfaceImage.h
@@ -36,39 +36,31 @@ public:
 
   // Copies the surface into a sharable texture's surface, and initializes
   // the image.
   HRESULT SetData(const Data& aData);
 
   // Returns the description of the shared surface.
   const D3DSURFACE_DESC& GetDesc() const;
 
-  // Returns the HANDLE that can be used to open the image as a shared resource.
-  // If the operation to copy the original resource to the shared resource
-  // hasn't finished yet, this function blocks until the synchronization is
-  // complete.
-  HANDLE GetShareHandle();
-
   gfx::IntSize GetSize() MOZ_OVERRIDE;
 
   virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
 
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
   virtual uint8_t* GetBuffer() MOZ_OVERRIDE { return nullptr; }
 
-private:
+  virtual bool IsValid() MOZ_OVERRIDE;
 
-  // Blocks the calling thread until the copy operation started in SetData()
-  // is complete, whereupon the texture is safe to use.
-  void EnsureSynchronized();
+private:
 
   gfx::IntSize mSize;
   RefPtr<IDirect3DTexture9> mTexture;
-  RefPtr<IDirect3DQuery9> mQuery;
   RefPtr<TextureClient> mTextureClient;
   HANDLE mShareHandle;
   D3DSURFACE_DESC mDesc;
+  bool mIsValid;
 };
 
 } // namepace layers
 } // namespace mozilla
 
 #endif // GFX_D3DSURFACEIMAGE_H
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -163,16 +163,18 @@ public:
 
   int32_t GetSerial() { return mSerial; }
 
   void MarkSent() { mSent = true; }
   bool IsSentToCompositor() { return mSent; }
 
   virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() = 0;
 
+  virtual bool IsValid() { return true; }
+
   virtual GrallocImage* AsGrallocImage()
   {
     return nullptr;
   }
 
 protected:
   Image(void* aImplData, ImageFormat aFormat) :
     mImplData(aImplData),