diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index fca385fcc2bf..a25793006785 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -66,6 +66,11 @@ static const DWORD sAMDPreUVD4[] = { 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; @@ -100,6 +105,7 @@ private: RefPtr mDeviceManager; RefPtr mTextureClientAllocator; RefPtr mDecoderService; + RefPtr mSyncSurface; GUID mDecoderGUID; UINT32 mResetToken; bool mFirstFrame; @@ -392,12 +398,19 @@ D3D9DXVA2Manager::Init(nsACString& aFailureReason) } } + RefPtr 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); @@ -427,35 +440,20 @@ D3D9DXVA2Manager::CopyToImage(IMFSample* aSample, 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 query; - hr = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, getter_AddRefs(query)); - NS_ENSURE_TRUE(SUCCEEDED(hr), hr); - hr = query->Issue(D3DISSUE_END); + RefPtr 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, ©Rect, mSyncSurface, ©Rect, 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; diff --git a/gfx/layers/D3D9SurfaceImage.cpp b/gfx/layers/D3D9SurfaceImage.cpp index a83725133442..49e31ee9b811 100644 --- a/gfx/layers/D3D9SurfaceImage.cpp +++ b/gfx/layers/D3D9SurfaceImage.cpp @@ -77,6 +77,13 @@ D3D9SurfaceImage::AllocateAndCopy(D3D9RecycleAllocator* aAllocator, return S_OK; } +already_AddRefed +D3D9SurfaceImage::GetD3D9Surface() +{ + return static_cast( + mTextureClient->GetInternalData())->GetD3D9Surface(); +} + const D3DSURFACE_DESC& D3D9SurfaceImage::GetDesc() const { diff --git a/gfx/layers/D3D9SurfaceImage.h b/gfx/layers/D3D9SurfaceImage.h index 9ea39045f7f0..f861bc0a2823 100644 --- a/gfx/layers/D3D9SurfaceImage.h +++ b/gfx/layers/D3D9SurfaceImage.h @@ -63,6 +63,8 @@ public: virtual TextureClient* GetTextureClient(CompositableClient* aClient) override; + already_AddRefed GetD3D9Surface(); + virtual bool IsValid() override { return mValid; } void Invalidate() { mValid = false; }