|
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/. */ |
|
5 |
|
6 #include "SourceSurfaceD2DTarget.h" |
|
7 #include "Logging.h" |
|
8 #include "DrawTargetD2D.h" |
|
9 #include "Tools.h" |
|
10 |
|
11 #include <algorithm> |
|
12 |
|
13 namespace mozilla { |
|
14 namespace gfx { |
|
15 |
|
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 } |
|
25 |
|
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(); |
|
33 |
|
34 DrawTargetD2D::mVRAMUsageSS -= size.width * size.height * BytesPerPixel(mFormat); |
|
35 } |
|
36 } |
|
37 |
|
38 IntSize |
|
39 SourceSurfaceD2DTarget::GetSize() const |
|
40 { |
|
41 D3D10_TEXTURE2D_DESC desc; |
|
42 mTexture->GetDesc(&desc); |
|
43 |
|
44 return IntSize(desc.Width, desc.Height); |
|
45 } |
|
46 |
|
47 SurfaceFormat |
|
48 SourceSurfaceD2DTarget::GetFormat() const |
|
49 { |
|
50 return mFormat; |
|
51 } |
|
52 |
|
53 TemporaryRef<DataSourceSurface> |
|
54 SourceSurfaceD2DTarget::GetDataSurface() |
|
55 { |
|
56 RefPtr<DataSourceSurfaceD2DTarget> dataSurf = |
|
57 new DataSourceSurfaceD2DTarget(mFormat); |
|
58 |
|
59 D3D10_TEXTURE2D_DESC desc; |
|
60 mTexture->GetDesc(&desc); |
|
61 |
|
62 desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ; |
|
63 desc.Usage = D3D10_USAGE_STAGING; |
|
64 desc.BindFlags = 0; |
|
65 desc.MiscFlags = 0; |
|
66 |
|
67 HRESULT hr = Factory::GetDirect3D10Device()->CreateTexture2D(&desc, nullptr, byRef(dataSurf->mTexture)); |
|
68 |
|
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); |
|
74 |
|
75 return dataSurf; |
|
76 } |
|
77 |
|
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 } |
|
86 |
|
87 ID3D10ShaderResourceView* |
|
88 SourceSurfaceD2DTarget::GetSRView() |
|
89 { |
|
90 if (mSRView) { |
|
91 return mSRView; |
|
92 } |
|
93 |
|
94 HRESULT hr = Factory::GetDirect3D10Device()->CreateShaderResourceView(mTexture, nullptr, byRef(mSRView)); |
|
95 |
|
96 if (FAILED(hr)) { |
|
97 gfxWarning() << "Failed to create ShaderResourceView. Code: " << hr; |
|
98 } |
|
99 |
|
100 return mSRView; |
|
101 } |
|
102 |
|
103 void |
|
104 SourceSurfaceD2DTarget::DrawTargetWillChange() |
|
105 { |
|
106 RefPtr<ID3D10Texture2D> oldTexture = mTexture; |
|
107 |
|
108 D3D10_TEXTURE2D_DESC desc; |
|
109 mTexture->GetDesc(&desc); |
|
110 |
|
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; |
|
115 |
|
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); |
|
119 |
|
120 mBitmap = nullptr; |
|
121 |
|
122 DrawTargetD2D::mVRAMUsageSS += desc.Width * desc.Height * BytesPerPixel(mFormat); |
|
123 mOwnsCopy = true; |
|
124 |
|
125 // We now no longer depend on the source surface content remaining the same. |
|
126 MarkIndependent(); |
|
127 } |
|
128 |
|
129 ID2D1Bitmap* |
|
130 SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) |
|
131 { |
|
132 if (mBitmap) { |
|
133 return mBitmap; |
|
134 } |
|
135 |
|
136 HRESULT hr; |
|
137 D3D10_TEXTURE2D_DESC desc; |
|
138 mTexture->GetDesc(&desc); |
|
139 |
|
140 IntSize size(desc.Width, desc.Height); |
|
141 |
|
142 RefPtr<IDXGISurface> surf; |
|
143 hr = mTexture->QueryInterface((IDXGISurface**)byRef(surf)); |
|
144 |
|
145 if (FAILED(hr)) { |
|
146 gfxWarning() << "Failed to query interface texture to DXGISurface. Code: " << hr; |
|
147 return nullptr; |
|
148 } |
|
149 |
|
150 D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat)); |
|
151 hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); |
|
152 |
|
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)); |
|
158 |
|
159 if (FAILED(hr)) { |
|
160 gfxWarning() << "Failed in CreateBitmap. Code: " << hr; |
|
161 return nullptr; |
|
162 } |
|
163 |
|
164 RefPtr<ID2D1RenderTarget> rt; |
|
165 |
|
166 if (mDrawTarget) { |
|
167 rt = mDrawTarget->mRT; |
|
168 } |
|
169 |
|
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; |
|
175 |
|
176 hr = mTexture->QueryInterface((IDXGISurface**)byRef(surface)); |
|
177 |
|
178 if (FAILED(hr)) { |
|
179 gfxWarning() << "Failed to QI texture to surface."; |
|
180 return nullptr; |
|
181 } |
|
182 |
|
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)); |
|
186 |
|
187 if (FAILED(hr)) { |
|
188 gfxWarning() << "Failed to create D2D render target for texture."; |
|
189 return nullptr; |
|
190 } |
|
191 } |
|
192 |
|
193 mBitmap->CopyFromRenderTarget(nullptr, rt, nullptr); |
|
194 return mBitmap; |
|
195 } |
|
196 |
|
197 return mBitmap; |
|
198 } |
|
199 |
|
200 void |
|
201 SourceSurfaceD2DTarget::MarkIndependent() |
|
202 { |
|
203 if (mDrawTarget) { |
|
204 MOZ_ASSERT(mDrawTarget->mSnapshot == this); |
|
205 mDrawTarget->mSnapshot = nullptr; |
|
206 mDrawTarget = nullptr; |
|
207 } |
|
208 } |
|
209 |
|
210 DataSourceSurfaceD2DTarget::DataSourceSurfaceD2DTarget(SurfaceFormat aFormat) |
|
211 : mFormat(aFormat) |
|
212 , mMapped(false) |
|
213 { |
|
214 } |
|
215 |
|
216 DataSourceSurfaceD2DTarget::~DataSourceSurfaceD2DTarget() |
|
217 { |
|
218 if (mMapped) { |
|
219 mTexture->Unmap(0); |
|
220 } |
|
221 } |
|
222 |
|
223 IntSize |
|
224 DataSourceSurfaceD2DTarget::GetSize() const |
|
225 { |
|
226 D3D10_TEXTURE2D_DESC desc; |
|
227 mTexture->GetDesc(&desc); |
|
228 |
|
229 return IntSize(desc.Width, desc.Height); |
|
230 } |
|
231 |
|
232 SurfaceFormat |
|
233 DataSourceSurfaceD2DTarget::GetFormat() const |
|
234 { |
|
235 return mFormat; |
|
236 } |
|
237 |
|
238 uint8_t* |
|
239 DataSourceSurfaceD2DTarget::GetData() |
|
240 { |
|
241 EnsureMapped(); |
|
242 |
|
243 return (unsigned char*)mMap.pData; |
|
244 } |
|
245 |
|
246 int32_t |
|
247 DataSourceSurfaceD2DTarget::Stride() |
|
248 { |
|
249 EnsureMapped(); |
|
250 return mMap.RowPitch; |
|
251 } |
|
252 |
|
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); |
|
259 |
|
260 if (!mTexture) { |
|
261 return false; |
|
262 } |
|
263 |
|
264 D3D10_MAP mapType; |
|
265 |
|
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 } |
|
273 |
|
274 D3D10_MAPPED_TEXTURE2D map; |
|
275 |
|
276 HRESULT hr = mTexture->Map(0, mapType, 0, &map); |
|
277 |
|
278 if (FAILED(hr)) { |
|
279 gfxWarning() << "Texture map failed with code: " << hr; |
|
280 return false; |
|
281 } |
|
282 |
|
283 aMappedSurface->mData = (uint8_t*)map.pData; |
|
284 aMappedSurface->mStride = map.RowPitch; |
|
285 mIsMapped = true; |
|
286 |
|
287 return true; |
|
288 } |
|
289 |
|
290 void |
|
291 DataSourceSurfaceD2DTarget::Unmap() |
|
292 { |
|
293 MOZ_ASSERT(mIsMapped); |
|
294 |
|
295 mIsMapped = false; |
|
296 mTexture->Unmap(0); |
|
297 } |
|
298 |
|
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 } |
|
313 |
|
314 } |
|
315 } |