gfx/layers/client/ContentClient.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/layers/client/ContentClient.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,890 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "mozilla/layers/ContentClient.h"
    1.10 +#include "BasicLayers.h"                // for BasicLayerManager
    1.11 +#include "gfxColor.h"                   // for gfxRGBA
    1.12 +#include "gfxContext.h"                 // for gfxContext, etc
    1.13 +#include "gfxPlatform.h"                // for gfxPlatform
    1.14 +#include "gfxPrefs.h"                   // for gfxPrefs
    1.15 +#include "gfxPoint.h"                   // for gfxIntSize, gfxPoint
    1.16 +#include "gfxTeeSurface.h"              // for gfxTeeSurface
    1.17 +#include "gfxUtils.h"                   // for gfxUtils
    1.18 +#include "ipc/ShadowLayers.h"           // for ShadowLayerForwarder
    1.19 +#include "mozilla/ArrayUtils.h"         // for ArrayLength
    1.20 +#include "mozilla/gfx/2D.h"             // for DrawTarget, Factory
    1.21 +#include "mozilla/gfx/BasePoint.h"      // for BasePoint
    1.22 +#include "mozilla/gfx/BaseSize.h"       // for BaseSize
    1.23 +#include "mozilla/gfx/Rect.h"           // for Rect
    1.24 +#include "mozilla/gfx/Types.h"
    1.25 +#include "mozilla/layers/LayerManagerComposite.h"
    1.26 +#include "mozilla/layers/LayersMessages.h"  // for ThebesBufferData
    1.27 +#include "mozilla/layers/LayersTypes.h"
    1.28 +#include "nsAutoPtr.h"                  // for nsRefPtr
    1.29 +#include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING, etc
    1.30 +#include "nsISupportsImpl.h"            // for gfxContext::Release, etc
    1.31 +#include "nsIWidget.h"                  // for nsIWidget
    1.32 +#include "prenv.h"                      // for PR_GetEnv
    1.33 +#ifdef XP_WIN
    1.34 +#include "gfxWindowsPlatform.h"
    1.35 +#endif
    1.36 +#include "gfx2DGlue.h"
    1.37 +
    1.38 +namespace mozilla {
    1.39 +
    1.40 +using namespace gfx;
    1.41 +
    1.42 +namespace layers {
    1.43 +
    1.44 +static TextureFlags TextureFlagsForRotatedContentBufferFlags(uint32_t aBufferFlags)
    1.45 +{
    1.46 +  TextureFlags result = 0;
    1.47 +
    1.48 +  if (aBufferFlags & RotatedContentBuffer::BUFFER_COMPONENT_ALPHA) {
    1.49 +    result |= TEXTURE_COMPONENT_ALPHA;
    1.50 +  }
    1.51 +
    1.52 +  if (aBufferFlags & RotatedContentBuffer::ALLOW_REPEAT) {
    1.53 +    result |= TEXTURE_ALLOW_REPEAT;
    1.54 +  }
    1.55 +
    1.56 +  return result;
    1.57 +}
    1.58 +
    1.59 +
    1.60 +/* static */ TemporaryRef<ContentClient>
    1.61 +ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
    1.62 +{
    1.63 +  LayersBackend backend = aForwarder->GetCompositorBackendType();
    1.64 +  if (backend != LayersBackend::LAYERS_OPENGL &&
    1.65 +      backend != LayersBackend::LAYERS_D3D9 &&
    1.66 +      backend != LayersBackend::LAYERS_D3D11 &&
    1.67 +      backend != LayersBackend::LAYERS_BASIC) {
    1.68 +    return nullptr;
    1.69 +  }
    1.70 +
    1.71 +  bool useDoubleBuffering = false;
    1.72 +
    1.73 +#ifdef XP_WIN
    1.74 +  if (backend == LayersBackend::LAYERS_D3D11) {
    1.75 +    useDoubleBuffering = !!gfxWindowsPlatform::GetPlatform()->GetD2DDevice();
    1.76 +  } else
    1.77 +#endif
    1.78 +  {
    1.79 +    useDoubleBuffering = (LayerManagerComposite::SupportsDirectTexturing() &&
    1.80 +                         backend != LayersBackend::LAYERS_D3D9) ||
    1.81 +                         backend == LayersBackend::LAYERS_BASIC;
    1.82 +  }
    1.83 +
    1.84 +  if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) {
    1.85 +    return new ContentClientDoubleBuffered(aForwarder);
    1.86 +  }
    1.87 +#ifdef XP_MACOSX
    1.88 +  if (backend == LayersBackend::LAYERS_OPENGL) {
    1.89 +    return new ContentClientIncremental(aForwarder);
    1.90 +  }
    1.91 +#endif
    1.92 +  return new ContentClientSingleBuffered(aForwarder);
    1.93 +}
    1.94 +
    1.95 +void
    1.96 +ContentClient::EndPaint()
    1.97 +{
    1.98 +  // It is very important that this is called after any overridden EndPaint behaviour,
    1.99 +  // because destroying textures is a three stage process:
   1.100 +  // 1. We are done with the buffer and move it to ContentClient::mOldTextures,
   1.101 +  // that happens in DestroyBuffers which is may be called indirectly from
   1.102 +  // PaintThebes.
   1.103 +  // 2. The content client calls RemoveTextureClient on the texture clients in
   1.104 +  // mOldTextures and forgets them. They then become invalid. The compositable
   1.105 +  // client keeps a record of IDs. This happens in EndPaint.
   1.106 +  // 3. An IPC message is sent to destroy the corresponding texture host. That
   1.107 +  // happens from OnTransaction.
   1.108 +  // It is important that these steps happen in order.
   1.109 +  OnTransaction();
   1.110 +}
   1.111 +
   1.112 +// We pass a null pointer for the ContentClient Forwarder argument, which means
   1.113 +// this client will not have a ContentHost on the other side.
   1.114 +ContentClientBasic::ContentClientBasic()
   1.115 +  : ContentClient(nullptr)
   1.116 +  , RotatedContentBuffer(ContainsVisibleBounds)
   1.117 +{}
   1.118 +
   1.119 +void
   1.120 +ContentClientBasic::CreateBuffer(ContentType aType,
   1.121 +                                 const nsIntRect& aRect,
   1.122 +                                 uint32_t aFlags,
   1.123 +                                 RefPtr<gfx::DrawTarget>* aBlackDT,
   1.124 +                                 RefPtr<gfx::DrawTarget>* aWhiteDT)
   1.125 +{
   1.126 +  MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA));
   1.127 +  gfxImageFormat format =
   1.128 +    gfxPlatform::GetPlatform()->OptimalFormatForContent(aType);
   1.129 +
   1.130 +  *aBlackDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
   1.131 +    IntSize(aRect.width, aRect.height),
   1.132 +    ImageFormatToSurfaceFormat(format));
   1.133 +}
   1.134 +
   1.135 +void
   1.136 +ContentClientRemoteBuffer::DestroyBuffers()
   1.137 +{
   1.138 +  if (!mTextureClient) {
   1.139 +    return;
   1.140 +  }
   1.141 +
   1.142 +  mOldTextures.AppendElement(mTextureClient);
   1.143 +  mTextureClient = nullptr;
   1.144 +  if (mTextureClientOnWhite) {
   1.145 +    mOldTextures.AppendElement(mTextureClientOnWhite);
   1.146 +    mTextureClientOnWhite = nullptr;
   1.147 +  }
   1.148 +
   1.149 +  DestroyFrontBuffer();
   1.150 +}
   1.151 +
   1.152 +void
   1.153 +ContentClientRemoteBuffer::BeginPaint()
   1.154 +{
   1.155 +  // XXX: So we might not have a TextureClient yet.. because it will
   1.156 +  // only be created by CreateBuffer.. which will deliver a locked surface!.
   1.157 +  if (mTextureClient) {
   1.158 +    SetBufferProvider(mTextureClient);
   1.159 +  }
   1.160 +  if (mTextureClientOnWhite) {
   1.161 +    SetBufferProviderOnWhite(mTextureClientOnWhite);
   1.162 +  }
   1.163 +}
   1.164 +
   1.165 +void
   1.166 +ContentClientRemoteBuffer::EndPaint()
   1.167 +{
   1.168 +  // XXX: We might still not have a texture client if PaintThebes
   1.169 +  // decided we didn't need one yet because the region to draw was empty.
   1.170 +  SetBufferProvider(nullptr);
   1.171 +  SetBufferProviderOnWhite(nullptr);
   1.172 +  for (unsigned i = 0; i< mOldTextures.Length(); ++i) {
   1.173 +    if (mOldTextures[i]->IsLocked()) {
   1.174 +      mOldTextures[i]->Unlock();
   1.175 +    }
   1.176 +  }
   1.177 +  mOldTextures.Clear();
   1.178 +
   1.179 +  if (mTextureClient && mTextureClient->IsLocked()) {
   1.180 +    mTextureClient->Unlock();
   1.181 +  }
   1.182 +  if (mTextureClientOnWhite && mTextureClientOnWhite->IsLocked()) {
   1.183 +    mTextureClientOnWhite->Unlock();
   1.184 +  }
   1.185 +  ContentClientRemote::EndPaint();
   1.186 +}
   1.187 +
   1.188 +bool
   1.189 +ContentClientRemoteBuffer::CreateAndAllocateTextureClient(RefPtr<TextureClient>& aClient,
   1.190 +                                                          TextureFlags aFlags)
   1.191 +{
   1.192 +  // gfx::BackendType::NONE means fallback to the content backend
   1.193 +  aClient = CreateTextureClientForDrawing(mSurfaceFormat,
   1.194 +                                          mTextureInfo.mTextureFlags | aFlags,
   1.195 +                                          gfx::BackendType::NONE,
   1.196 +                                          mSize);
   1.197 +  if (!aClient) {
   1.198 +    return false;
   1.199 +  }
   1.200 +
   1.201 +  if (!aClient->AllocateForSurface(mSize, ALLOC_CLEAR_BUFFER)) {
   1.202 +    aClient = CreateTextureClientForDrawing(mSurfaceFormat,
   1.203 +                mTextureInfo.mTextureFlags | TEXTURE_ALLOC_FALLBACK | aFlags,
   1.204 +                gfx::BackendType::NONE,
   1.205 +                mSize);
   1.206 +    if (!aClient) {
   1.207 +      return false;
   1.208 +    }
   1.209 +    if (!aClient->AllocateForSurface(mSize, ALLOC_CLEAR_BUFFER)) {
   1.210 +      NS_WARNING("Could not allocate texture client");
   1.211 +      aClient = nullptr;
   1.212 +      return false;
   1.213 +    }
   1.214 +  }
   1.215 +
   1.216 +  NS_WARN_IF_FALSE(aClient->IsValid(), "Created an invalid texture client");
   1.217 +  return true;
   1.218 +}
   1.219 +
   1.220 +void
   1.221 +ContentClientRemoteBuffer::BuildTextureClients(SurfaceFormat aFormat,
   1.222 +                                               const nsIntRect& aRect,
   1.223 +                                               uint32_t aFlags)
   1.224 +{
   1.225 +  // If we hit this assertion, then it might be due to an empty transaction
   1.226 +  // followed by a real transaction. Our buffers should be created (but not
   1.227 +  // painted in the empty transaction) and then painted (but not created) in the
   1.228 +  // real transaction. That is kind of fragile, and this assert will catch
   1.229 +  // circumstances where we screw that up, e.g., by unnecessarily recreating our
   1.230 +  // buffers.
   1.231 +  NS_ABORT_IF_FALSE(!mIsNewBuffer,
   1.232 +                    "Bad! Did we create a buffer twice without painting?");
   1.233 +
   1.234 +  mIsNewBuffer = true;
   1.235 +
   1.236 +  DestroyBuffers();
   1.237 +
   1.238 +  mSurfaceFormat = aFormat;
   1.239 +  mSize = gfx::IntSize(aRect.width, aRect.height);
   1.240 +  mTextureInfo.mTextureFlags = TextureFlagsForRotatedContentBufferFlags(aFlags);
   1.241 +
   1.242 +  if (!CreateAndAllocateTextureClient(mTextureClient, TEXTURE_ON_BLACK) ||
   1.243 +      !AddTextureClient(mTextureClient)) {
   1.244 +    AbortTextureClientCreation();
   1.245 +    return;
   1.246 +  }
   1.247 +
   1.248 +  if (aFlags & BUFFER_COMPONENT_ALPHA) {
   1.249 +    if (!CreateAndAllocateTextureClient(mTextureClientOnWhite, TEXTURE_ON_WHITE) ||
   1.250 +        !AddTextureClient(mTextureClientOnWhite)) {
   1.251 +      AbortTextureClientCreation();
   1.252 +      return;
   1.253 +    }
   1.254 +    mTextureInfo.mTextureFlags |= TEXTURE_COMPONENT_ALPHA;
   1.255 +  }
   1.256 +
   1.257 +  CreateFrontBuffer(aRect);
   1.258 +}
   1.259 +
   1.260 +void
   1.261 +ContentClientRemoteBuffer::CreateBuffer(ContentType aType,
   1.262 +                                        const nsIntRect& aRect,
   1.263 +                                        uint32_t aFlags,
   1.264 +                                        RefPtr<gfx::DrawTarget>* aBlackDT,
   1.265 +                                        RefPtr<gfx::DrawTarget>* aWhiteDT)
   1.266 +{
   1.267 +  BuildTextureClients(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType), aRect, aFlags);
   1.268 +  if (!mTextureClient) {
   1.269 +    return;
   1.270 +  }
   1.271 +
   1.272 +  // We just created the textures and we are about to get their draw targets
   1.273 +  // so we have to lock them here.
   1.274 +  DebugOnly<bool> locked = mTextureClient->Lock(OPEN_READ_WRITE);
   1.275 +  MOZ_ASSERT(locked, "Could not lock the TextureClient");
   1.276 +
   1.277 +  *aBlackDT = mTextureClient->GetAsDrawTarget();
   1.278 +  if (aFlags & BUFFER_COMPONENT_ALPHA) {
   1.279 +    locked = mTextureClientOnWhite->Lock(OPEN_READ_WRITE);
   1.280 +    MOZ_ASSERT(locked, "Could not lock the second TextureClient for component alpha");
   1.281 +
   1.282 +    *aWhiteDT = mTextureClientOnWhite->GetAsDrawTarget();
   1.283 +  }
   1.284 +}
   1.285 +
   1.286 +nsIntRegion
   1.287 +ContentClientRemoteBuffer::GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
   1.288 +                                            const nsIntRegion& aVisibleRegion,
   1.289 +                                            bool aDidSelfCopy)
   1.290 +{
   1.291 +  nsIntRegion updatedRegion;
   1.292 +  if (mIsNewBuffer || aDidSelfCopy) {
   1.293 +    // A buffer reallocation clears both buffers. The front buffer has all the
   1.294 +    // content by now, but the back buffer is still clear. Here, in effect, we
   1.295 +    // are saying to copy all of the pixels of the front buffer to the back.
   1.296 +    // Also when we self-copied in the buffer, the buffer space
   1.297 +    // changes and some changed buffer content isn't reflected in the
   1.298 +    // draw or invalidate region (on purpose!).  When this happens, we
   1.299 +    // need to read back the entire buffer too.
   1.300 +    updatedRegion = aVisibleRegion;
   1.301 +    mIsNewBuffer = false;
   1.302 +  } else {
   1.303 +    updatedRegion = aRegionToDraw;
   1.304 +  }
   1.305 +
   1.306 +  NS_ASSERTION(BufferRect().Contains(aRegionToDraw.GetBounds()),
   1.307 +               "Update outside of buffer rect!");
   1.308 +  NS_ABORT_IF_FALSE(mTextureClient, "should have a back buffer by now");
   1.309 +
   1.310 +  return updatedRegion;
   1.311 +}
   1.312 +
   1.313 +void
   1.314 +ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw,
   1.315 +                                   const nsIntRegion& aVisibleRegion,
   1.316 +                                   bool aDidSelfCopy)
   1.317 +{
   1.318 +  nsIntRegion updatedRegion = GetUpdatedRegion(aRegionToDraw,
   1.319 +                                               aVisibleRegion,
   1.320 +                                               aDidSelfCopy);
   1.321 +
   1.322 +  MOZ_ASSERT(mTextureClient);
   1.323 +  if (mTextureClientOnWhite) {
   1.324 +    mForwarder->UseComponentAlphaTextures(this, mTextureClient,
   1.325 +                                          mTextureClientOnWhite);
   1.326 +  } else {
   1.327 +    mForwarder->UseTexture(this, mTextureClient);
   1.328 +  }
   1.329 +  mForwarder->UpdateTextureRegion(this,
   1.330 +                                  ThebesBufferData(BufferRect(),
   1.331 +                                                   BufferRotation()),
   1.332 +                                  updatedRegion);
   1.333 +}
   1.334 +
   1.335 +void
   1.336 +ContentClientRemoteBuffer::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
   1.337 +{
   1.338 +  MOZ_ASSERT(mTextureClient);
   1.339 +  mFrontAndBackBufferDiffer = true;
   1.340 +}
   1.341 +
   1.342 +void
   1.343 +ContentClientDoubleBuffered::CreateFrontBuffer(const nsIntRect& aBufferRect)
   1.344 +{
   1.345 +  if (!CreateAndAllocateTextureClient(mFrontClient, TEXTURE_ON_BLACK) ||
   1.346 +      !AddTextureClient(mFrontClient)) {
   1.347 +    AbortTextureClientCreation();
   1.348 +    return;
   1.349 +  }
   1.350 +  if (mTextureInfo.mTextureFlags & TEXTURE_COMPONENT_ALPHA) {
   1.351 +    if (!CreateAndAllocateTextureClient(mFrontClientOnWhite, TEXTURE_ON_WHITE) ||
   1.352 +        !AddTextureClient(mFrontClientOnWhite)) {
   1.353 +      AbortTextureClientCreation();
   1.354 +      return;
   1.355 +    }
   1.356 +  }
   1.357 +
   1.358 +  mFrontBufferRect = aBufferRect;
   1.359 +  mFrontBufferRotation = nsIntPoint();
   1.360 +}
   1.361 +
   1.362 +void
   1.363 +ContentClientDoubleBuffered::DestroyFrontBuffer()
   1.364 +{
   1.365 +  MOZ_ASSERT(mFrontClient);
   1.366 +
   1.367 +  mOldTextures.AppendElement(mFrontClient);
   1.368 +  mFrontClient = nullptr;
   1.369 +  if (mFrontClientOnWhite) {
   1.370 +    mOldTextures.AppendElement(mFrontClientOnWhite);
   1.371 +    mFrontClientOnWhite = nullptr;
   1.372 +  }
   1.373 +}
   1.374 +
   1.375 +void
   1.376 +ContentClientDoubleBuffered::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
   1.377 +{
   1.378 +  mFrontUpdatedRegion = aFrontUpdatedRegion;
   1.379 +
   1.380 +  RefPtr<TextureClient> oldBack = mTextureClient;
   1.381 +  mTextureClient = mFrontClient;
   1.382 +  mFrontClient = oldBack;
   1.383 +
   1.384 +  oldBack = mTextureClientOnWhite;
   1.385 +  mTextureClientOnWhite = mFrontClientOnWhite;
   1.386 +  mFrontClientOnWhite = oldBack;
   1.387 +
   1.388 +  nsIntRect oldBufferRect = mBufferRect;
   1.389 +  mBufferRect = mFrontBufferRect;
   1.390 +  mFrontBufferRect = oldBufferRect;
   1.391 +
   1.392 +  nsIntPoint oldBufferRotation = mBufferRotation;
   1.393 +  mBufferRotation = mFrontBufferRotation;
   1.394 +  mFrontBufferRotation = oldBufferRotation;
   1.395 +
   1.396 +  MOZ_ASSERT(mFrontClient);
   1.397 +
   1.398 +  ContentClientRemoteBuffer::SwapBuffers(aFrontUpdatedRegion);
   1.399 +}
   1.400 +
   1.401 +void
   1.402 +ContentClientDoubleBuffered::BeginPaint()
   1.403 +{
   1.404 +  ContentClientRemoteBuffer::BeginPaint();
   1.405 +
   1.406 +  mIsNewBuffer = false;
   1.407 +
   1.408 +  if (!mFrontAndBackBufferDiffer) {
   1.409 +    return;
   1.410 +  }
   1.411 +
   1.412 +  if (mDidSelfCopy) {
   1.413 +    // We can't easily draw our front buffer into us, since we're going to be
   1.414 +    // copying stuff around anyway it's easiest if we just move our situation
   1.415 +    // to non-rotated while we're at it. If this situation occurs we'll have
   1.416 +    // hit a self-copy path in PaintThebes before as well anyway.
   1.417 +    mBufferRect.MoveTo(mFrontBufferRect.TopLeft());
   1.418 +    mBufferRotation = nsIntPoint();
   1.419 +    return;
   1.420 +  }
   1.421 +  mBufferRect = mFrontBufferRect;
   1.422 +  mBufferRotation = mFrontBufferRotation;
   1.423 +}
   1.424 +
   1.425 +// Sync front/back buffers content
   1.426 +// After executing, the new back buffer has the same (interesting) pixels as
   1.427 +// the new front buffer, and mValidRegion et al. are correct wrt the new
   1.428 +// back buffer (i.e. as they were for the old back buffer)
   1.429 +void
   1.430 +ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
   1.431 +{
   1.432 +  if (mTextureClient) {
   1.433 +    DebugOnly<bool> locked = mTextureClient->Lock(OPEN_READ_WRITE);
   1.434 +    MOZ_ASSERT(locked);
   1.435 +  }
   1.436 +  if (mTextureClientOnWhite) {
   1.437 +    DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OPEN_READ_WRITE);
   1.438 +    MOZ_ASSERT(locked);
   1.439 +  }
   1.440 +
   1.441 +  if (!mFrontAndBackBufferDiffer) {
   1.442 +    MOZ_ASSERT(!mDidSelfCopy, "If we have to copy the world, then our buffers are different, right?");
   1.443 +    return;
   1.444 +  }
   1.445 +  MOZ_ASSERT(mFrontClient);
   1.446 +
   1.447 +  MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
   1.448 +                  this,
   1.449 +                  mFrontUpdatedRegion.GetBounds().x,
   1.450 +                  mFrontUpdatedRegion.GetBounds().y,
   1.451 +                  mFrontUpdatedRegion.GetBounds().width,
   1.452 +                  mFrontUpdatedRegion.GetBounds().height));
   1.453 +
   1.454 +  mFrontAndBackBufferDiffer = false;
   1.455 +
   1.456 +  nsIntRegion updateRegion = mFrontUpdatedRegion;
   1.457 +  if (mDidSelfCopy) {
   1.458 +    mDidSelfCopy = false;
   1.459 +    updateRegion = mBufferRect;
   1.460 +  }
   1.461 +
   1.462 +  // No point in sync'ing what we are going to draw over anyway. And if there is
   1.463 +  // nothing to sync at all, there is nothing to do and we can go home early.
   1.464 +  updateRegion.Sub(updateRegion, aRegionToDraw);
   1.465 +  if (updateRegion.IsEmpty()) {
   1.466 +    return;
   1.467 +  }
   1.468 +
   1.469 +  // We need to ensure that we lock these two buffers in the same
   1.470 +  // order as the compositor to prevent deadlocks.
   1.471 +  if (!mFrontClient->Lock(OPEN_READ_ONLY)) {
   1.472 +    return;
   1.473 +  }
   1.474 +  if (mFrontClientOnWhite &&
   1.475 +      !mFrontClientOnWhite->Lock(OPEN_READ_ONLY)) {
   1.476 +    mFrontClient->Unlock();
   1.477 +    return;
   1.478 +  }
   1.479 +  {
   1.480 +    // Restrict the DrawTargets and frontBuffer to a scope to make
   1.481 +    // sure there is no more external references to the DrawTargets
   1.482 +    // when we Unlock the TextureClients.
   1.483 +    RefPtr<DrawTarget> dt = mFrontClient->GetAsDrawTarget();
   1.484 +    RefPtr<DrawTarget> dtOnWhite = mFrontClientOnWhite
   1.485 +      ? mFrontClientOnWhite->GetAsDrawTarget()
   1.486 +      : nullptr;
   1.487 +    RotatedBuffer frontBuffer(dt,
   1.488 +                              dtOnWhite,
   1.489 +                              mFrontBufferRect,
   1.490 +                              mFrontBufferRotation);
   1.491 +    UpdateDestinationFrom(frontBuffer, updateRegion);
   1.492 +  }
   1.493 +
   1.494 +  mFrontClient->Unlock();
   1.495 +  if (mFrontClientOnWhite) {
   1.496 +    mFrontClientOnWhite->Unlock();
   1.497 +  }
   1.498 +}
   1.499 +
   1.500 +void
   1.501 +ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
   1.502 +                                                   const nsIntRegion& aUpdateRegion)
   1.503 +{
   1.504 +  DrawIterator iter;
   1.505 +  while (DrawTarget* destDT =
   1.506 +    BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
   1.507 +    bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
   1.508 +    if (isClippingCheap) {
   1.509 +      gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
   1.510 +    }
   1.511 +
   1.512 +    aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
   1.513 +    if (isClippingCheap) {
   1.514 +      destDT->PopClip();
   1.515 +    }
   1.516 +    // Flush the destination before the sources become inaccessible (Unlock).
   1.517 +    destDT->Flush();
   1.518 +    ReturnDrawTargetToBuffer(destDT);
   1.519 +  }
   1.520 +
   1.521 +  if (aSource.HaveBufferOnWhite()) {
   1.522 +    MOZ_ASSERT(HaveBufferOnWhite());
   1.523 +    DrawIterator whiteIter;
   1.524 +    while (DrawTarget* destDT =
   1.525 +      BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
   1.526 +      bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
   1.527 +      if (isClippingCheap) {
   1.528 +        gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
   1.529 +      }
   1.530 +
   1.531 +      aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
   1.532 +      if (isClippingCheap) {
   1.533 +        destDT->PopClip();
   1.534 +      }
   1.535 +      // Flush the destination before the sources become inaccessible (Unlock).
   1.536 +      destDT->Flush();
   1.537 +      ReturnDrawTargetToBuffer(destDT);
   1.538 +    }
   1.539 +  }
   1.540 +}
   1.541 +
   1.542 +void
   1.543 +ContentClientSingleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
   1.544 +{
   1.545 +  if (mTextureClient) {
   1.546 +    DebugOnly<bool> locked = mTextureClient->Lock(OPEN_READ_WRITE);
   1.547 +    MOZ_ASSERT(locked);
   1.548 +  }
   1.549 +  if (mTextureClientOnWhite) {
   1.550 +    DebugOnly<bool> locked = mTextureClientOnWhite->Lock(OPEN_READ_WRITE);
   1.551 +    MOZ_ASSERT(locked);
   1.552 +  }
   1.553 +}
   1.554 +
   1.555 +static void
   1.556 +WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
   1.557 +{
   1.558 +  if (*aRotationPoint < 0) {
   1.559 +    *aRotationPoint += aSize;
   1.560 +  } else if (*aRotationPoint >= aSize) {
   1.561 +    *aRotationPoint -= aSize;
   1.562 +  }
   1.563 +}
   1.564 +
   1.565 +static void
   1.566 +FillSurface(DrawTarget* aDT, const nsIntRegion& aRegion,
   1.567 +            const nsIntPoint& aOffset, const gfxRGBA& aColor)
   1.568 +{
   1.569 +  nsIntRegionRectIterator iter(aRegion);
   1.570 +  const nsIntRect* r;
   1.571 +  while ((r = iter.Next()) != nullptr) {
   1.572 +    aDT->FillRect(Rect(r->x - aOffset.x, r->y - aOffset.y,
   1.573 +                       r->width, r->height),
   1.574 +                  ColorPattern(ToColor(aColor)));
   1.575 +  }
   1.576 +}
   1.577 +
   1.578 +RotatedContentBuffer::PaintState
   1.579 +ContentClientIncremental::BeginPaintBuffer(ThebesLayer* aLayer,
   1.580 +                                           uint32_t aFlags)
   1.581 +{
   1.582 +  mTextureInfo.mDeprecatedTextureHostFlags = 0;
   1.583 +  PaintState result;
   1.584 +  // We need to disable rotation if we're going to be resampled when
   1.585 +  // drawing, because we might sample across the rotation boundary.
   1.586 +  bool canHaveRotation =  !(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE);
   1.587 +
   1.588 +  nsIntRegion validRegion = aLayer->GetValidRegion();
   1.589 +
   1.590 +  bool canUseOpaqueSurface = aLayer->CanUseOpaqueSurface();
   1.591 +  ContentType contentType =
   1.592 +    canUseOpaqueSurface ? gfxContentType::COLOR :
   1.593 +                          gfxContentType::COLOR_ALPHA;
   1.594 +
   1.595 +  SurfaceMode mode;
   1.596 +  nsIntRegion neededRegion;
   1.597 +  bool canReuseBuffer;
   1.598 +  nsIntRect destBufferRect;
   1.599 +
   1.600 +  while (true) {
   1.601 +    mode = aLayer->GetSurfaceMode();
   1.602 +    neededRegion = aLayer->GetVisibleRegion();
   1.603 +    // If we're going to resample, we need a buffer that's in clamp mode.
   1.604 +    canReuseBuffer = neededRegion.GetBounds().Size() <= mBufferRect.Size() &&
   1.605 +      mHasBuffer &&
   1.606 +      (!(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) ||
   1.607 +       !(mTextureInfo.mTextureFlags & TEXTURE_ALLOW_REPEAT));
   1.608 +
   1.609 +    if (canReuseBuffer) {
   1.610 +      if (mBufferRect.Contains(neededRegion.GetBounds())) {
   1.611 +        // We don't need to adjust mBufferRect.
   1.612 +        destBufferRect = mBufferRect;
   1.613 +      } else {
   1.614 +        // The buffer's big enough but doesn't contain everything that's
   1.615 +        // going to be visible. We'll move it.
   1.616 +        destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
   1.617 +      }
   1.618 +    } else {
   1.619 +      destBufferRect = neededRegion.GetBounds();
   1.620 +    }
   1.621 +
   1.622 +    if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
   1.623 +      if (!gfxPrefs::ComponentAlphaEnabled() ||
   1.624 +          !aLayer->GetParent() ||
   1.625 +          !aLayer->GetParent()->SupportsComponentAlphaChildren()) {
   1.626 +        mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
   1.627 +      } else {
   1.628 +        contentType = gfxContentType::COLOR;
   1.629 +      }
   1.630 +    }
   1.631 +
   1.632 +    if ((aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) &&
   1.633 +        (!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
   1.634 +         neededRegion.GetNumRects() > 1)) {
   1.635 +      // The area we add to neededRegion might not be painted opaquely
   1.636 +      if (mode == SurfaceMode::SURFACE_OPAQUE) {
   1.637 +        contentType = gfxContentType::COLOR_ALPHA;
   1.638 +        mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
   1.639 +      }
   1.640 +      // For component alpha layers, we leave contentType as gfxContentType::COLOR.
   1.641 +
   1.642 +      // We need to validate the entire buffer, to make sure that only valid
   1.643 +      // pixels are sampled
   1.644 +      neededRegion = destBufferRect;
   1.645 +    }
   1.646 +
   1.647 +    if (mHasBuffer &&
   1.648 +        (mContentType != contentType ||
   1.649 +         (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mHasBufferOnWhite)) {
   1.650 +      // We're effectively clearing the valid region, so we need to draw
   1.651 +      // the entire needed region now.
   1.652 +      result.mRegionToInvalidate = aLayer->GetValidRegion();
   1.653 +      validRegion.SetEmpty();
   1.654 +      mHasBuffer = false;
   1.655 +      mHasBufferOnWhite = false;
   1.656 +      mBufferRect.SetRect(0, 0, 0, 0);
   1.657 +      mBufferRotation.MoveTo(0, 0);
   1.658 +      // Restart decision process with the cleared buffer. We can only go
   1.659 +      // around the loop one more iteration, since mTexImage is null now.
   1.660 +      continue;
   1.661 +    }
   1.662 +
   1.663 +    break;
   1.664 +  }
   1.665 +
   1.666 +  result.mRegionToDraw.Sub(neededRegion, validRegion);
   1.667 +  if (result.mRegionToDraw.IsEmpty())
   1.668 +    return result;
   1.669 +
   1.670 +  if (destBufferRect.width > mForwarder->GetMaxTextureSize() ||
   1.671 +      destBufferRect.height > mForwarder->GetMaxTextureSize()) {
   1.672 +    return result;
   1.673 +  }
   1.674 +
   1.675 +  // BlitTextureImage depends on the FBO texture target being
   1.676 +  // TEXTURE_2D.  This isn't the case on some older X1600-era Radeons.
   1.677 +  if (!mForwarder->SupportsTextureBlitting() ||
   1.678 +      !mForwarder->SupportsPartialUploads()) {
   1.679 +    result.mRegionToDraw = neededRegion;
   1.680 +    validRegion.SetEmpty();
   1.681 +    mHasBuffer = false;
   1.682 +    mHasBufferOnWhite = false;
   1.683 +    mBufferRect.SetRect(0, 0, 0, 0);
   1.684 +    mBufferRotation.MoveTo(0, 0);
   1.685 +    canReuseBuffer = false;
   1.686 +  }
   1.687 +
   1.688 +  nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
   1.689 +  bool createdBuffer = false;
   1.690 +
   1.691 +  uint32_t bufferFlags = canHaveRotation ? TEXTURE_ALLOW_REPEAT : 0;
   1.692 +  if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
   1.693 +    bufferFlags |= TEXTURE_COMPONENT_ALPHA;
   1.694 +  }
   1.695 +  if (canReuseBuffer) {
   1.696 +    nsIntRect keepArea;
   1.697 +    if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
   1.698 +      // Set mBufferRotation so that the pixels currently in mBuffer
   1.699 +      // will still be rendered in the right place when mBufferRect
   1.700 +      // changes to destBufferRect.
   1.701 +      nsIntPoint newRotation = mBufferRotation +
   1.702 +        (destBufferRect.TopLeft() - mBufferRect.TopLeft());
   1.703 +      WrapRotationAxis(&newRotation.x, mBufferRect.width);
   1.704 +      WrapRotationAxis(&newRotation.y, mBufferRect.height);
   1.705 +      NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
   1.706 +                   "newRotation out of bounds");
   1.707 +      int32_t xBoundary = destBufferRect.XMost() - newRotation.x;
   1.708 +      int32_t yBoundary = destBufferRect.YMost() - newRotation.y;
   1.709 +      if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
   1.710 +          (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) ||
   1.711 +          (newRotation != nsIntPoint(0,0) && !canHaveRotation)) {
   1.712 +        // The stuff we need to redraw will wrap around an edge of the
   1.713 +        // buffer, so we will need to do a self-copy
   1.714 +        // If mBufferRotation == nsIntPoint(0,0) we could do a real
   1.715 +        // self-copy but we're not going to do that in GL yet.
   1.716 +        // We can't do a real self-copy because the buffer is rotated.
   1.717 +        // So allocate a new buffer for the destination.
   1.718 +        destBufferRect = neededRegion.GetBounds();
   1.719 +        createdBuffer = true;
   1.720 +      } else {
   1.721 +        mBufferRect = destBufferRect;
   1.722 +        mBufferRotation = newRotation;
   1.723 +      }
   1.724 +    } else {
   1.725 +      // No pixels are going to be kept. The whole visible region
   1.726 +      // will be redrawn, so we don't need to copy anything, so we don't
   1.727 +      // set destBuffer.
   1.728 +      mBufferRect = destBufferRect;
   1.729 +      mBufferRotation = nsIntPoint(0,0);
   1.730 +    }
   1.731 +  } else {
   1.732 +    // The buffer's not big enough, so allocate a new one
   1.733 +    createdBuffer = true;
   1.734 +  }
   1.735 +  NS_ASSERTION(!(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) ||
   1.736 +               destBufferRect == neededRegion.GetBounds(),
   1.737 +               "If we're resampling, we need to validate the entire buffer");
   1.738 +
   1.739 +  if (!createdBuffer && !mHasBuffer) {
   1.740 +    return result;
   1.741 +  }
   1.742 +
   1.743 +  if (createdBuffer) {
   1.744 +    if (mHasBuffer &&
   1.745 +        (mode != SurfaceMode::SURFACE_COMPONENT_ALPHA || mHasBufferOnWhite)) {
   1.746 +      mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_COPY_PREVIOUS;
   1.747 +    }
   1.748 +
   1.749 +    mHasBuffer = true;
   1.750 +    if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
   1.751 +      mHasBufferOnWhite = true;
   1.752 +    }
   1.753 +    mBufferRect = destBufferRect;
   1.754 +    mBufferRotation = nsIntPoint(0,0);
   1.755 +    NotifyBufferCreated(contentType, bufferFlags);
   1.756 +  }
   1.757 +
   1.758 +  NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0),
   1.759 +               "Rotation disabled, but we have nonzero rotation?");
   1.760 +
   1.761 +  nsIntRegion invalidate;
   1.762 +  invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
   1.763 +  result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
   1.764 +
   1.765 +  // If we do partial updates, we have to clip drawing to the regionToDraw.
   1.766 +  // If we don't clip, background images will be fillrect'd to the region correctly,
   1.767 +  // while text or lines will paint outside of the regionToDraw. This becomes apparent
   1.768 +  // with concave regions. Right now the scrollbars invalidate a narrow strip of the bar
   1.769 +  // although they never cover it. This leads to two draw rects, the narow strip and the actually
   1.770 +  // newly exposed area. It would be wise to fix this glitch in any way to have simpler
   1.771 +  // clip and draw regions.
   1.772 +  result.mClip = DrawRegionClip::DRAW;
   1.773 +  result.mMode = mode;
   1.774 +
   1.775 +  return result;
   1.776 +}
   1.777 +
   1.778 +DrawTarget*
   1.779 +ContentClientIncremental::BorrowDrawTargetForPainting(const PaintState& aPaintState,
   1.780 +                                                      RotatedContentBuffer::DrawIterator* aIter)
   1.781 +{
   1.782 +  if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
   1.783 +    return nullptr;
   1.784 +  }
   1.785 +
   1.786 +  if (aIter) {
   1.787 +    if (aIter->mCount++ > 0) {
   1.788 +      return nullptr;
   1.789 +    }
   1.790 +    aIter->mDrawRegion = aPaintState.mRegionToDraw;
   1.791 +  }
   1.792 +
   1.793 +  DrawTarget* result = nullptr;
   1.794 +
   1.795 +  nsIntRect drawBounds = aPaintState.mRegionToDraw.GetBounds();
   1.796 +  MOZ_ASSERT(!mLoanedDrawTarget);
   1.797 +
   1.798 +  // BeginUpdate is allowed to modify the given region,
   1.799 +  // if it wants more to be repainted than we request.
   1.800 +  if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
   1.801 +    nsIntRegion drawRegionCopy = aPaintState.mRegionToDraw;
   1.802 +    RefPtr<DrawTarget> onBlack = GetUpdateSurface(BUFFER_BLACK, drawRegionCopy);
   1.803 +    RefPtr<DrawTarget> onWhite = GetUpdateSurface(BUFFER_WHITE, aPaintState.mRegionToDraw);
   1.804 +    if (onBlack && onWhite) {
   1.805 +      NS_ASSERTION(aPaintState.mRegionToDraw == drawRegionCopy,
   1.806 +                   "BeginUpdate should always modify the draw region in the same way!");
   1.807 +      FillSurface(onBlack, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(0.0, 0.0, 0.0, 1.0));
   1.808 +      FillSurface(onWhite, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(1.0, 1.0, 1.0, 1.0));
   1.809 +      mLoanedDrawTarget = Factory::CreateDualDrawTarget(onBlack, onWhite);
   1.810 +    } else {
   1.811 +      mLoanedDrawTarget = nullptr;
   1.812 +    }
   1.813 +  } else {
   1.814 +    mLoanedDrawTarget = GetUpdateSurface(BUFFER_BLACK, aPaintState.mRegionToDraw);
   1.815 +  }
   1.816 +  if (!mLoanedDrawTarget) {
   1.817 +    NS_WARNING("unable to get context for update");
   1.818 +    return nullptr;
   1.819 +  }
   1.820 +
   1.821 +  result = mLoanedDrawTarget;
   1.822 +  mLoanedTransform = mLoanedDrawTarget->GetTransform();
   1.823 +  mLoanedTransform.Translate(-drawBounds.x, -drawBounds.y);
   1.824 +  result->SetTransform(mLoanedTransform);
   1.825 +  mLoanedTransform.Translate(drawBounds.x, drawBounds.y);
   1.826 +
   1.827 +  if (mContentType == gfxContentType::COLOR_ALPHA) {
   1.828 +    gfxUtils::ClipToRegion(result, aPaintState.mRegionToDraw);
   1.829 +    nsIntRect bounds = aPaintState.mRegionToDraw.GetBounds();
   1.830 +    result->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
   1.831 +  }
   1.832 +
   1.833 +  return result;
   1.834 +}
   1.835 +
   1.836 +void
   1.837 +ContentClientIncremental::Updated(const nsIntRegion& aRegionToDraw,
   1.838 +                                  const nsIntRegion& aVisibleRegion,
   1.839 +                                  bool aDidSelfCopy)
   1.840 +{
   1.841 +  if (IsSurfaceDescriptorValid(mUpdateDescriptor)) {
   1.842 +    mForwarder->UpdateTextureIncremental(this,
   1.843 +                                         TextureFront,
   1.844 +                                         mUpdateDescriptor,
   1.845 +                                         aRegionToDraw,
   1.846 +                                         mBufferRect,
   1.847 +                                         mBufferRotation);
   1.848 +    mUpdateDescriptor = SurfaceDescriptor();
   1.849 +  }
   1.850 +  if (IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite)) {
   1.851 +    mForwarder->UpdateTextureIncremental(this,
   1.852 +                                         TextureOnWhiteFront,
   1.853 +                                         mUpdateDescriptorOnWhite,
   1.854 +                                         aRegionToDraw,
   1.855 +                                         mBufferRect,
   1.856 +                                         mBufferRotation);
   1.857 +    mUpdateDescriptorOnWhite = SurfaceDescriptor();
   1.858 +  }
   1.859 +
   1.860 +}
   1.861 +
   1.862 +TemporaryRef<DrawTarget>
   1.863 +ContentClientIncremental::GetUpdateSurface(BufferType aType,
   1.864 +                                           const nsIntRegion& aUpdateRegion)
   1.865 +{
   1.866 +  nsIntRect rgnSize = aUpdateRegion.GetBounds();
   1.867 +  if (!mBufferRect.Contains(rgnSize)) {
   1.868 +    NS_ERROR("update outside of image");
   1.869 +    return nullptr;
   1.870 +  }
   1.871 +  SurfaceDescriptor desc;
   1.872 +  if (!mForwarder->AllocSurfaceDescriptor(rgnSize.Size().ToIntSize(),
   1.873 +                                          mContentType,
   1.874 +                                          &desc)) {
   1.875 +    NS_WARNING("creating SurfaceDescriptor failed!");
   1.876 +    Clear();
   1.877 +    return nullptr;
   1.878 +  }
   1.879 +
   1.880 +  if (aType == BUFFER_BLACK) {
   1.881 +    MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptor));
   1.882 +    mUpdateDescriptor = desc;
   1.883 +  } else {
   1.884 +    MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite));
   1.885 +    MOZ_ASSERT(aType == BUFFER_WHITE);
   1.886 +    mUpdateDescriptorOnWhite = desc;
   1.887 +  }
   1.888 +
   1.889 +  return GetDrawTargetForDescriptor(desc, gfx::BackendType::COREGRAPHICS);
   1.890 +}
   1.891 +
   1.892 +}
   1.893 +}

mercurial