|
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
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 "LayerManagerD3D9.h" |
|
7 |
|
8 #include "ThebesLayerD3D9.h" |
|
9 #include "ContainerLayerD3D9.h" |
|
10 #include "ImageLayerD3D9.h" |
|
11 #include "ColorLayerD3D9.h" |
|
12 #include "CanvasLayerD3D9.h" |
|
13 #include "ReadbackLayerD3D9.h" |
|
14 #include "gfxWindowsPlatform.h" |
|
15 #include "nsIGfxInfo.h" |
|
16 #include "nsServiceManagerUtils.h" |
|
17 #include "gfxFailure.h" |
|
18 #include "gfxPrefs.h" |
|
19 |
|
20 #include "gfxCrashReporterUtils.h" |
|
21 |
|
22 namespace mozilla { |
|
23 namespace layers { |
|
24 |
|
25 LayerManagerD3D9::LayerManagerD3D9(nsIWidget *aWidget) |
|
26 : mWidget(aWidget) |
|
27 , mDeviceResetCount(0) |
|
28 { |
|
29 mCurrentCallbackInfo.Callback = nullptr; |
|
30 mCurrentCallbackInfo.CallbackData = nullptr; |
|
31 } |
|
32 |
|
33 LayerManagerD3D9::~LayerManagerD3D9() |
|
34 { |
|
35 Destroy(); |
|
36 } |
|
37 |
|
38 bool |
|
39 LayerManagerD3D9::Initialize(bool force) |
|
40 { |
|
41 ScopedGfxFeatureReporter reporter("D3D9 Layers", force); |
|
42 |
|
43 /* XXX: this preference and blacklist code should move out of the layer manager */ |
|
44 bool forceAccelerate = gfxPrefs::LayersAccelerationForceEnabled(); |
|
45 |
|
46 nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); |
|
47 if (gfxInfo) { |
|
48 int32_t status; |
|
49 if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) { |
|
50 if (status != nsIGfxInfo::FEATURE_NO_INFO && !forceAccelerate) |
|
51 { |
|
52 NS_WARNING("Direct3D 9-accelerated layers are not supported on this system."); |
|
53 return false; |
|
54 } |
|
55 } |
|
56 } |
|
57 |
|
58 mDeviceManager = gfxWindowsPlatform::GetPlatform()->GetD3D9DeviceManager(); |
|
59 if (!mDeviceManager) { |
|
60 return false; |
|
61 } |
|
62 |
|
63 mSwapChain = mDeviceManager-> |
|
64 CreateSwapChain((HWND)mWidget->GetNativeData(NS_NATIVE_WINDOW)); |
|
65 |
|
66 if (!mSwapChain) { |
|
67 return false; |
|
68 } |
|
69 |
|
70 reporter.SetSuccessful(); |
|
71 return true; |
|
72 } |
|
73 |
|
74 void |
|
75 LayerManagerD3D9::SetClippingRegion(const nsIntRegion &aClippingRegion) |
|
76 { |
|
77 mClippingRegion = aClippingRegion; |
|
78 } |
|
79 |
|
80 void |
|
81 LayerManagerD3D9::Destroy() |
|
82 { |
|
83 if (!IsDestroyed()) { |
|
84 if (mRoot) { |
|
85 static_cast<LayerD3D9*>(mRoot->ImplData())->LayerManagerDestroyed(); |
|
86 } |
|
87 /* Important to release this first since it also holds a reference to the |
|
88 * device manager |
|
89 */ |
|
90 mSwapChain = nullptr; |
|
91 mDeviceManager = nullptr; |
|
92 } |
|
93 LayerManager::Destroy(); |
|
94 } |
|
95 |
|
96 void |
|
97 LayerManagerD3D9::BeginTransaction() |
|
98 { |
|
99 mInTransaction = true; |
|
100 } |
|
101 |
|
102 void |
|
103 LayerManagerD3D9::BeginTransactionWithTarget(gfxContext *aTarget) |
|
104 { |
|
105 mInTransaction = true; |
|
106 mTarget = aTarget; |
|
107 } |
|
108 |
|
109 void |
|
110 LayerManagerD3D9::EndConstruction() |
|
111 { |
|
112 } |
|
113 |
|
114 bool |
|
115 LayerManagerD3D9::EndEmptyTransaction(EndTransactionFlags aFlags) |
|
116 { |
|
117 mInTransaction = false; |
|
118 |
|
119 // If the device reset count from our last EndTransaction doesn't match |
|
120 // the current device reset count, the device must have been reset one or |
|
121 // more times since our last transaction. In that case, an empty transaction |
|
122 // is not possible, because layers may need to be rerendered. |
|
123 if (!mRoot || mDeviceResetCount != mDeviceManager->GetDeviceResetCount()) |
|
124 return false; |
|
125 |
|
126 EndTransaction(nullptr, nullptr, aFlags); |
|
127 return true; |
|
128 } |
|
129 |
|
130 void |
|
131 LayerManagerD3D9::EndTransaction(DrawThebesLayerCallback aCallback, |
|
132 void* aCallbackData, |
|
133 EndTransactionFlags aFlags) |
|
134 { |
|
135 mInTransaction = false; |
|
136 |
|
137 mDeviceResetCount = mDeviceManager->GetDeviceResetCount(); |
|
138 |
|
139 if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) { |
|
140 mCurrentCallbackInfo.Callback = aCallback; |
|
141 mCurrentCallbackInfo.CallbackData = aCallbackData; |
|
142 |
|
143 if (aFlags & END_NO_COMPOSITE) { |
|
144 // Apply pending tree updates before recomputing effective |
|
145 // properties. |
|
146 mRoot->ApplyPendingUpdatesToSubtree(); |
|
147 } |
|
148 |
|
149 // The results of our drawing always go directly into a pixel buffer, |
|
150 // so we don't need to pass any global transform here. |
|
151 mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); |
|
152 |
|
153 SetCompositingDisabled(aFlags & END_NO_COMPOSITE); |
|
154 Render(); |
|
155 /* Clean this out for sanity */ |
|
156 mCurrentCallbackInfo.Callback = nullptr; |
|
157 mCurrentCallbackInfo.CallbackData = nullptr; |
|
158 } |
|
159 |
|
160 // Clear mTarget, next transaction could have no target |
|
161 mTarget = nullptr; |
|
162 } |
|
163 |
|
164 void |
|
165 LayerManagerD3D9::SetRoot(Layer *aLayer) |
|
166 { |
|
167 mRoot = aLayer; |
|
168 } |
|
169 |
|
170 already_AddRefed<ThebesLayer> |
|
171 LayerManagerD3D9::CreateThebesLayer() |
|
172 { |
|
173 nsRefPtr<ThebesLayer> layer = new ThebesLayerD3D9(this); |
|
174 return layer.forget(); |
|
175 } |
|
176 |
|
177 already_AddRefed<ContainerLayer> |
|
178 LayerManagerD3D9::CreateContainerLayer() |
|
179 { |
|
180 nsRefPtr<ContainerLayer> layer = new ContainerLayerD3D9(this); |
|
181 return layer.forget(); |
|
182 } |
|
183 |
|
184 already_AddRefed<ImageLayer> |
|
185 LayerManagerD3D9::CreateImageLayer() |
|
186 { |
|
187 nsRefPtr<ImageLayer> layer = new ImageLayerD3D9(this); |
|
188 return layer.forget(); |
|
189 } |
|
190 |
|
191 already_AddRefed<ColorLayer> |
|
192 LayerManagerD3D9::CreateColorLayer() |
|
193 { |
|
194 nsRefPtr<ColorLayer> layer = new ColorLayerD3D9(this); |
|
195 return layer.forget(); |
|
196 } |
|
197 |
|
198 already_AddRefed<CanvasLayer> |
|
199 LayerManagerD3D9::CreateCanvasLayer() |
|
200 { |
|
201 nsRefPtr<CanvasLayer> layer = new CanvasLayerD3D9(this); |
|
202 return layer.forget(); |
|
203 } |
|
204 |
|
205 already_AddRefed<ReadbackLayer> |
|
206 LayerManagerD3D9::CreateReadbackLayer() |
|
207 { |
|
208 nsRefPtr<ReadbackLayer> layer = new ReadbackLayerD3D9(this); |
|
209 return layer.forget(); |
|
210 } |
|
211 |
|
212 void |
|
213 LayerManagerD3D9::ReportFailure(const nsACString &aMsg, HRESULT aCode) |
|
214 { |
|
215 // We could choose to abort here when hr == E_OUTOFMEMORY. |
|
216 nsCString msg; |
|
217 msg.Append(aMsg); |
|
218 msg.AppendLiteral(" Error code: "); |
|
219 msg.AppendInt(uint32_t(aCode)); |
|
220 NS_WARNING(msg.BeginReading()); |
|
221 |
|
222 gfx::LogFailure(msg); |
|
223 } |
|
224 |
|
225 void |
|
226 LayerManagerD3D9::Render() |
|
227 { |
|
228 if (mSwapChain->PrepareForRendering() != DeviceOK) { |
|
229 return; |
|
230 } |
|
231 |
|
232 deviceManager()->SetupRenderState(); |
|
233 |
|
234 SetupPipeline(); |
|
235 |
|
236 if (CompositingDisabled()) { |
|
237 static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer(); |
|
238 return; |
|
239 } |
|
240 |
|
241 nsIntRect rect; |
|
242 mWidget->GetClientBounds(rect); |
|
243 |
|
244 device()->Clear(0, nullptr, D3DCLEAR_TARGET, 0x00000000, 0, 0); |
|
245 |
|
246 device()->BeginScene(); |
|
247 |
|
248 const nsIntRect *clipRect = mRoot->GetClipRect(); |
|
249 RECT r; |
|
250 if (clipRect) { |
|
251 r.left = (LONG)clipRect->x; |
|
252 r.top = (LONG)clipRect->y; |
|
253 r.right = (LONG)(clipRect->x + clipRect->width); |
|
254 r.bottom = (LONG)(clipRect->y + clipRect->height); |
|
255 } else { |
|
256 r.left = r.top = 0; |
|
257 r.right = rect.width; |
|
258 r.bottom = rect.height; |
|
259 } |
|
260 device()->SetScissorRect(&r); |
|
261 |
|
262 static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer(); |
|
263 |
|
264 if (!mRegionToClear.IsEmpty()) { |
|
265 D3DRECT* rects = new D3DRECT[mRegionToClear.GetNumRects()]; |
|
266 nsIntRegionRectIterator iter(mRegionToClear); |
|
267 const nsIntRect *r; |
|
268 size_t i = 0; |
|
269 while ((r = iter.Next())) { |
|
270 rects[i].x1 = r->x; |
|
271 rects[i].y1 = r->y; |
|
272 rects[i].x2 = r->x + r->width; |
|
273 rects[i].y2 = r->y + r->height; |
|
274 i++; |
|
275 } |
|
276 |
|
277 device()->Clear(i, rects, D3DCLEAR_TARGET, |
|
278 0x00000000, 0, 0); |
|
279 |
|
280 delete [] rects; |
|
281 } |
|
282 |
|
283 device()->EndScene(); |
|
284 |
|
285 if (!mTarget) { |
|
286 const nsIntRect *r; |
|
287 for (nsIntRegionRectIterator iter(mClippingRegion); |
|
288 (r = iter.Next()) != nullptr;) { |
|
289 mSwapChain->Present(*r); |
|
290 } |
|
291 RecordFrame(); |
|
292 PostPresent(); |
|
293 } else { |
|
294 PaintToTarget(); |
|
295 } |
|
296 } |
|
297 |
|
298 void |
|
299 LayerManagerD3D9::SetupPipeline() |
|
300 { |
|
301 nsIntRect rect; |
|
302 mWidget->GetClientBounds(rect); |
|
303 |
|
304 gfx3DMatrix viewMatrix; |
|
305 /* |
|
306 * Matrix to transform to viewport space ( <-1.0, 1.0> topleft, |
|
307 * <1.0, -1.0> bottomright) |
|
308 */ |
|
309 viewMatrix._11 = 2.0f / rect.width; |
|
310 viewMatrix._22 = -2.0f / rect.height; |
|
311 viewMatrix._33 = 0.0f; |
|
312 viewMatrix._41 = -1.0f; |
|
313 viewMatrix._42 = 1.0f; |
|
314 |
|
315 HRESULT hr = device()->SetVertexShaderConstantF(CBmProjection, |
|
316 &viewMatrix._11, 4); |
|
317 |
|
318 if (FAILED(hr)) { |
|
319 NS_WARNING("Failed to set projection shader constant!"); |
|
320 } |
|
321 |
|
322 hr = device()->SetVertexShaderConstantF(CBvTextureCoords, |
|
323 ShaderConstantRect(0, 0, 1.0f, 1.0f), |
|
324 1); |
|
325 |
|
326 if (FAILED(hr)) { |
|
327 NS_WARNING("Failed to set texCoords shader constant!"); |
|
328 } |
|
329 |
|
330 float offset[] = { 0, 0, 0, 0 }; |
|
331 hr = device()->SetVertexShaderConstantF(CBvRenderTargetOffset, offset, 1); |
|
332 |
|
333 if (FAILED(hr)) { |
|
334 NS_WARNING("Failed to set RenderTargetOffset shader constant!"); |
|
335 } |
|
336 } |
|
337 |
|
338 void |
|
339 LayerManagerD3D9::PaintToTarget() |
|
340 { |
|
341 nsRefPtr<IDirect3DSurface9> backBuff; |
|
342 nsRefPtr<IDirect3DSurface9> destSurf; |
|
343 device()->GetRenderTarget(0, getter_AddRefs(backBuff)); |
|
344 |
|
345 D3DSURFACE_DESC desc; |
|
346 backBuff->GetDesc(&desc); |
|
347 |
|
348 device()->CreateOffscreenPlainSurface(desc.Width, desc.Height, |
|
349 D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, |
|
350 getter_AddRefs(destSurf), nullptr); |
|
351 |
|
352 device()->GetRenderTargetData(backBuff, destSurf); |
|
353 |
|
354 D3DLOCKED_RECT rect; |
|
355 destSurf->LockRect(&rect, nullptr, D3DLOCK_READONLY); |
|
356 |
|
357 nsRefPtr<gfxImageSurface> imageSurface = |
|
358 new gfxImageSurface((unsigned char*)rect.pBits, |
|
359 gfxIntSize(desc.Width, desc.Height), |
|
360 rect.Pitch, |
|
361 gfxImageFormat::ARGB32); |
|
362 |
|
363 mTarget->SetSource(imageSurface); |
|
364 mTarget->SetOperator(gfxContext::OPERATOR_OVER); |
|
365 mTarget->Paint(); |
|
366 destSurf->UnlockRect(); |
|
367 } |
|
368 |
|
369 LayerD3D9::LayerD3D9(LayerManagerD3D9 *aManager) |
|
370 : mD3DManager(aManager) |
|
371 { |
|
372 } |
|
373 |
|
374 } /* namespace layers */ |
|
375 } /* namespace mozilla */ |