Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "DXVA2Manager.h"
8 #include "nsThreadUtils.h"
9 #include "ImageContainer.h"
10 #include "D3D9SurfaceImage.h"
11 #include "mozilla/Preferences.h"
13 namespace mozilla {
15 using layers::Image;
16 using layers::ImageContainer;
17 using layers::D3D9SurfaceImage;
19 class D3D9DXVA2Manager : public DXVA2Manager
20 {
21 public:
22 D3D9DXVA2Manager();
23 virtual ~D3D9DXVA2Manager();
25 HRESULT Init();
27 IUnknown* GetDXVADeviceManager() MOZ_OVERRIDE;
29 // Copies a region (aRegion) of the video frame stored in aVideoSample
30 // into an image which is returned by aOutImage.
31 HRESULT CopyToImage(IMFSample* aVideoSample,
32 const nsIntRect& aRegion,
33 ImageContainer* aContainer,
34 Image** aOutImage) MOZ_OVERRIDE;
36 private:
37 nsRefPtr<IDirect3D9Ex> mD3D9;
38 nsRefPtr<IDirect3DDevice9Ex> mDevice;
39 nsRefPtr<IDirect3DDeviceManager9> mDeviceManager;
40 UINT32 mResetToken;
41 };
43 D3D9DXVA2Manager::D3D9DXVA2Manager()
44 : mResetToken(0)
45 {
46 MOZ_COUNT_CTOR(D3D9DXVA2Manager);
47 MOZ_ASSERT(NS_IsMainThread());
48 }
50 D3D9DXVA2Manager::~D3D9DXVA2Manager()
51 {
52 MOZ_COUNT_DTOR(D3D9DXVA2Manager);
53 MOZ_ASSERT(NS_IsMainThread());
54 }
56 IUnknown*
57 D3D9DXVA2Manager::GetDXVADeviceManager()
58 {
59 MutexAutoLock lock(mLock);
60 return mDeviceManager;
61 }
63 HRESULT
64 D3D9DXVA2Manager::Init()
65 {
66 MOZ_ASSERT(NS_IsMainThread());
68 // Create D3D9Ex.
69 HMODULE d3d9lib = LoadLibraryW(L"d3d9.dll");
70 NS_ENSURE_TRUE(d3d9lib, E_FAIL);
71 decltype(Direct3DCreate9Ex)* d3d9Create =
72 (decltype(Direct3DCreate9Ex)*) GetProcAddress(d3d9lib, "Direct3DCreate9Ex");
73 nsRefPtr<IDirect3D9Ex> d3d9Ex;
74 HRESULT hr = d3d9Create(D3D_SDK_VERSION, getter_AddRefs(d3d9Ex));
75 if (!d3d9Ex) {
76 NS_WARNING("Direct3DCreate9 failed");
77 return E_FAIL;
78 }
80 // Ensure we can do the YCbCr->RGB conversion in StretchRect.
81 // Fail if we can't.
82 hr = d3d9Ex->CheckDeviceFormatConversion(D3DADAPTER_DEFAULT,
83 D3DDEVTYPE_HAL,
84 (D3DFORMAT)MAKEFOURCC('N','V','1','2'),
85 D3DFMT_X8R8G8B8);
86 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
88 // Create D3D9DeviceEx.
89 D3DPRESENT_PARAMETERS params = {0};
90 params.BackBufferWidth = 1;
91 params.BackBufferHeight = 1;
92 params.BackBufferFormat = D3DFMT_UNKNOWN;
93 params.BackBufferCount = 1;
94 params.SwapEffect = D3DSWAPEFFECT_DISCARD;
95 params.hDeviceWindow = ::GetShellWindow();
96 params.Windowed = TRUE;
97 params.Flags = D3DPRESENTFLAG_VIDEO;
99 nsRefPtr<IDirect3DDevice9Ex> device;
100 hr = d3d9Ex->CreateDeviceEx(D3DADAPTER_DEFAULT,
101 D3DDEVTYPE_HAL,
102 ::GetShellWindow(),
103 D3DCREATE_FPU_PRESERVE |
104 D3DCREATE_MULTITHREADED |
105 D3DCREATE_MIXED_VERTEXPROCESSING,
106 ¶ms,
107 nullptr,
108 getter_AddRefs(device));
109 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
111 // Ensure we can create queries to synchronize operations between devices.
112 // Without this, when we make a copy of the frame in order to share it with
113 // another device, we can't be sure that the copy has finished before the
114 // other device starts using it.
115 nsRefPtr<IDirect3DQuery9> query;
117 hr = device->CreateQuery(D3DQUERYTYPE_EVENT, getter_AddRefs(query));
118 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
120 // Create and initialize IDirect3DDeviceManager9.
121 UINT resetToken = 0;
122 nsRefPtr<IDirect3DDeviceManager9> deviceManager;
124 hr = wmf::DXVA2CreateDirect3DDeviceManager9(&resetToken,
125 getter_AddRefs(deviceManager));
126 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
127 hr = deviceManager->ResetDevice(device, resetToken);
128 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
130 mResetToken = resetToken;
131 mD3D9 = d3d9Ex;
132 mDevice = device;
133 mDeviceManager = deviceManager;
135 return S_OK;
136 }
138 HRESULT
139 D3D9DXVA2Manager::CopyToImage(IMFSample* aSample,
140 const nsIntRect& aRegion,
141 ImageContainer* aImageContainer,
142 Image** aOutImage)
143 {
144 nsRefPtr<IMFMediaBuffer> buffer;
145 HRESULT hr = aSample->GetBufferByIndex(0, getter_AddRefs(buffer));
146 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
148 nsRefPtr<IDirect3DSurface9> surface;
149 hr = wmf::MFGetService(buffer,
150 MR_BUFFER_SERVICE,
151 IID_IDirect3DSurface9,
152 getter_AddRefs(surface));
153 NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
155 nsRefPtr<Image> image = aImageContainer->CreateImage(ImageFormat::D3D9_RGB32_TEXTURE);
156 NS_ENSURE_TRUE(image, E_FAIL);
157 NS_ASSERTION(image->GetFormat() == ImageFormat::D3D9_RGB32_TEXTURE,
158 "Wrong format?");
160 D3D9SurfaceImage* videoImage = static_cast<D3D9SurfaceImage*>(image.get());
161 hr = videoImage->SetData(D3D9SurfaceImage::Data(surface, aRegion));
163 image.forget(aOutImage);
165 return S_OK;
166 }
168 // Count of the number of DXVAManager's we've created. This is also the
169 // number of videos we're decoding with DXVA. Use on main thread only.
170 static uint32_t sDXVAVideosCount = 0;
172 /* static */
173 DXVA2Manager*
174 DXVA2Manager::Create()
175 {
176 MOZ_ASSERT(NS_IsMainThread());
177 HRESULT hr;
179 // DXVA processing takes up a lot of GPU resources, so limit the number of
180 // videos we use DXVA with at any one time.
181 const uint32_t dxvaLimit =
182 Preferences::GetInt("media.windows-media-foundation.max-dxva-videos", 8);
183 if (sDXVAVideosCount == dxvaLimit) {
184 return nullptr;
185 }
187 nsAutoPtr<D3D9DXVA2Manager> d3d9Manager(new D3D9DXVA2Manager());
188 hr = d3d9Manager->Init();
189 if (SUCCEEDED(hr)) {
190 return d3d9Manager.forget();
191 }
193 // No hardware accelerated video decoding. :(
194 return nullptr;
195 }
197 DXVA2Manager::DXVA2Manager()
198 : mLock("DXVA2Manager")
199 {
200 MOZ_ASSERT(NS_IsMainThread());
201 ++sDXVAVideosCount;
202 }
204 DXVA2Manager::~DXVA2Manager()
205 {
206 MOZ_ASSERT(NS_IsMainThread());
207 --sDXVAVideosCount;
208 }
210 } // namespace mozilla