Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "mozilla/layers/PLayerTransaction.h"
8 // This must occur *after* layers/PLayerTransaction.h to avoid
9 // typedefs conflicts.
10 #include "mozilla/ArrayUtils.h"
12 #include "ThebesLayerD3D10.h"
13 #include "gfxPlatform.h"
15 #include "gfxWindowsPlatform.h"
16 #ifdef CAIRO_HAS_D2D_SURFACE
17 #include "gfxD2DSurface.h"
18 #endif
20 #include "../d3d9/Nv3DVUtils.h"
21 #include "gfxTeeSurface.h"
22 #include "gfxUtils.h"
23 #include "ReadbackLayer.h"
24 #include "ReadbackProcessor.h"
26 #include "mozilla/Preferences.h"
27 #include "mozilla/gfx/2D.h"
29 using namespace mozilla::gfx;
31 namespace mozilla {
32 namespace layers {
34 ThebesLayerD3D10::ThebesLayerD3D10(LayerManagerD3D10 *aManager)
35 : ThebesLayer(aManager, nullptr)
36 , LayerD3D10(aManager)
37 , mCurrentSurfaceMode(SurfaceMode::SURFACE_OPAQUE)
38 {
39 mImplData = static_cast<LayerD3D10*>(this);
40 }
42 ThebesLayerD3D10::~ThebesLayerD3D10()
43 {
44 }
46 void
47 ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion)
48 {
49 mInvalidRegion.Or(mInvalidRegion, aRegion);
50 mInvalidRegion.SimplifyOutward(20);
51 mValidRegion.Sub(mValidRegion, mInvalidRegion);
52 }
54 void ThebesLayerD3D10::CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcOffset,
55 ID3D10Texture2D* aDest, const nsIntPoint &aDestOffset,
56 const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion)
57 {
58 nsIntRegion retainedRegion;
59 nsIntRegionRectIterator iter(aCopyRegion);
60 const nsIntRect *r;
61 while ((r = iter.Next())) {
62 // Calculate the retained rectangle's position on the old and the new
63 // surface.
64 D3D10_BOX box;
65 box.left = r->x - aSrcOffset.x;
66 box.top = r->y - aSrcOffset.y;
67 box.right = box.left + r->width;
68 box.bottom = box.top + r->height;
69 box.back = 1;
70 box.front = 0;
72 device()->CopySubresourceRegion(aDest, 0,
73 r->x - aDestOffset.x,
74 r->y - aDestOffset.y,
75 0,
76 aSrc, 0,
77 &box);
79 retainedRegion.Or(retainedRegion, *r);
80 }
82 // Areas which were valid and were retained are still valid
83 aValidRegion->And(*aValidRegion, retainedRegion);
84 }
86 void
87 ThebesLayerD3D10::RenderLayer()
88 {
89 if (!mTexture) {
90 return;
91 }
93 SetEffectTransformAndOpacity();
95 ID3D10EffectTechnique *technique;
96 switch (mCurrentSurfaceMode) {
97 case SurfaceMode::SURFACE_COMPONENT_ALPHA:
98 technique = SelectShader(SHADER_COMPONENT_ALPHA | LoadMaskTexture());
99 break;
100 case SurfaceMode::SURFACE_OPAQUE:
101 technique = SelectShader(SHADER_RGB | SHADER_PREMUL | LoadMaskTexture());
102 break;
103 case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA:
104 technique = SelectShader(SHADER_RGBA | SHADER_PREMUL | LoadMaskTexture());
105 break;
106 default:
107 NS_ERROR("Unknown mode");
108 return;
109 }
111 nsIntRegionRectIterator iter(mVisibleRegion);
113 const nsIntRect *iterRect;
114 if (mSRView) {
115 effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(mSRView);
116 }
117 if (mSRViewOnWhite) {
118 effect()->GetVariableByName("tRGBWhite")->AsShaderResource()->SetResource(mSRViewOnWhite);
119 }
121 while ((iterRect = iter.Next())) {
122 effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
123 ShaderConstantRectD3D10(
124 (float)iterRect->x,
125 (float)iterRect->y,
126 (float)iterRect->width,
127 (float)iterRect->height)
128 );
130 effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector(
131 ShaderConstantRectD3D10(
132 (float)(iterRect->x - mTextureRect.x) / (float)mTextureRect.width,
133 (float)(iterRect->y - mTextureRect.y) / (float)mTextureRect.height,
134 (float)iterRect->width / (float)mTextureRect.width,
135 (float)iterRect->height / (float)mTextureRect.height)
136 );
138 technique->GetPassByIndex(0)->Apply(0);
139 device()->Draw(4, 0);
140 }
142 // Set back to default.
143 effect()->GetVariableByName("vTextureCoords")->AsVector()->
144 SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
145 }
147 void
148 ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
149 {
150 if (mVisibleRegion.IsEmpty()) {
151 return;
152 }
154 if (FAILED(gfxWindowsPlatform::GetPlatform()->GetD3D10Device()->GetDeviceRemovedReason())) {
155 // Device removed, this will be discovered on the next rendering pass.
156 // Do no validate.
157 return;
158 }
160 nsIntRect newTextureRect = mVisibleRegion.GetBounds();
162 SurfaceMode mode = GetSurfaceMode();
163 if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA &&
164 (!mParent || !mParent->SupportsComponentAlphaChildren())) {
165 mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
166 }
167 // If we have a transform that requires resampling of our texture, then
168 // we need to make sure we don't sample pixels that haven't been drawn.
169 // We clamp sample coordinates to the texture rect, but when the visible region
170 // doesn't fill the entire texture rect we need to make sure we draw all the
171 // pixels in the texture rect anyway in case they get sampled.
172 nsIntRegion neededRegion = mVisibleRegion;
173 if (!neededRegion.GetBounds().IsEqualInterior(newTextureRect) ||
174 neededRegion.GetNumRects() > 1) {
175 if (MayResample()) {
176 neededRegion = newTextureRect;
177 if (mode == SurfaceMode::SURFACE_OPAQUE) {
178 // We're going to paint outside the visible region, but layout hasn't
179 // promised that it will paint opaquely there, so we'll have to
180 // treat this layer as transparent.
181 mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
182 }
183 }
184 }
185 mCurrentSurfaceMode = mode;
187 VerifyContentType(mode);
189 nsTArray<ReadbackProcessor::Update> readbackUpdates;
190 nsIntRegion readbackRegion;
191 if (aReadback && UsedForReadback()) {
192 aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion);
193 }
195 if (mTexture) {
196 if (!mTextureRect.IsEqualInterior(newTextureRect)) {
197 nsRefPtr<ID3D10Texture2D> oldTexture = mTexture;
198 mTexture = nullptr;
199 nsRefPtr<ID3D10Texture2D> oldTextureOnWhite = mTextureOnWhite;
200 mTextureOnWhite = nullptr;
202 nsIntRegion retainRegion = mTextureRect;
203 // Old visible region will become the region that is covered by both the
204 // old and the new visible region.
205 retainRegion.And(retainRegion, mVisibleRegion);
206 // No point in retaining parts which were not valid.
207 retainRegion.And(retainRegion, mValidRegion);
209 CreateNewTextures(gfx::IntSize(newTextureRect.width, newTextureRect.height), mode);
211 nsIntRect largeRect = retainRegion.GetLargestRectangle();
213 // If we had no hardware texture before, or have no retained area larger than
214 // the retention threshold, we're not retaining and are done here.
215 // If our texture creation failed this can mean a device reset is pending
216 // and we should silently ignore the failure. In the future when device
217 // failures are properly handled we should test for the type of failure
218 // and gracefully handle different failures. See bug 569081.
219 if (!oldTexture || !mTexture) {
220 mValidRegion.SetEmpty();
221 } else {
222 CopyRegion(oldTexture, mTextureRect.TopLeft(),
223 mTexture, newTextureRect.TopLeft(),
224 retainRegion, &mValidRegion);
225 if (oldTextureOnWhite) {
226 CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(),
227 mTextureOnWhite, newTextureRect.TopLeft(),
228 retainRegion, &mValidRegion);
229 }
230 }
231 }
232 }
233 mTextureRect = newTextureRect;
235 if (!mTexture || (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA && !mTextureOnWhite)) {
236 CreateNewTextures(gfx::IntSize(newTextureRect.width, newTextureRect.height), mode);
237 mValidRegion.SetEmpty();
238 }
240 nsIntRegion drawRegion;
241 drawRegion.Sub(neededRegion, mValidRegion);
243 if (!drawRegion.IsEmpty()) {
244 LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
245 if (!cbInfo.Callback) {
246 NS_ERROR("D3D10 should never need to update ThebesLayers in an empty transaction");
247 return;
248 }
250 DrawRegion(drawRegion, mode);
252 if (readbackUpdates.Length() > 0) {
253 CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
254 newTextureRect.width, newTextureRect.height,
255 1, 1, 0, D3D10_USAGE_STAGING,
256 D3D10_CPU_ACCESS_READ);
258 nsRefPtr<ID3D10Texture2D> readbackTexture;
259 HRESULT hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(readbackTexture));
260 if (FAILED(hr)) {
261 LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("ThebesLayerD3D10::Validate(): Failed to create texture"),
262 hr);
263 return;
264 }
266 device()->CopyResource(readbackTexture, mTexture);
268 for (uint32_t i = 0; i < readbackUpdates.Length(); i++) {
269 mD3DManager->readbackManager()->PostTask(readbackTexture,
270 &readbackUpdates[i],
271 gfxPoint(newTextureRect.x, newTextureRect.y));
272 }
273 }
275 mValidRegion = neededRegion;
276 }
277 }
279 void
280 ThebesLayerD3D10::LayerManagerDestroyed()
281 {
282 mD3DManager = nullptr;
283 }
285 Layer*
286 ThebesLayerD3D10::GetLayer()
287 {
288 return this;
289 }
291 void
292 ThebesLayerD3D10::VerifyContentType(SurfaceMode aMode)
293 {
294 if (mD2DSurface) {
295 gfxContentType type = aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ?
296 gfxContentType::COLOR : gfxContentType::COLOR_ALPHA;
298 if (type != mD2DSurface->GetContentType()) {
299 mD2DSurface = new gfxD2DSurface(mTexture, type);
301 if (!mD2DSurface || mD2DSurface->CairoStatus()) {
302 NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
303 mD2DSurface = nullptr;
304 return;
305 }
307 mValidRegion.SetEmpty();
308 }
309 } else if (mDrawTarget) {
310 SurfaceFormat format = aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ?
311 SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
313 if (format != mDrawTarget->GetFormat()) {
314 mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, format);
316 if (!mDrawTarget) {
317 NS_WARNING("Failed to create drawtarget for ThebesLayerD3D10.");
318 return;
319 }
321 mValidRegion.SetEmpty();
322 }
323 }
325 if (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA && mTextureOnWhite) {
326 // If we've transitioned away from component alpha, we can delete those resources.
327 mD2DSurfaceOnWhite = nullptr;
328 mSRViewOnWhite = nullptr;
329 mTextureOnWhite = nullptr;
330 mValidRegion.SetEmpty();
331 }
332 }
334 void
335 ThebesLayerD3D10::FillTexturesBlackWhite(const nsIntRegion& aRegion, const nsIntPoint& aOffset)
336 {
337 if (mTexture && mTextureOnWhite) {
338 // It would be more optimal to draw the actual geometry, but more code
339 // and probably not worth the win here as this will often be a single
340 // rect.
341 nsRefPtr<ID3D10RenderTargetView> oldRT;
342 device()->OMGetRenderTargets(1, getter_AddRefs(oldRT), nullptr);
344 nsRefPtr<ID3D10RenderTargetView> viewBlack;
345 nsRefPtr<ID3D10RenderTargetView> viewWhite;
346 device()->CreateRenderTargetView(mTexture, nullptr, getter_AddRefs(viewBlack));
347 device()->CreateRenderTargetView(mTextureOnWhite, nullptr, getter_AddRefs(viewWhite));
349 D3D10_RECT oldScissor;
350 UINT numRects = 1;
351 device()->RSGetScissorRects(&numRects, &oldScissor);
353 D3D10_TEXTURE2D_DESC desc;
354 mTexture->GetDesc(&desc);
356 D3D10_RECT scissor = { 0, 0, desc.Width, desc.Height };
357 device()->RSSetScissorRects(1, &scissor);
359 mD3DManager->SetupInputAssembler();
360 nsIntSize oldVP = mD3DManager->GetViewport();
362 mD3DManager->SetViewport(nsIntSize(desc.Width, desc.Height));
364 ID3D10RenderTargetView *views[2] = { viewBlack, viewWhite };
365 device()->OMSetRenderTargets(2, views, nullptr);
367 gfx3DMatrix transform;
368 transform.Translate(gfxPoint3D(-aOffset.x, -aOffset.y, 0));
369 void* raw = &const_cast<gfx3DMatrix&>(transform)._11;
370 effect()->GetVariableByName("mLayerTransform")->SetRawValue(raw, 0, 64);
372 ID3D10EffectTechnique *technique =
373 effect()->GetTechniqueByName("PrepareAlphaExtractionTextures");
375 nsIntRegionRectIterator iter(aRegion);
377 const nsIntRect *iterRect;
378 while ((iterRect = iter.Next())) {
379 effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
380 ShaderConstantRectD3D10(
381 (float)iterRect->x,
382 (float)iterRect->y,
383 (float)iterRect->width,
384 (float)iterRect->height)
385 );
387 technique->GetPassByIndex(0)->Apply(0);
388 device()->Draw(4, 0);
389 }
391 views[0] = oldRT;
392 device()->OMSetRenderTargets(1, views, nullptr);
393 mD3DManager->SetViewport(oldVP);
394 device()->RSSetScissorRects(1, &oldScissor);
395 }
396 }
398 void
399 ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode)
400 {
401 nsIntRect visibleRect = mVisibleRegion.GetBounds();
403 if (!mD2DSurface && !mDrawTarget) {
404 return;
405 }
407 aRegion.SimplifyOutwardByArea(100 * 100);
409 nsRefPtr<gfxASurface> destinationSurface;
411 if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
412 FillTexturesBlackWhite(aRegion, visibleRect.TopLeft());
413 } else {
414 destinationSurface = mD2DSurface;
415 }
417 MOZ_ASSERT(mDrawTarget);
418 nsRefPtr<gfxContext> context = new gfxContext(mDrawTarget);
420 context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y));
421 if (aMode == SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA) {
422 nsIntRegionRectIterator iter(aRegion);
423 const nsIntRect *iterRect;
424 while ((iterRect = iter.Next())) {
425 mDrawTarget->ClearRect(Rect(iterRect->x, iterRect->y, iterRect->width, iterRect->height));
426 }
427 }
429 mDrawTarget->SetPermitSubpixelAA(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
431 LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
432 cbInfo.Callback(this, context, aRegion, DrawRegionClip::DRAW, nsIntRegion(), cbInfo.CallbackData);
433 }
435 void
436 ThebesLayerD3D10::CreateNewTextures(const gfx::IntSize &aSize, SurfaceMode aMode)
437 {
438 if (aSize.width == 0 || aSize.height == 0) {
439 // Nothing to do.
440 return;
441 }
443 CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
444 desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
445 desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
446 HRESULT hr;
448 if (!mTexture) {
449 hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture));
451 if (FAILED(hr)) {
452 NS_WARNING("Failed to create new texture for ThebesLayerD3D10!");
453 return;
454 }
456 hr = device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mSRView));
458 if (FAILED(hr)) {
459 NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
460 }
462 mDrawTarget = nullptr;
463 }
465 if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA && !mTextureOnWhite) {
466 hr = device()->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTextureOnWhite));
468 if (FAILED(hr)) {
469 NS_WARNING("Failed to create new texture for ThebesLayerD3D10!");
470 return;
471 }
473 hr = device()->CreateShaderResourceView(mTextureOnWhite, nullptr, getter_AddRefs(mSRViewOnWhite));
475 if (FAILED(hr)) {
476 NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
477 }
479 mDrawTarget = nullptr;
480 }
482 if (!mDrawTarget) {
483 if (aMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
484 mDrawTarget = Factory::CreateDualDrawTargetForD3D10Textures(mTexture, mTextureOnWhite, SurfaceFormat::B8G8R8X8);
485 } else {
486 mDrawTarget = Factory::CreateDrawTargetForD3D10Texture(mTexture, aMode != SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA ?
487 SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8);
488 }
490 if (!mDrawTarget) {
491 NS_WARNING("Failed to create DrawTarget for ThebesLayerD3D10.");
492 mDrawTarget = nullptr;
493 return;
494 }
495 }
496 }
498 } /* namespace layers */
499 } /* namespace mozilla */