mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
7b236d5446
Differential Revision: https://phabricator.services.mozilla.com/D199626
174 lines
5.5 KiB
C++
174 lines
5.5 KiB
C++
/* -*- 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<SharedContextWebgl>& 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<TextureHandle> 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<SourceSurface> 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<TextureHandle> subHandle;
|
|
RefPtr<SharedContextWebgl> 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<SourceSurfaceWebgl> surface = new SourceSurfaceWebgl(sharedContext);
|
|
surface->SetHandle(subHandle);
|
|
return surface.forget();
|
|
}
|
|
|
|
} // namespace mozilla::gfx
|