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 "SourceSurfaceD2D.h"
7 #include "DrawTargetD2D.h"
8 #include "Logging.h"
9 #include "Tools.h"
11 namespace mozilla {
12 namespace gfx {
14 SourceSurfaceD2D::SourceSurfaceD2D()
15 {
16 }
18 SourceSurfaceD2D::~SourceSurfaceD2D()
19 {
20 if (mBitmap) {
21 DrawTargetD2D::mVRAMUsageSS -= GetByteSize();
22 }
23 }
25 IntSize
26 SourceSurfaceD2D::GetSize() const
27 {
28 return mSize;
29 }
31 SurfaceFormat
32 SourceSurfaceD2D::GetFormat() const
33 {
34 return mFormat;
35 }
37 bool
38 SourceSurfaceD2D::IsValid() const
39 {
40 return mDevice == Factory::GetDirect3D10Device();
41 }
43 TemporaryRef<DataSourceSurface>
44 SourceSurfaceD2D::GetDataSurface()
45 {
46 RefPtr<DataSourceSurfaceD2D> result = new DataSourceSurfaceD2D(this);
47 if (result->IsValid()) {
48 return result;
49 }
50 return nullptr;
51 }
53 bool
54 SourceSurfaceD2D::InitFromData(unsigned char *aData,
55 const IntSize &aSize,
56 int32_t aStride,
57 SurfaceFormat aFormat,
58 ID2D1RenderTarget *aRT)
59 {
60 HRESULT hr;
62 mFormat = aFormat;
63 mSize = aSize;
65 if ((uint32_t)aSize.width > aRT->GetMaximumBitmapSize() ||
66 (uint32_t)aSize.height > aRT->GetMaximumBitmapSize()) {
67 gfxDebug() << "Bitmap does not fit in texture.";
68 return false;
69 }
71 D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat));
72 hr = aRT->CreateBitmap(D2DIntSize(aSize), aData, aStride, props, byRef(mBitmap));
74 if (FAILED(hr)) {
75 gfxWarning() << "Failed to create D2D Bitmap for data. Code: " << hr;
76 return false;
77 }
79 DrawTargetD2D::mVRAMUsageSS += GetByteSize();
80 mDevice = Factory::GetDirect3D10Device();
82 return true;
83 }
85 bool
86 SourceSurfaceD2D::InitFromTexture(ID3D10Texture2D *aTexture,
87 SurfaceFormat aFormat,
88 ID2D1RenderTarget *aRT)
89 {
90 HRESULT hr;
92 RefPtr<IDXGISurface> surf;
94 hr = aTexture->QueryInterface((IDXGISurface**)&surf);
96 if (FAILED(hr)) {
97 gfxWarning() << "Failed to QI texture to surface. Code: " << hr;
98 return false;
99 }
101 D3D10_TEXTURE2D_DESC desc;
102 aTexture->GetDesc(&desc);
104 mSize = IntSize(desc.Width, desc.Height);
105 mFormat = aFormat;
107 D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat));
108 hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap));
110 if (FAILED(hr)) {
111 gfxWarning() << "Failed to create SharedBitmap. Code: " << hr;
112 return false;
113 }
115 aTexture->GetDevice(byRef(mDevice));
116 DrawTargetD2D::mVRAMUsageSS += GetByteSize();
118 return true;
119 }
121 uint32_t
122 SourceSurfaceD2D::GetByteSize() const
123 {
124 return mSize.width * mSize.height * BytesPerPixel(mFormat);
125 }
127 DataSourceSurfaceD2D::DataSourceSurfaceD2D(SourceSurfaceD2D* aSourceSurface)
128 : mTexture(nullptr)
129 , mFormat(aSourceSurface->mFormat)
130 , mSize(aSourceSurface->mSize)
131 , mMapped(false)
132 {
133 // We allocate ourselves a regular D3D surface (sourceTexture) and paint the
134 // D2D bitmap into it via a DXGI render target. Then we need to copy
135 // sourceTexture into a staging texture (mTexture), which we will lazily map
136 // to get the data.
138 CD3D10_TEXTURE2D_DESC desc(DXGIFormat(mFormat), mSize.width, mSize.height);
139 desc.MipLevels = 1;
140 desc.Usage = D3D10_USAGE_DEFAULT;
141 desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
142 RefPtr<ID3D10Texture2D> sourceTexture;
143 HRESULT hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr,
144 byRef(sourceTexture));
145 if (FAILED(hr)) {
146 gfxWarning() << "Failed to create texture. Code: " << hr;
147 return;
148 }
150 RefPtr<IDXGISurface> dxgiSurface;
151 hr = sourceTexture->QueryInterface((IDXGISurface**)byRef(dxgiSurface));
152 if (FAILED(hr)) {
153 gfxWarning() << "Failed to create DXGI surface. Code: " << hr;
154 return;
155 }
157 D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties(
158 D2D1_RENDER_TARGET_TYPE_DEFAULT,
159 D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
161 RefPtr<ID2D1RenderTarget> renderTarget;
162 hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(dxgiSurface,
163 &rtProps,
164 byRef(renderTarget));
165 if (FAILED(hr)) {
166 gfxWarning() << "Failed to create render target. Code: " << hr;
167 return;
168 }
170 renderTarget->BeginDraw();
171 renderTarget->Clear(D2D1::ColorF(0, 0.0f));
172 renderTarget->DrawBitmap(aSourceSurface->mBitmap,
173 D2D1::RectF(0, 0,
174 Float(mSize.width),
175 Float(mSize.height)));
176 hr = renderTarget->EndDraw();
177 if (FAILED(hr)) {
178 gfxWarning() << "Failed to draw bitmap. Code: " << hr;
179 return;
180 }
182 desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE;
183 desc.Usage = D3D10_USAGE_STAGING;
184 desc.BindFlags = 0;
185 hr = aSourceSurface->mDevice->CreateTexture2D(&desc, nullptr, byRef(mTexture));
186 if (FAILED(hr)) {
187 gfxWarning() << "Failed to create staging texture. Code: " << hr;
188 mTexture = nullptr;
189 return;
190 }
192 aSourceSurface->mDevice->CopyResource(mTexture, sourceTexture);
193 }
195 DataSourceSurfaceD2D::~DataSourceSurfaceD2D()
196 {
197 if (mMapped) {
198 mTexture->Unmap(0);
199 }
200 }
202 unsigned char*
203 DataSourceSurfaceD2D::GetData()
204 {
205 EnsureMappedTexture();
206 if (!mMapped) {
207 return nullptr;
208 }
210 return reinterpret_cast<unsigned char*>(mData.pData);
211 }
213 int32_t
214 DataSourceSurfaceD2D::Stride()
215 {
216 EnsureMappedTexture();
217 if (!mMapped) {
218 return 0;
219 }
221 return mData.RowPitch;
222 }
224 IntSize
225 DataSourceSurfaceD2D::GetSize() const
226 {
227 return mSize;
228 }
230 SurfaceFormat
231 DataSourceSurfaceD2D::GetFormat() const
232 {
233 return mFormat;
234 }
236 bool
237 DataSourceSurfaceD2D::Map(MapType aMapType, MappedSurface *aMappedSurface)
238 {
239 // DataSourceSurfaces used with the new Map API should not be used with GetData!!
240 MOZ_ASSERT(!mMapped);
241 MOZ_ASSERT(!mIsMapped);
243 if (!mTexture) {
244 return false;
245 }
247 D3D10_MAP mapType;
249 if (aMapType == MapType::READ) {
250 mapType = D3D10_MAP_READ;
251 } else if (aMapType == MapType::WRITE) {
252 mapType = D3D10_MAP_WRITE;
253 } else {
254 mapType = D3D10_MAP_READ_WRITE;
255 }
257 D3D10_MAPPED_TEXTURE2D map;
259 HRESULT hr = mTexture->Map(0, mapType, 0, &map);
261 if (FAILED(hr)) {
262 gfxWarning() << "Texture map failed with code: " << hr;
263 return false;
264 }
266 aMappedSurface->mData = (uint8_t*)map.pData;
267 aMappedSurface->mStride = map.RowPitch;
268 mIsMapped = true;
270 return true;
271 }
273 void
274 DataSourceSurfaceD2D::Unmap()
275 {
276 MOZ_ASSERT(mIsMapped);
278 mIsMapped = false;
279 mTexture->Unmap(0);
280 }
282 void
283 DataSourceSurfaceD2D::EnsureMappedTexture()
284 {
285 // Do not use GetData() after having used Map!
286 MOZ_ASSERT(!mIsMapped);
288 if (mMapped ||
289 !mTexture) {
290 return;
291 }
293 HRESULT hr = mTexture->Map(0, D3D10_MAP_READ, 0, &mData);
294 if (FAILED(hr)) {
295 gfxWarning() << "Failed to map texture. Code: " << hr;
296 mTexture = nullptr;
297 } else {
298 mMapped = true;
299 }
300 }
302 }
303 }