Bug 1771504 - Handle mapped DrawTargetWebgl snapshots that subsequently need to be drawn. r=aosmond,gfx-reviewers

If a DrawTargetWebgl's snapshot is mapped, then subsequently drawn, this can cause an assert to
trigger as we may not have a handle available when we go to unlink the cached snapshot that later
gets added to the texture cache. This assert is otherwise harmless, so we just fix the assert.

Otherwise, there are some inefficiencies with this scenario that this patch also tries to address.
When we go to draw the snapshot, DrawTargetWillChange gets invoked on the snapshot, and we can
ensure in this case the handle is copied efficiently here rather than later uploaded from mapped
data.

Differential Revision: https://phabricator.services.mozilla.com/D148102
This commit is contained in:
Lee Salzman 2022-06-02 15:27:00 +00:00
parent b1b82d16bf
commit d87f81eedd
4 changed files with 19 additions and 8 deletions

View File

@ -190,7 +190,7 @@ inline void DrawTargetWebgl::SharedContext::ClearLastTexture() {
// this target, then it should simply be destroyed. If it is a WebGL surface in
// use by something else, then special cleanup such as reusing the texture or
// copy-on-write may be possible.
void DrawTargetWebgl::ClearSnapshot(bool aCopyOnWrite) {
void DrawTargetWebgl::ClearSnapshot(bool aCopyOnWrite, bool aNeedHandle) {
if (!mSnapshot) {
return;
}
@ -204,7 +204,7 @@ void DrawTargetWebgl::ClearSnapshot(bool aCopyOnWrite) {
if (aCopyOnWrite) {
// WebGL snapshots must be notified that the framebuffer contents will be
// changing so that it can copy the data.
snapshot->DrawTargetWillChange();
snapshot->DrawTargetWillChange(aNeedHandle);
} else {
// If not copying, then give the backing texture to the surface for reuse.
snapshot->GiveTexture(
@ -769,7 +769,8 @@ void DrawTargetWebgl::DetachAllSnapshots() {
// framebuffer.
bool DrawTargetWebgl::MarkChanged() {
if (mSnapshot) {
ClearSnapshot();
// Try to copy the target into a new texture if possible.
ClearSnapshot(true, true);
}
if (!mWebglValid && !FlushFromSkia()) {
return false;

View File

@ -450,7 +450,7 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
bool ReadInto(uint8_t* aDstData, int32_t aDstStride);
already_AddRefed<DataSourceSurface> ReadSnapshot();
already_AddRefed<TextureHandle> CopySnapshot();
void ClearSnapshot(bool aCopyOnWrite = true);
void ClearSnapshot(bool aCopyOnWrite = true, bool aNeedHandle = false);
bool CreateFramebuffer();

View File

@ -78,9 +78,14 @@ void SourceSurfaceWebgl::Unmap() {
// 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() {
void SourceSurfaceWebgl::DrawTargetWillChange(bool aNeedHandle) {
MOZ_ASSERT(mDT);
if (!mData && !mHandle) {
// 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) {
@ -113,7 +118,12 @@ void SourceSurfaceWebgl::OnUnlinkTexture(
// If we get here, then we must have copied a snapshot, which only happens
// if the target changed.
MOZ_ASSERT(!mDT);
MOZ_ASSERT(mHandle);
// 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);
}

View File

@ -44,7 +44,7 @@ class SourceSurfaceWebgl : public DataSourceSurface {
bool EnsureData();
void DrawTargetWillChange();
void DrawTargetWillChange(bool aNeedHandle);
void GiveTexture(RefPtr<TextureHandle> aHandle);