tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SourceSurfaceWebgl.cpp (7968B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "SourceSurfaceWebgl.h"
      8 
      9 #include "DrawTargetWebglInternal.h"
     10 #include "WebGLBuffer.h"
     11 #include "mozilla/gfx/Swizzle.h"
     12 
     13 namespace mozilla::gfx {
     14 
     15 SourceSurfaceWebgl::SourceSurfaceWebgl(DrawTargetWebgl* aDT)
     16    : mFormat(aDT->GetFormat()),
     17      mSize(aDT->GetSize()),
     18      mDT(aDT),
     19      mSharedContext(aDT->mSharedContext) {}
     20 
     21 SourceSurfaceWebgl::SourceSurfaceWebgl(
     22    const RefPtr<SharedContextWebgl>& aSharedContext)
     23    : mSharedContext(aSharedContext) {}
     24 
     25 SourceSurfaceWebgl::~SourceSurfaceWebgl() {
     26  if (mHandle) {
     27    // Signal that the texture handle is not being used now.
     28    mHandle->ClearSurface();
     29  }
     30  if (mReadBuffer) {
     31    if (RefPtr<SharedContextWebgl> sharedContext = {mSharedContext}) {
     32      sharedContext->RemoveSnapshotPBO(this, mReadBuffer.forget());
     33    }
     34    mReadBuffer = nullptr;
     35  }
     36 }
     37 
     38 // Read back the contents of the target or texture handle for data use. This
     39 // may attempt a readback into a PBO for performance, unless forced to
     40 // immediately read into data.
     41 inline bool SourceSurfaceWebgl::EnsureData(bool aForce, uint8_t* aData,
     42                                           int32_t aStride) {
     43  if (mData) {
     44    if (aData) {
     45      DataSourceSurface::ScopedMap map(mData, MapType::READ);
     46      if (!map.IsMapped()) {
     47        return false;
     48      }
     49      SwizzleData(map.GetData(), map.GetStride(), mFormat, aData, aStride,
     50                  mFormat, mSize);
     51    }
     52    return true;
     53  }
     54 
     55  if (mReadBuffer) {
     56    // If there is a pending PBO readback, then copy the contents of the PBO.
     57    if (RefPtr<SharedContextWebgl> sharedContext = {mSharedContext}) {
     58      mData = sharedContext->ReadSnapshotFromPBO(mReadBuffer, mFormat, mSize,
     59                                                 aData, aStride);
     60      mOwnsData = !mData || !aData;
     61      sharedContext->RemoveSnapshotPBO(this, mReadBuffer.forget());
     62    }
     63    mReadBuffer = nullptr;
     64    return !!mData;
     65  }
     66 
     67  if (RefPtr<DrawTargetWebgl> dt = {mDT}) {
     68    if (!aForce) {
     69      mReadBuffer = dt->ReadSnapshotIntoPBO(this);
     70    }
     71    if (!mReadBuffer) {
     72      mData = dt->ReadSnapshot(aData, aStride);
     73      mOwnsData = !mData || !aData;
     74    }
     75  } else if (mHandle) {
     76    // Assume that the target changed, so there should be a texture handle
     77    // holding a copy. Try to read data from the copy since we can't read
     78    // from the target.
     79    if (RefPtr<SharedContextWebgl> sharedContext = {mSharedContext}) {
     80      if (!aForce) {
     81        mReadBuffer = sharedContext->ReadSnapshotIntoPBO(this, mHandle);
     82      }
     83      if (!mReadBuffer) {
     84        mData = sharedContext->ReadSnapshot(mHandle, aData, aStride);
     85        mOwnsData = !mData || !aData;
     86      }
     87    }
     88  }
     89  return mData || mReadBuffer;
     90 }
     91 
     92 bool SourceSurfaceWebgl::ReadDataInto(uint8_t* aData, int32_t aStride) {
     93  return EnsureData(true, aData, aStride);
     94 }
     95 
     96 bool SourceSurfaceWebgl::ForceReadFromPBO() {
     97  if (mReadBuffer && EnsureData()) {
     98    MOZ_ASSERT(!mReadBuffer);
     99    return true;
    100  }
    101  return false;
    102 }
    103 
    104 uint8_t* SourceSurfaceWebgl::GetData() {
    105  if (!EnsureData()) {
    106    return nullptr;
    107  }
    108  if (!mOwnsData) {
    109    mData = Factory::CopyDataSourceSurface(mData);
    110    mOwnsData = true;
    111  }
    112  return mData ? mData->GetData() : nullptr;
    113 }
    114 
    115 int32_t SourceSurfaceWebgl::Stride() {
    116  if (!EnsureData()) {
    117    return 0;
    118  }
    119  return mData->Stride();
    120 }
    121 
    122 bool SourceSurfaceWebgl::Map(MapType aType, MappedSurface* aMappedSurface) {
    123  if (!EnsureData()) {
    124    return false;
    125  }
    126  if (!mOwnsData && aType != MapType::READ) {
    127    mData = Factory::CopyDataSourceSurface(mData);
    128    mOwnsData = true;
    129  }
    130  return mData && mData->Map(aType, aMappedSurface);
    131 }
    132 
    133 void SourceSurfaceWebgl::Unmap() {
    134  if (mData) {
    135    mData->Unmap();
    136  }
    137 }
    138 
    139 // Handler for when the owner DrawTargetWebgl is about to modify its internal
    140 // framebuffer, and so this snapshot must be copied into a new texture, if
    141 // possible, or read back into data, if necessary, to preserve this particular
    142 // version of the framebuffer.
    143 void SourceSurfaceWebgl::DrawTargetWillChange(bool aNeedHandle) {
    144  RefPtr<DrawTargetWebgl> dt(mDT);
    145  if (!dt) {
    146    MOZ_ASSERT_UNREACHABLE("No DrawTargetWebgl for SourceSurfaceWebgl");
    147    return;
    148  }
    149  // Only try to copy into a new texture handle if we don't already have data.
    150  // However, we still might need to immediately draw this snapshot to a WebGL
    151  // target, which would require a subsequent upload, so also copy into a new
    152  // handle even if we already have data in that case since it is faster than
    153  // uploading.
    154  if ((aNeedHandle || (!mData && !mReadBuffer)) && !mHandle) {
    155    // Prefer copying the framebuffer to a texture if possible.
    156    mHandle = dt->CopySnapshot();
    157    if (mHandle) {
    158      // Link this surface to the handle.
    159      mHandle->SetSurface(this);
    160    } else {
    161      // If that fails, then try to just read the data to a surface.
    162      EnsureData(false);
    163    }
    164  }
    165  mDT = nullptr;
    166 }
    167 
    168 // Handler for when the owner DrawTargetWebgl is itself being destroyed and
    169 // needs to transfer ownership of its internal backing texture to the snapshot.
    170 void SourceSurfaceWebgl::GiveTexture(RefPtr<TextureHandle> aHandle) {
    171  // If we get here, then the target still points to this surface as its
    172  // snapshot and needs to hand off its backing texture before it is destroyed.
    173  MOZ_ASSERT(mDT);
    174  MOZ_ASSERT(!mHandle);
    175  mHandle = aHandle.forget();
    176  mHandle->SetSurface(this);
    177  mDT = nullptr;
    178 }
    179 
    180 void SourceSurfaceWebgl::SetHandle(TextureHandle* aHandle) {
    181  MOZ_ASSERT(!mHandle);
    182  mFormat = aHandle->GetFormat();
    183  mSize = aHandle->GetSize();
    184  mHandle = aHandle;
    185  mHandle->SetSurface(this);
    186 }
    187 
    188 // Handler for when the owner DrawTargetWebgl is destroying the cached texture
    189 // handle that has been allocated for this snapshot, or if the surface has
    190 // uploaded data.
    191 void SourceSurfaceWebgl::OnUnlinkTexture(SharedContextWebgl* aContext,
    192                                         TextureHandle* aHandle, bool aForce) {
    193  // If the snapshot was mapped before the target changed, we may have read
    194  // data instead of holding a copied texture handle. If subsequently we then
    195  // try to draw with this snapshot, we might have allocated an external texture
    196  // handle in the texture cache that still links to this snapshot and can cause
    197  // us to end up here inside OnUnlinkTexture.
    198  if (mHandle != aHandle) {
    199    return;
    200  }
    201  if (!mData && !mReadBuffer) {
    202    if (!aForce) {
    203      mReadBuffer = aContext->ReadSnapshotIntoPBO(this, mHandle);
    204    }
    205    if (!mReadBuffer) {
    206      mData = aContext->ReadSnapshot(mHandle);
    207      mOwnsData = true;
    208    }
    209  }
    210  mHandle = nullptr;
    211 }
    212 
    213 already_AddRefed<SourceSurface> SourceSurfaceWebgl::ExtractSubrect(
    214    const IntRect& aRect) {
    215  // Ensure the subrect is actually in bounds.
    216  if (aRect.IsEmpty() || !GetRect().Contains(aRect)) {
    217    return nullptr;
    218  }
    219  RefPtr<TextureHandle> subHandle;
    220  RefPtr<SharedContextWebgl> sharedContext;
    221  if (RefPtr<DrawTargetWebgl> dt = {mDT}) {
    222    // If this is still a snapshot linked to a target, then copy from the
    223    // target.
    224    subHandle = dt->CopySnapshot(aRect);
    225    sharedContext = dt->mSharedContext;
    226  } else if (mHandle) {
    227    // Otherwise, we have a handle, but we need to verify it is still linked to
    228    // a valid context.
    229    sharedContext = mSharedContext;
    230    if (sharedContext) {
    231      // Try to copy directly from the handle using the context.
    232      subHandle = sharedContext->CopySnapshot(aRect, mHandle);
    233    }
    234  }
    235  if (subHandle && sharedContext) {
    236    RefPtr<SourceSurfaceWebgl> surface = new SourceSurfaceWebgl(sharedContext);
    237    surface->SetHandle(subHandle);
    238    return surface.forget();
    239  }
    240  return nullptr;
    241 }
    242 
    243 }  // namespace mozilla::gfx