gfx/layers/d3d10/ThebesLayerD3D10.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 */

mercurial