|
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 "mozilla/layers/PLayerTransaction.h" |
|
7 |
|
8 // This must occur *after* layers/PLayerTransaction.h to avoid |
|
9 // typedefs conflicts. |
|
10 #include "mozilla/ArrayUtils.h" |
|
11 |
|
12 #include "ThebesLayerD3D9.h" |
|
13 #include "gfxPlatform.h" |
|
14 |
|
15 #include "gfxWindowsPlatform.h" |
|
16 #include "gfxTeeSurface.h" |
|
17 #include "gfxUtils.h" |
|
18 #include "ReadbackProcessor.h" |
|
19 #include "ReadbackLayer.h" |
|
20 #include "mozilla/gfx/2D.h" |
|
21 |
|
22 namespace mozilla { |
|
23 namespace layers { |
|
24 |
|
25 using namespace gfx; |
|
26 |
|
27 ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager) |
|
28 : ThebesLayer(aManager, nullptr) |
|
29 , LayerD3D9(aManager) |
|
30 { |
|
31 mImplData = static_cast<LayerD3D9*>(this); |
|
32 aManager->deviceManager()->mLayersWithResources.AppendElement(this); |
|
33 } |
|
34 |
|
35 ThebesLayerD3D9::~ThebesLayerD3D9() |
|
36 { |
|
37 if (mD3DManager) { |
|
38 mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this); |
|
39 } |
|
40 } |
|
41 |
|
42 /** |
|
43 * Retention threshold - amount of pixels intersection required to enable |
|
44 * layer content retention. This is a guesstimate. Profiling could be done to |
|
45 * figure out the optimal threshold. |
|
46 */ |
|
47 #define RETENTION_THRESHOLD 16384 |
|
48 |
|
49 void |
|
50 ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion) |
|
51 { |
|
52 mInvalidRegion.Or(mInvalidRegion, aRegion); |
|
53 mInvalidRegion.SimplifyOutward(20); |
|
54 mValidRegion.Sub(mValidRegion, mInvalidRegion); |
|
55 } |
|
56 |
|
57 void |
|
58 ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset, |
|
59 IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset, |
|
60 const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion) |
|
61 { |
|
62 nsRefPtr<IDirect3DSurface9> srcSurface, dstSurface; |
|
63 aSrc->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); |
|
64 aDest->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); |
|
65 |
|
66 nsIntRegion retainedRegion; |
|
67 nsIntRegionRectIterator iter(aCopyRegion); |
|
68 const nsIntRect *r; |
|
69 while ((r = iter.Next())) { |
|
70 if (r->width * r->height > RETENTION_THRESHOLD) { |
|
71 RECT oldRect, newRect; |
|
72 |
|
73 // Calculate the retained rectangle's position on the old and the new |
|
74 // surface. |
|
75 oldRect.left = r->x - aSrcOffset.x; |
|
76 oldRect.top = r->y - aSrcOffset.y; |
|
77 oldRect.right = oldRect.left + r->width; |
|
78 oldRect.bottom = oldRect.top + r->height; |
|
79 |
|
80 newRect.left = r->x - aDestOffset.x; |
|
81 newRect.top = r->y - aDestOffset.y; |
|
82 newRect.right = newRect.left + r->width; |
|
83 newRect.bottom = newRect.top + r->height; |
|
84 |
|
85 // Copy data from our old texture to the new one |
|
86 HRESULT hr = device()-> |
|
87 StretchRect(srcSurface, &oldRect, dstSurface, &newRect, D3DTEXF_NONE); |
|
88 |
|
89 if (SUCCEEDED(hr)) { |
|
90 retainedRegion.Or(retainedRegion, *r); |
|
91 } |
|
92 } |
|
93 } |
|
94 |
|
95 // Areas which were valid and were retained are still valid |
|
96 aValidRegion->And(*aValidRegion, retainedRegion); |
|
97 } |
|
98 |
|
99 static uint64_t RectArea(const nsIntRect& aRect) |
|
100 { |
|
101 return aRect.width*uint64_t(aRect.height); |
|
102 } |
|
103 |
|
104 void |
|
105 ThebesLayerD3D9::UpdateTextures(SurfaceMode aMode) |
|
106 { |
|
107 nsIntRect visibleRect = mVisibleRegion.GetBounds(); |
|
108 |
|
109 if (HaveTextures(aMode)) { |
|
110 if (!mTextureRect.IsEqualInterior(visibleRect)) { |
|
111 nsRefPtr<IDirect3DTexture9> oldTexture = mTexture; |
|
112 nsRefPtr<IDirect3DTexture9> oldTextureOnWhite = mTextureOnWhite; |
|
113 |
|
114 NS_ASSERTION(mTextureRect.Contains(mValidRegion.GetBounds()), |
|
115 "How can we have valid data outside the texture?"); |
|
116 nsIntRegion retainRegion; |
|
117 // The region we want to retain is the valid data that is inside |
|
118 // the new visible region |
|
119 retainRegion.And(mValidRegion, mVisibleRegion); |
|
120 |
|
121 CreateNewTextures(gfx::IntSize(visibleRect.width, visibleRect.height), aMode); |
|
122 |
|
123 // If our texture creation failed this can mean a device reset is pending and we |
|
124 // should silently ignore the failure. In the future when device failures |
|
125 // are properly handled we should test for the type of failure and gracefully |
|
126 // handle different failures. See bug 569081. |
|
127 if (!HaveTextures(aMode)) { |
|
128 mValidRegion.SetEmpty(); |
|
129 } else { |
|
130 CopyRegion(oldTexture, mTextureRect.TopLeft(), mTexture, visibleRect.TopLeft(), |
|
131 retainRegion, &mValidRegion); |
|
132 if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { |
|
133 CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(), mTextureOnWhite, visibleRect.TopLeft(), |
|
134 retainRegion, &mValidRegion); |
|
135 } |
|
136 } |
|
137 |
|
138 mTextureRect = visibleRect; |
|
139 } |
|
140 } else { |
|
141 CreateNewTextures(gfx::IntSize(visibleRect.width, visibleRect.height), aMode); |
|
142 mTextureRect = visibleRect; |
|
143 |
|
144 NS_ASSERTION(mValidRegion.IsEmpty(), "Someone forgot to empty the region"); |
|
145 } |
|
146 } |
|
147 |
|
148 void |
|
149 ThebesLayerD3D9::RenderRegion(const nsIntRegion& aRegion) |
|
150 { |
|
151 nsIntRegionRectIterator iter(aRegion); |
|
152 |
|
153 const nsIntRect *iterRect; |
|
154 while ((iterRect = iter.Next())) { |
|
155 device()->SetVertexShaderConstantF(CBvLayerQuad, |
|
156 ShaderConstantRect(iterRect->x, |
|
157 iterRect->y, |
|
158 iterRect->width, |
|
159 iterRect->height), |
|
160 1); |
|
161 |
|
162 device()->SetVertexShaderConstantF(CBvTextureCoords, |
|
163 ShaderConstantRect( |
|
164 (float)(iterRect->x - mTextureRect.x) / (float)mTextureRect.width, |
|
165 (float)(iterRect->y - mTextureRect.y) / (float)mTextureRect.height, |
|
166 (float)iterRect->width / (float)mTextureRect.width, |
|
167 (float)iterRect->height / (float)mTextureRect.height), 1); |
|
168 |
|
169 device()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); |
|
170 } |
|
171 } |
|
172 |
|
173 void |
|
174 ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback) |
|
175 { |
|
176 if (mVisibleRegion.IsEmpty()) { |
|
177 return; |
|
178 } |
|
179 |
|
180 nsIntRect newTextureRect = mVisibleRegion.GetBounds(); |
|
181 |
|
182 SurfaceMode mode = GetSurfaceMode(); |
|
183 if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA && |
|
184 (!mParent || !mParent->SupportsComponentAlphaChildren())) { |
|
185 mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; |
|
186 } |
|
187 // If we have a transform that requires resampling of our texture, then |
|
188 // we need to make sure we don't sample pixels that haven't been drawn. |
|
189 // We clamp sample coordinates to the texture rect, but when the visible region |
|
190 // doesn't fill the entire texture rect we need to make sure we draw all the |
|
191 // pixels in the texture rect anyway in case they get sampled. |
|
192 nsIntRegion neededRegion = mVisibleRegion; |
|
193 if (!neededRegion.GetBounds().IsEqualInterior(newTextureRect) || |
|
194 neededRegion.GetNumRects() > 1) { |
|
195 if (MayResample()) { |
|
196 neededRegion = newTextureRect; |
|
197 if (mode == SurfaceMode::SURFACE_OPAQUE) { |
|
198 // We're going to paint outside the visible region, but layout hasn't |
|
199 // promised that it will paint opaquely there, so we'll have to |
|
200 // treat this layer as transparent. |
|
201 mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA; |
|
202 } |
|
203 } |
|
204 } |
|
205 |
|
206 VerifyContentType(mode); |
|
207 UpdateTextures(mode); |
|
208 if (!HaveTextures(mode)) { |
|
209 NS_WARNING("Texture creation failed"); |
|
210 return; |
|
211 } |
|
212 |
|
213 nsTArray<ReadbackProcessor::Update> readbackUpdates; |
|
214 nsIntRegion readbackRegion; |
|
215 if (aReadback && UsedForReadback()) { |
|
216 aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion); |
|
217 } |
|
218 |
|
219 // Because updates to D3D9 ThebesLayers are rendered with the CPU, we don't |
|
220 // have to do readback from D3D9 surfaces. Instead we make sure that any area |
|
221 // needed for readback is included in the drawRegion we ask layout to render. |
|
222 // Then the readback areas we need can be copied out of the temporary |
|
223 // destinationSurface in DrawRegion. |
|
224 nsIntRegion drawRegion; |
|
225 drawRegion.Sub(neededRegion, mValidRegion); |
|
226 drawRegion.Or(drawRegion, readbackRegion); |
|
227 // NS_ASSERTION(mVisibleRegion.Contains(region), "Bad readback region!"); |
|
228 |
|
229 if (!drawRegion.IsEmpty()) { |
|
230 LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); |
|
231 if (!cbInfo.Callback) { |
|
232 NS_ERROR("D3D9 should never need to update ThebesLayers in an empty transaction"); |
|
233 return; |
|
234 } |
|
235 |
|
236 DrawRegion(drawRegion, mode, readbackUpdates); |
|
237 |
|
238 mValidRegion = neededRegion; |
|
239 } |
|
240 |
|
241 if (mD3DManager->CompositingDisabled()) { |
|
242 return; |
|
243 } |
|
244 |
|
245 SetShaderTransformAndOpacity(); |
|
246 |
|
247 if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { |
|
248 mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1, |
|
249 GetMaskLayer()); |
|
250 device()->SetTexture(0, mTexture); |
|
251 device()->SetTexture(1, mTextureOnWhite); |
|
252 device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO); |
|
253 device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCCOLOR); |
|
254 RenderRegion(neededRegion); |
|
255 |
|
256 mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS2, |
|
257 GetMaskLayer()); |
|
258 device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); |
|
259 device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); |
|
260 RenderRegion(neededRegion); |
|
261 |
|
262 // Restore defaults |
|
263 device()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); |
|
264 device()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); |
|
265 device()->SetTexture(1, nullptr); |
|
266 } else { |
|
267 mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER, |
|
268 GetMaskLayer()); |
|
269 device()->SetTexture(0, mTexture); |
|
270 RenderRegion(neededRegion); |
|
271 } |
|
272 |
|
273 // Set back to default. |
|
274 device()->SetVertexShaderConstantF(CBvTextureCoords, |
|
275 ShaderConstantRect(0, 0, 1.0f, 1.0f), |
|
276 1); |
|
277 } |
|
278 |
|
279 void |
|
280 ThebesLayerD3D9::CleanResources() |
|
281 { |
|
282 mTexture = nullptr; |
|
283 mTextureOnWhite = nullptr; |
|
284 mValidRegion.SetEmpty(); |
|
285 } |
|
286 |
|
287 void |
|
288 ThebesLayerD3D9::LayerManagerDestroyed() |
|
289 { |
|
290 mD3DManager->deviceManager()->mLayersWithResources.RemoveElement(this); |
|
291 mD3DManager = nullptr; |
|
292 } |
|
293 |
|
294 Layer* |
|
295 ThebesLayerD3D9::GetLayer() |
|
296 { |
|
297 return this; |
|
298 } |
|
299 |
|
300 bool |
|
301 ThebesLayerD3D9::IsEmpty() |
|
302 { |
|
303 return !mTexture; |
|
304 } |
|
305 |
|
306 void |
|
307 ThebesLayerD3D9::VerifyContentType(SurfaceMode aMode) |
|
308 { |
|
309 if (!mTexture) |
|
310 return; |
|
311 |
|
312 D3DSURFACE_DESC desc; |
|
313 mTexture->GetLevelDesc(0, &desc); |
|
314 |
|
315 switch (aMode) { |
|
316 case SurfaceMode::SURFACE_OPAQUE: |
|
317 if (desc.Format == D3DFMT_X8R8G8B8 && !mTextureOnWhite) |
|
318 return; |
|
319 break; |
|
320 |
|
321 case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: |
|
322 if (desc.Format == D3DFMT_A8R8G8B8 && !mTextureOnWhite) |
|
323 return; |
|
324 break; |
|
325 |
|
326 case SurfaceMode::SURFACE_COMPONENT_ALPHA: |
|
327 if (mTextureOnWhite) { |
|
328 NS_ASSERTION(desc.Format == D3DFMT_X8R8G8B8, "Wrong format for component alpha texture"); |
|
329 return; |
|
330 } |
|
331 break; |
|
332 } |
|
333 |
|
334 // The new format isn't compatible with the old texture(s), toss out the old |
|
335 // texture(s). |
|
336 mTexture = nullptr; |
|
337 mTextureOnWhite = nullptr; |
|
338 mValidRegion.SetEmpty(); |
|
339 } |
|
340 |
|
341 class OpaqueRenderer { |
|
342 public: |
|
343 OpaqueRenderer(const nsIntRegion& aUpdateRegion) : |
|
344 mUpdateRegion(aUpdateRegion) {} |
|
345 ~OpaqueRenderer() { End(); } |
|
346 already_AddRefed<gfxWindowsSurface> Begin(LayerD3D9* aLayer); |
|
347 void End(); |
|
348 IDirect3DTexture9* GetTexture() { return mTmpTexture; } |
|
349 |
|
350 private: |
|
351 const nsIntRegion& mUpdateRegion; |
|
352 nsRefPtr<IDirect3DTexture9> mTmpTexture; |
|
353 nsRefPtr<IDirect3DSurface9> mSurface; |
|
354 nsRefPtr<gfxWindowsSurface> mD3D9ThebesSurface; |
|
355 }; |
|
356 |
|
357 already_AddRefed<gfxWindowsSurface> |
|
358 OpaqueRenderer::Begin(LayerD3D9* aLayer) |
|
359 { |
|
360 nsIntRect bounds = mUpdateRegion.GetBounds(); |
|
361 |
|
362 HRESULT hr = aLayer->device()-> |
|
363 CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_X8R8G8B8, |
|
364 D3DPOOL_SYSTEMMEM, getter_AddRefs(mTmpTexture), nullptr); |
|
365 |
|
366 if (FAILED(hr)) { |
|
367 aLayer->ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr); |
|
368 return nullptr; |
|
369 } |
|
370 |
|
371 hr = mTmpTexture->GetSurfaceLevel(0, getter_AddRefs(mSurface)); |
|
372 |
|
373 if (FAILED(hr)) { |
|
374 // Uh-oh, bail. |
|
375 NS_WARNING("Failed to get texture surface level."); |
|
376 return nullptr; |
|
377 } |
|
378 |
|
379 nsRefPtr<gfxWindowsSurface> result = new gfxWindowsSurface(mSurface); |
|
380 if (!result || result->CairoStatus()) { |
|
381 NS_WARNING("Failed to d3d9 cairo surface."); |
|
382 return nullptr; |
|
383 } |
|
384 mD3D9ThebesSurface = result; |
|
385 |
|
386 return result.forget(); |
|
387 } |
|
388 |
|
389 void |
|
390 OpaqueRenderer::End() |
|
391 { |
|
392 mSurface = nullptr; |
|
393 // gfxWindowsSurface returned from ::Begin() should be released before the |
|
394 // texture is used. This will assert that this is the case |
|
395 #if 1 |
|
396 if (mD3D9ThebesSurface) { |
|
397 mD3D9ThebesSurface->AddRef(); |
|
398 nsrefcnt c = mD3D9ThebesSurface->Release(); |
|
399 if (c != 1) |
|
400 NS_RUNTIMEABORT("Reference mD3D9ThebesSurface must be released by caller of Begin() before calling End()"); |
|
401 } |
|
402 #endif |
|
403 mD3D9ThebesSurface = nullptr; |
|
404 |
|
405 } |
|
406 |
|
407 static void |
|
408 FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion, |
|
409 const nsIntPoint& aOffset, const gfxRGBA& aColor) |
|
410 { |
|
411 nsRefPtr<gfxContext> ctx = new gfxContext(aSurface); |
|
412 ctx->Translate(-gfxPoint(aOffset.x, aOffset.y)); |
|
413 gfxUtils::ClipToRegion(ctx, aRegion); |
|
414 ctx->SetColor(aColor); |
|
415 ctx->Paint(); |
|
416 } |
|
417 |
|
418 void |
|
419 ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode, |
|
420 const nsTArray<ReadbackProcessor::Update>& aReadbackUpdates) |
|
421 { |
|
422 HRESULT hr; |
|
423 nsIntRect visibleRect = mVisibleRegion.GetBounds(); |
|
424 |
|
425 nsRefPtr<gfxASurface> destinationSurface; |
|
426 nsIntRect bounds = aRegion.GetBounds(); |
|
427 nsRefPtr<IDirect3DTexture9> tmpTexture; |
|
428 OpaqueRenderer opaqueRenderer(aRegion); |
|
429 OpaqueRenderer opaqueRendererOnWhite(aRegion); |
|
430 |
|
431 switch (aMode) |
|
432 { |
|
433 case SurfaceMode::SURFACE_OPAQUE: |
|
434 destinationSurface = opaqueRenderer.Begin(this); |
|
435 break; |
|
436 |
|
437 case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { |
|
438 hr = device()->CreateTexture(bounds.width, bounds.height, 1, |
|
439 0, D3DFMT_A8R8G8B8, |
|
440 D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), nullptr); |
|
441 |
|
442 if (FAILED(hr)) { |
|
443 ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr); |
|
444 return; |
|
445 } |
|
446 |
|
447 // XXX - We may consider retaining a SYSTEMMEM texture texture the size |
|
448 // of our DEFAULT texture and then use UpdateTexture and add dirty rects |
|
449 // to update in a single call. |
|
450 nsRefPtr<gfxWindowsSurface> dest = new gfxWindowsSurface( |
|
451 gfxIntSize(bounds.width, bounds.height), gfxImageFormat::ARGB32); |
|
452 // If the contents of this layer don't require component alpha in the |
|
453 // end of rendering, it's safe to enable Cleartype since all the Cleartype |
|
454 // glyphs must be over (or under) opaque pixels. |
|
455 dest->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA)); |
|
456 destinationSurface = dest.forget(); |
|
457 break; |
|
458 } |
|
459 |
|
460 case SurfaceMode::SURFACE_COMPONENT_ALPHA: { |
|
461 nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this); |
|
462 nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this); |
|
463 if (onBlack && onWhite) { |
|
464 FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0)); |
|
465 FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0)); |
|
466 gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() }; |
|
467 destinationSurface = new gfxTeeSurface(surfaces, ArrayLength(surfaces)); |
|
468 // Using this surface as a source will likely go horribly wrong, since |
|
469 // only the onBlack surface will really be used, so alpha information will |
|
470 // be incorrect. |
|
471 destinationSurface->SetAllowUseAsSource(false); |
|
472 } |
|
473 break; |
|
474 } |
|
475 } |
|
476 |
|
477 if (!destinationSurface) |
|
478 return; |
|
479 |
|
480 nsRefPtr<gfxContext> context; |
|
481 if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) { |
|
482 RefPtr<DrawTarget> dt = |
|
483 gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface, |
|
484 IntSize(destinationSurface->GetSize().width, |
|
485 destinationSurface->GetSize().height)); |
|
486 |
|
487 context = new gfxContext(dt); |
|
488 } else { |
|
489 context = new gfxContext(destinationSurface); |
|
490 } |
|
491 |
|
492 context->Translate(gfxPoint(-bounds.x, -bounds.y)); |
|
493 LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); |
|
494 cbInfo.Callback(this, context, aRegion, DrawRegionClip::CLIP_NONE, nsIntRegion(), cbInfo.CallbackData); |
|
495 |
|
496 for (uint32_t i = 0; i < aReadbackUpdates.Length(); ++i) { |
|
497 NS_ASSERTION(aMode == SurfaceMode::SURFACE_OPAQUE, |
|
498 "Transparent surfaces should not be used for readback"); |
|
499 const ReadbackProcessor::Update& update = aReadbackUpdates[i]; |
|
500 nsIntPoint offset = update.mLayer->GetBackgroundLayerOffset(); |
|
501 nsRefPtr<gfxContext> ctx = |
|
502 update.mLayer->GetSink()->BeginUpdate(update.mUpdateRect + offset, |
|
503 update.mSequenceCounter); |
|
504 if (ctx) { |
|
505 ctx->Translate(gfxPoint(offset.x, offset.y)); |
|
506 ctx->SetSource(destinationSurface, gfxPoint(bounds.x, bounds.y)); |
|
507 ctx->Paint(); |
|
508 update.mLayer->GetSink()->EndUpdate(ctx, update.mUpdateRect + offset); |
|
509 } |
|
510 } |
|
511 |
|
512 // Release the cairo d3d9 surface before we try to composite it |
|
513 context = nullptr; |
|
514 |
|
515 nsAutoTArray<IDirect3DTexture9*,2> srcTextures; |
|
516 nsAutoTArray<IDirect3DTexture9*,2> destTextures; |
|
517 switch (aMode) |
|
518 { |
|
519 case SurfaceMode::SURFACE_OPAQUE: |
|
520 // Must release reference to dest surface before ending drawing |
|
521 destinationSurface = nullptr; |
|
522 opaqueRenderer.End(); |
|
523 srcTextures.AppendElement(opaqueRenderer.GetTexture()); |
|
524 destTextures.AppendElement(mTexture); |
|
525 break; |
|
526 |
|
527 case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: { |
|
528 LockTextureRectD3D9 textureLock(tmpTexture); |
|
529 if (!textureLock.HasLock()) { |
|
530 NS_WARNING("Failed to lock ThebesLayer tmpTexture texture."); |
|
531 return; |
|
532 } |
|
533 |
|
534 D3DLOCKED_RECT r = textureLock.GetLockRect(); |
|
535 |
|
536 nsRefPtr<gfxImageSurface> imgSurface = |
|
537 new gfxImageSurface((unsigned char *)r.pBits, |
|
538 bounds.Size(), |
|
539 r.Pitch, |
|
540 gfxImageFormat::ARGB32); |
|
541 |
|
542 if (destinationSurface) { |
|
543 nsRefPtr<gfxContext> context = new gfxContext(imgSurface); |
|
544 context->SetSource(destinationSurface); |
|
545 context->SetOperator(gfxContext::OPERATOR_SOURCE); |
|
546 context->Paint(); |
|
547 } |
|
548 |
|
549 // Must release reference to dest surface before ending drawing |
|
550 destinationSurface = nullptr; |
|
551 imgSurface = nullptr; |
|
552 |
|
553 srcTextures.AppendElement(tmpTexture); |
|
554 destTextures.AppendElement(mTexture); |
|
555 break; |
|
556 } |
|
557 |
|
558 case SurfaceMode::SURFACE_COMPONENT_ALPHA: { |
|
559 // Must release reference to dest surface before ending drawing |
|
560 destinationSurface = nullptr; |
|
561 opaqueRenderer.End(); |
|
562 opaqueRendererOnWhite.End(); |
|
563 srcTextures.AppendElement(opaqueRenderer.GetTexture()); |
|
564 destTextures.AppendElement(mTexture); |
|
565 srcTextures.AppendElement(opaqueRendererOnWhite.GetTexture()); |
|
566 destTextures.AppendElement(mTextureOnWhite); |
|
567 break; |
|
568 } |
|
569 } |
|
570 NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths"); |
|
571 |
|
572 |
|
573 // Copy to the texture. |
|
574 for (uint32_t i = 0; i < srcTextures.Length(); ++i) { |
|
575 nsRefPtr<IDirect3DSurface9> srcSurface; |
|
576 nsRefPtr<IDirect3DSurface9> dstSurface; |
|
577 |
|
578 destTextures[i]->GetSurfaceLevel(0, getter_AddRefs(dstSurface)); |
|
579 srcTextures[i]->GetSurfaceLevel(0, getter_AddRefs(srcSurface)); |
|
580 |
|
581 nsIntRegionRectIterator iter(aRegion); |
|
582 const nsIntRect *iterRect; |
|
583 while ((iterRect = iter.Next())) { |
|
584 RECT rect; |
|
585 rect.left = iterRect->x - bounds.x; |
|
586 rect.top = iterRect->y - bounds.y; |
|
587 rect.right = iterRect->XMost() - bounds.x; |
|
588 rect.bottom = iterRect->YMost() - bounds.y; |
|
589 |
|
590 POINT point; |
|
591 point.x = iterRect->x - visibleRect.x; |
|
592 point.y = iterRect->y - visibleRect.y; |
|
593 device()->UpdateSurface(srcSurface, &rect, dstSurface, &point); |
|
594 } |
|
595 } |
|
596 } |
|
597 |
|
598 void |
|
599 ThebesLayerD3D9::CreateNewTextures(const gfx::IntSize &aSize, |
|
600 SurfaceMode aMode) |
|
601 { |
|
602 if (aSize.width == 0 || aSize.height == 0) { |
|
603 // Nothing to do. |
|
604 return; |
|
605 } |
|
606 |
|
607 mTexture = nullptr; |
|
608 mTextureOnWhite = nullptr; |
|
609 HRESULT hr = device()->CreateTexture(aSize.width, aSize.height, 1, |
|
610 D3DUSAGE_RENDERTARGET, |
|
611 aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8, |
|
612 D3DPOOL_DEFAULT, getter_AddRefs(mTexture), nullptr); |
|
613 if (FAILED(hr)) { |
|
614 ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D9::CreateNewTextures(): Failed to create texture"), |
|
615 hr); |
|
616 return; |
|
617 } |
|
618 |
|
619 if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { |
|
620 hr = device()->CreateTexture(aSize.width, aSize.height, 1, |
|
621 D3DUSAGE_RENDERTARGET, |
|
622 D3DFMT_X8R8G8B8, |
|
623 D3DPOOL_DEFAULT, getter_AddRefs(mTextureOnWhite), nullptr); |
|
624 if (FAILED(hr)) { |
|
625 ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D9::CreateNewTextures(): Failed to create texture (2)"), |
|
626 hr); |
|
627 return; |
|
628 } |
|
629 } |
|
630 } |
|
631 |
|
632 } /* namespace layers */ |
|
633 } /* namespace mozilla */ |