/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DrawTargetWebglInternal.h" #include "SourceSurfaceWebgl.h" namespace mozilla::gfx { SourceSurfaceWebgl::SourceSurfaceWebgl(DrawTargetWebgl* aDT) : mFormat(aDT->GetFormat()), mSize(aDT->GetSize()), mDT(aDT), mSharedContext(aDT->mSharedContext) {} SourceSurfaceWebgl::SourceSurfaceWebgl( const RefPtr& aSharedContext) : mSharedContext(aSharedContext) {} SourceSurfaceWebgl::~SourceSurfaceWebgl() { if (mHandle) { // Signal that the texture handle is not being used now. mHandle->ClearSurface(); } } // Read back the contents of the target or texture handle for data use. inline bool SourceSurfaceWebgl::EnsureData() { if (mData) { return true; } if (!mDT) { // Assume that the target changed, so there should be a texture handle // holding a copy. Try to read data from the copy since we can't read // from the target. if (!mHandle || !mSharedContext) { return false; } mData = mSharedContext->ReadSnapshot(mHandle); } else { mData = mDT->ReadSnapshot(); } return !!mData; } uint8_t* SourceSurfaceWebgl::GetData() { if (!EnsureData()) { return nullptr; } return mData->GetData(); } int32_t SourceSurfaceWebgl::Stride() { if (!EnsureData()) { return 0; } return mData->Stride(); } bool SourceSurfaceWebgl::Map(MapType aType, MappedSurface* aMappedSurface) { if (!EnsureData()) { return false; } return mData->Map(aType, aMappedSurface); } void SourceSurfaceWebgl::Unmap() { if (mData) { mData->Unmap(); } } // Handler for when the owner DrawTargetWebgl is about to modify its internal // framebuffer, and so this snapshot must be copied into a new texture, if // possible, or read back into data, if necessary, to preserve this particular // version of the framebuffer. void SourceSurfaceWebgl::DrawTargetWillChange(bool aNeedHandle) { MOZ_ASSERT(mDT); // Only try to copy into a new texture handle if we don't already have data. // However, we still might need to immediately draw this snapshot to a WebGL // target, which would require a subsequent upload, so also copy into a new // handle even if we already have data in that case since it is faster than // uploading. if ((!mData || aNeedHandle) && !mHandle) { // Prefer copying the framebuffer to a texture if possible. mHandle = mDT->CopySnapshot(); if (mHandle) { // Link this surface to the handle. mHandle->SetSurface(this); } else { // If that fails, then try to just read the data to a surface. EnsureData(); } } mDT = nullptr; } // Handler for when the owner DrawTargetWebgl is itself being destroyed and // needs to transfer ownership of its internal backing texture to the snapshot. void SourceSurfaceWebgl::GiveTexture(RefPtr aHandle) { // If we get here, then the target still points to this surface as its // snapshot and needs to hand off its backing texture before it is destroyed. MOZ_ASSERT(mDT); MOZ_ASSERT(!mHandle); mHandle = aHandle.forget(); mHandle->SetSurface(this); mDT = nullptr; } void SourceSurfaceWebgl::SetHandle(TextureHandle* aHandle) { MOZ_ASSERT(!mHandle); mFormat = aHandle->GetFormat(); mSize = aHandle->GetSize(); mHandle = aHandle; mHandle->SetSurface(this); } // Handler for when the owner DrawTargetWebgl is destroying the cached texture // handle that has been allocated for this snapshot. void SourceSurfaceWebgl::OnUnlinkTexture(SharedContextWebgl* aContext) { // If we get here, then we must have copied a snapshot, which only happens // if the target changed. MOZ_ASSERT(!mDT); // If the snapshot was mapped before the target changed, we may have read // data instead of holding a copied texture handle. If subsequently we then // try to draw with this snapshot, we might have allocated an external texture // handle in the texture cache that still links to this snapshot and can cause // us to end up here inside OnUnlinkTexture. MOZ_ASSERT(mHandle || mData); if (!mData) { mData = aContext->ReadSnapshot(mHandle); } mHandle = nullptr; } already_AddRefed SourceSurfaceWebgl::ExtractSubrect( const IntRect& aRect) { // Ensure we have a texture source available to extract from. if (!(mDT || (mHandle && mSharedContext)) || aRect.IsEmpty() || !GetRect().Contains(aRect)) { return nullptr; } RefPtr subHandle; RefPtr sharedContext; if (mDT) { // If this is still a snapshot linked to a target, then copy from the // target. subHandle = mDT->CopySnapshot(aRect); if (!subHandle) { return nullptr; } sharedContext = mDT->mSharedContext; } else { // Otherwise, we have a handle, but we need to verify it is still linked to // a valid context. sharedContext = mSharedContext; if (!sharedContext) { return nullptr; } // Try to copy directly from the handle using the context. subHandle = sharedContext->CopySnapshot(aRect, mHandle); if (!subHandle) { return nullptr; } } RefPtr surface = new SourceSurfaceWebgl(sharedContext); surface->SetHandle(subHandle); return surface.forget(); } } // namespace mozilla::gfx