Bug 1257013 - Part 1: Use readback to synchronize d3d9 video. r=cpearce r=Bas, a=ritu
authorMatt Woodrow <mwoodrow@mozilla.com>
Mon, 21 Mar 2016 18:49:43 +1300
changeset 323960 714808ad8a7d61fb8500de96bc36dee12cb28f69
parent 323959 c7b83c2dddd33aba3f11294e0af9f3297a1aae94
child 323961 e040ea9522763d6cf7dbbb124336ff9c37887b40
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, Bas, ritu
bugs1257013
milestone47.0a2
Bug 1257013 - Part 1: Use readback to synchronize d3d9 video. r=cpearce r=Bas, a=ritu
dom/media/platforms/wmf/DXVA2Manager.cpp
gfx/layers/D3D9SurfaceImage.cpp
gfx/layers/D3D9SurfaceImage.h
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -61,16 +61,21 @@ static const DWORD sAMDPreUVD4[] = {
   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
 };
 
+// The size we use for our synchronization surface.
+// 16x16 is the size recommended by Microsoft (in the D3D9ExDXGISharedSurf sample) that works
+// best to avoid driver bugs.
+static const uint32_t kSyncSurfaceSize = 16;
+
 namespace mozilla {
 
 using layers::Image;
 using layers::ImageContainer;
 using layers::D3D9SurfaceImage;
 using layers::D3D9RecycleAllocator;
 using layers::D3D11ShareHandleImage;
 using layers::D3D11RecycleAllocator;
@@ -95,16 +100,17 @@ public:
   bool SupportsConfig(IMFMediaType* aType, float aFramerate) override;
 
 private:
   RefPtr<IDirect3D9Ex> mD3D9;
   RefPtr<IDirect3DDevice9Ex> mDevice;
   RefPtr<IDirect3DDeviceManager9> mDeviceManager;
   RefPtr<D3D9RecycleAllocator> mTextureClientAllocator;
   RefPtr<IDirectXVideoDecoderService> mDecoderService;
+  RefPtr<IDirect3DSurface9> mSyncSurface;
   GUID mDecoderGUID;
   UINT32 mResetToken;
   bool mFirstFrame;
   bool mIsAMDPreUVD4;
 };
 
 void GetDXVA2ExtendedFormatFromMFMediaType(IMFMediaType *pType,
                                            DXVA2_ExtendedFormat *pFormat)
@@ -387,22 +393,29 @@ D3D9DXVA2Manager::Init(nsACString& aFail
     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sAMDPreUVD4); i++) {
       if (adapter.DeviceId == sAMDPreUVD4[i]) {
         mIsAMDPreUVD4 = true;
         break;
       }
     }
   }
 
+  RefPtr<IDirect3DSurface9> syncSurf;
+  hr = device->CreateRenderTarget(kSyncSurfaceSize, kSyncSurfaceSize,
+                                  D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE,
+                                  0, TRUE, getter_AddRefs(syncSurf), NULL);
+  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+
   mDecoderService = decoderService;
 
   mResetToken = resetToken;
   mD3D9 = d3d9Ex;
   mDevice = device;
   mDeviceManager = deviceManager;
+  mSyncSurface = syncSurf;
 
   mTextureClientAllocator = new D3D9RecycleAllocator(layers::ImageBridgeChild::GetSingleton(),
                                                      mDevice);
   mTextureClientAllocator->SetMaxPoolSize(5);
 
   return S_OK;
 }
 
@@ -422,45 +435,30 @@ D3D9DXVA2Manager::CopyToImage(IMFSample*
                          IID_IDirect3DSurface9,
                          getter_AddRefs(surface));
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   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);
+  RefPtr<IDirect3DSurface9> sourceSurf = image->GetD3D9Surface();
+
+  // Copy a small rect into our sync surface, and then map it
+  // to block until decoding/color conversion completes.
+  RECT copyRect = { 0, 0, kSyncSurfaceSize, kSyncSurfaceSize };
+  hr = mDevice->StretchRect(sourceSurf, &copyRect, mSyncSurface, &copyRect, D3DTEXF_NONE);
   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;
-  }
+  D3DLOCKED_RECT lockedRect;
+  hr = mSyncSurface->LockRect(&lockedRect, NULL, D3DLOCK_READONLY);
+  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
-  mFirstFrame = false;
-
-  if (!valid) {
-    image->Invalidate();
-  }
+  hr = mSyncSurface->UnlockRect();
+  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   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
@@ -72,16 +72,23 @@ D3D9SurfaceImage::AllocateAndCopy(D3D9Re
   hr = device->StretchRect(surface, &src, textureSurface, nullptr, D3DTEXF_NONE);
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   mTextureClient = textureClient;
   mSize = aRegion.Size();
   return S_OK;
 }
 
+already_AddRefed<IDirect3DSurface9>
+D3D9SurfaceImage::GetD3D9Surface()
+{
+  return static_cast<DXGID3D9TextureData*>(
+    mTextureClient->GetInternalData())->GetD3D9Surface();
+}
+
 const D3DSURFACE_DESC&
 D3D9SurfaceImage::GetDesc() const
 {
   return static_cast<DXGID3D9TextureData*>(mTextureClient->GetInternalData())->GetDesc();
 }
 
 gfx::IntSize
 D3D9SurfaceImage::GetSize()
--- a/gfx/layers/D3D9SurfaceImage.h
+++ b/gfx/layers/D3D9SurfaceImage.h
@@ -58,16 +58,18 @@ public:
   const D3DSURFACE_DESC& GetDesc() const;
 
   gfx::IntSize GetSize() override;
 
   virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
 
   virtual TextureClient* GetTextureClient(CompositableClient* aClient) override;
 
+  already_AddRefed<IDirect3DSurface9> GetD3D9Surface();
+
   virtual bool IsValid() override { return mValid; }
 
   void Invalidate() { mValid = false; }
 
 private:
 
   gfx::IntSize mSize;
   RefPtr<TextureClient> mTextureClient;