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: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "SourceSurfaceD2DTarget.h"
7 #include "Logging.h"
8 #include "DrawTargetD2D.h"
9 #include "Tools.h"
11 #include <algorithm>
13 namespace mozilla {
14 namespace gfx {
16 SourceSurfaceD2DTarget::SourceSurfaceD2DTarget(DrawTargetD2D* aDrawTarget,
17 ID3D10Texture2D* aTexture,
18 SurfaceFormat aFormat)
19 : mDrawTarget(aDrawTarget)
20 , mTexture(aTexture)
21 , mFormat(aFormat)
22 , mOwnsCopy(false)
23 {
24 }
26 SourceSurfaceD2DTarget::~SourceSurfaceD2DTarget()
27 {
28 // We don't need to do anything special here to notify our mDrawTarget. It must
29 // already have cleared its mSnapshot field, otherwise this object would
30 // be kept alive.
31 if (mOwnsCopy) {
32 IntSize size = GetSize();
34 DrawTargetD2D::mVRAMUsageSS -= size.width * size.height * BytesPerPixel(mFormat);
35 }
36 }
38 IntSize
39 SourceSurfaceD2DTarget::GetSize() const
40 {
41 D3D10_TEXTURE2D_DESC desc;
42 mTexture->GetDesc(&desc);
44 return IntSize(desc.Width, desc.Height);
45 }
47 SurfaceFormat
48 SourceSurfaceD2DTarget::GetFormat() const
49 {
50 return mFormat;
51 }
53 TemporaryRef<DataSourceSurface>
54 SourceSurfaceD2DTarget::GetDataSurface()
55 {
56 RefPtr<DataSourceSurfaceD2DTarget> dataSurf =
57 new DataSourceSurfaceD2DTarget(mFormat);
59 D3D10_TEXTURE2D_DESC desc;
60 mTexture->GetDesc(&desc);
62 desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
63 desc.Usage = D3D10_USAGE_STAGING;
64 desc.BindFlags = 0;
65 desc.MiscFlags = 0;
67 HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture));
69 if (FAILED(hr)) {
70 gfxDebug() << "Failed to create staging texture for SourceSurface. Code: " << hr;
71 return nullptr;
72 }
73 Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture);
75 return dataSurf;
76 }
78 void*
79 SourceSurfaceD2DTarget::GetNativeSurface(NativeSurfaceType aType)
80 {
81 if (aType == NativeSurfaceType::D3D10_TEXTURE) {
82 return static_cast<void*>(mTexture.get());
83 }
84 return nullptr;
85 }
87 ID3D10ShaderResourceView*
88 SourceSurfaceD2DTarget::GetSRView()
89 {
90 if (mSRView) {
91 return mSRView;
92 }
94 HRESULT hr = Factory::GetDirect3D10Device()->CreateShaderResourceView(mTexture, nullptr, byRef(mSRView));
96 if (FAILED(hr)) {
97 gfxWarning() << "Failed to create ShaderResourceView. Code: " << hr;
98 }
100 return mSRView;
101 }
103 void
104 SourceSurfaceD2DTarget::DrawTargetWillChange()
105 {
106 RefPtr<ID3D10Texture2D> oldTexture = mTexture;
108 D3D10_TEXTURE2D_DESC desc;
109 mTexture->GetDesc(&desc);
111 // Our original texture might implement the keyed mutex flag. We shouldn't
112 // need that here. We actually specifically don't want it since we don't lock
113 // our texture for usage!
114 desc.MiscFlags = 0;
116 // Get a copy of the surface data so the content at snapshot time was saved.
117 Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(mTexture));
118 Factory::GetDirect3D10Device()->CopyResource(mTexture, oldTexture);
120 mBitmap = nullptr;
122 DrawTargetD2D::mVRAMUsageSS += desc.Width * desc.Height * BytesPerPixel(mFormat);
123 mOwnsCopy = true;
125 // We now no longer depend on the source surface content remaining the same.
126 MarkIndependent();
127 }
129 ID2D1Bitmap*
130 SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT)
131 {
132 if (mBitmap) {
133 return mBitmap;
134 }
136 HRESULT hr;
137 D3D10_TEXTURE2D_DESC desc;
138 mTexture->GetDesc(&desc);
140 IntSize size(desc.Width, desc.Height);
142 RefPtr<IDXGISurface> surf;
143 hr = mTexture->QueryInterface((IDXGISurface**)byRef(surf));
145 if (FAILED(hr)) {
146 gfxWarning() << "Failed to query interface texture to DXGISurface. Code: " << hr;
147 return nullptr;
148 }
150 D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat));
151 hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap));
153 if (FAILED(hr)) {
154 // This seems to happen for SurfaceFormat::A8 sometimes...
155 hr = aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height),
156 D2D1::BitmapProperties(D2DPixelFormat(mFormat)),
157 byRef(mBitmap));
159 if (FAILED(hr)) {
160 gfxWarning() << "Failed in CreateBitmap. Code: " << hr;
161 return nullptr;
162 }
164 RefPtr<ID2D1RenderTarget> rt;
166 if (mDrawTarget) {
167 rt = mDrawTarget->mRT;
168 }
170 if (!rt) {
171 // Okay, we already separated from our drawtarget. And we're an A8
172 // surface the only way we can get to a bitmap is by creating a
173 // a rendertarget and from there copying to a bitmap! Terrible!
174 RefPtr<IDXGISurface> surface;
176 hr = mTexture->QueryInterface((IDXGISurface**)byRef(surface));
178 if (FAILED(hr)) {
179 gfxWarning() << "Failed to QI texture to surface.";
180 return nullptr;
181 }
183 D2D1_RENDER_TARGET_PROPERTIES props =
184 D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2DPixelFormat(mFormat));
185 hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt));
187 if (FAILED(hr)) {
188 gfxWarning() << "Failed to create D2D render target for texture.";
189 return nullptr;
190 }
191 }
193 mBitmap->CopyFromRenderTarget(nullptr, rt, nullptr);
194 return mBitmap;
195 }
197 return mBitmap;
198 }
200 void
201 SourceSurfaceD2DTarget::MarkIndependent()
202 {
203 if (mDrawTarget) {
204 MOZ_ASSERT(mDrawTarget->mSnapshot == this);
205 mDrawTarget->mSnapshot = nullptr;
206 mDrawTarget = nullptr;
207 }
208 }
210 DataSourceSurfaceD2DTarget::DataSourceSurfaceD2DTarget(SurfaceFormat aFormat)
211 : mFormat(aFormat)
212 , mMapped(false)
213 {
214 }
216 DataSourceSurfaceD2DTarget::~DataSourceSurfaceD2DTarget()
217 {
218 if (mMapped) {
219 mTexture->Unmap(0);
220 }
221 }
223 IntSize
224 DataSourceSurfaceD2DTarget::GetSize() const
225 {
226 D3D10_TEXTURE2D_DESC desc;
227 mTexture->GetDesc(&desc);
229 return IntSize(desc.Width, desc.Height);
230 }
232 SurfaceFormat
233 DataSourceSurfaceD2DTarget::GetFormat() const
234 {
235 return mFormat;
236 }
238 uint8_t*
239 DataSourceSurfaceD2DTarget::GetData()
240 {
241 EnsureMapped();
243 return (unsigned char*)mMap.pData;
244 }
246 int32_t
247 DataSourceSurfaceD2DTarget::Stride()
248 {
249 EnsureMapped();
250 return mMap.RowPitch;
251 }
253 bool
254 DataSourceSurfaceD2DTarget::Map(MapType aMapType, MappedSurface *aMappedSurface)
255 {
256 // DataSourceSurfaces used with the new Map API should not be used with GetData!!
257 MOZ_ASSERT(!mMapped);
258 MOZ_ASSERT(!mIsMapped);
260 if (!mTexture) {
261 return false;
262 }
264 D3D10_MAP mapType;
266 if (aMapType == MapType::READ) {
267 mapType = D3D10_MAP_READ;
268 } else if (aMapType == MapType::WRITE) {
269 mapType = D3D10_MAP_WRITE;
270 } else {
271 mapType = D3D10_MAP_READ_WRITE;
272 }
274 D3D10_MAPPED_TEXTURE2D map;
276 HRESULT hr = mTexture->Map(0, mapType, 0, &map);
278 if (FAILED(hr)) {
279 gfxWarning() << "Texture map failed with code: " << hr;
280 return false;
281 }
283 aMappedSurface->mData = (uint8_t*)map.pData;
284 aMappedSurface->mStride = map.RowPitch;
285 mIsMapped = true;
287 return true;
288 }
290 void
291 DataSourceSurfaceD2DTarget::Unmap()
292 {
293 MOZ_ASSERT(mIsMapped);
295 mIsMapped = false;
296 mTexture->Unmap(0);
297 }
299 void
300 DataSourceSurfaceD2DTarget::EnsureMapped()
301 {
302 // Do not use GetData() after having used Map!
303 MOZ_ASSERT(!mIsMapped);
304 if (!mMapped) {
305 HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mMap);
306 if (FAILED(hr)) {
307 gfxWarning() << "Failed to map texture to memory. Code: " << hr;
308 return;
309 }
310 mMapped = true;
311 }
312 }
314 }
315 }