Skip to content

Commit

Permalink
Bug 1751205 - Part 2. Ensure we y-flip surfaces with OffscreenCanvas …
Browse files Browse the repository at this point in the history
…if needed. r=gfx-reviewers,jgilbert

On the path that we need to read the pixels from the canvas for display
purposes, instead of using a platform buffer handle, we need to take
into account the need to y-flip for WebGL. This patch ensures that we do
so.

Differential Revision: https://phabricator.services.mozilla.com/D136504
  • Loading branch information
aosmond committed Jan 28, 2022
1 parent bcb62d5 commit 162ffc6
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 29 deletions.
4 changes: 2 additions & 2 deletions dom/canvas/OffscreenCanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ void OffscreenCanvas::GetContext(
return;
}

int32_t childId = 0;
Maybe<int32_t> childId;

MOZ_ASSERT(mCurrentContext);
switch (mCurrentContextType) {
Expand All @@ -157,7 +157,7 @@ void OffscreenCanvas::GetContext(
auto* webgl = static_cast<ClientWebGLContext*>(mCurrentContext.get());
WebGLChild* webglChild = webgl->GetChild();
if (webglChild) {
childId = webglChild->Id();
childId.emplace(webglChild->Id());
}
aResult.SetValue().SetAsWebGLRenderingContext() = *webgl;
break;
Expand Down
88 changes: 70 additions & 18 deletions dom/canvas/OffscreenCanvasDisplayHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "OffscreenCanvasDisplayHelper.h"
#include "mozilla/gfx/CanvasManagerChild.h"
#include "mozilla/gfx/Swizzle.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/TextureClientSharedSurface.h"
#include "mozilla/layers/TextureWrapperImage.h"
Expand Down Expand Up @@ -43,16 +44,18 @@ RefPtr<layers::ImageContainer> OffscreenCanvasDisplayHelper::GetImageContainer()
return mImageContainer;
}

void OffscreenCanvasDisplayHelper::UpdateContext(CanvasContextType aType,
int32_t aChildId) {
void OffscreenCanvasDisplayHelper::UpdateContext(
CanvasContextType aType, const Maybe<int32_t>& aChildId) {
MutexAutoLock lock(mMutex);
mImageContainer =
MakeRefPtr<layers::ImageContainer>(layers::ImageContainer::ASYNCHRONOUS);
mType = aType;
mContextChildId = aChildId;

if (aChildId) {
mContextManagerId = gfx::CanvasManagerChild::Get()->Id();
mContextChildId = aChildId;
mContextManagerId = Some(gfx::CanvasManagerChild::Get()->Id());
} else {
mContextManagerId.reset();
}

MaybeQueueInvalidateElement();
Expand Down Expand Up @@ -119,9 +122,11 @@ bool OffscreenCanvasDisplayHelper::CommitFrameToCompositor(
texture, gfx::IntRect(gfx::IntPoint(0, 0), mData.mSize));
}
} else {
surface = aContext->GetFrontBufferSnapshot(/* requireAlphaPremult */ true);
surface = aContext->GetFrontBufferSnapshot(/* requireAlphaPremult */ false);
if (surface) {
image = new layers::SourceSurfaceImage(surface);
auto surfaceImage = MakeRefPtr<layers::SourceSurfaceImage>(surface);
surfaceImage->SetTextureFlags(flags);
image = surfaceImage;
}
}

Expand All @@ -138,8 +143,6 @@ bool OffscreenCanvasDisplayHelper::CommitFrameToCompositor(
mImageContainer->ClearAllImages();
}

mFrontBufferDesc = std::move(desc);
mFrontBufferSurface = std::move(surface);
return true;
}

Expand Down Expand Up @@ -182,27 +185,76 @@ OffscreenCanvasDisplayHelper::GetSurfaceSnapshot() {
Maybe<layers::SurfaceDescriptor> desc;

bool hasAlpha;
uint32_t managerId;
int32_t childId;
gl::OriginPos originPos;
Maybe<uint32_t> managerId;
Maybe<int32_t> childId;
HTMLCanvasElement* canvasElement;

{
MutexAutoLock lock(mMutex);
if (mFrontBufferSurface) {
RefPtr<gfx::SourceSurface> surface = mFrontBufferSurface;
return surface.forget();
}

hasAlpha = !mData.mIsOpaque;
originPos = mData.mOriginPos;
managerId = mContextManagerId;
childId = mContextChildId;
canvasElement = mCanvasElement;
}

if (NS_WARN_IF(!managerId || !childId)) {
if (managerId && childId) {
// The context lives in the compositor process.
return gfx::CanvasManagerChild::Get()->GetSnapshot(
managerId.value(), childId.value(), hasAlpha);
}

// If we don't have any protocol IDs, it is possible it is a main thread
// OffscreenCanvas instance. If so, then the element's OffscreenCanvas is
// not neutered and has access to the context. We can use that to get the
// snapshot directly.
if (!canvasElement) {
return nullptr;
}

return gfx::CanvasManagerChild::Get()->GetSnapshot(managerId, childId,
hasAlpha);
const auto* offscreenCanvas = canvasElement->GetOffscreenCanvas();
nsICanvasRenderingContextInternal* context = offscreenCanvas->GetContext();
if (!context) {
return nullptr;
}

RefPtr<gfx::SourceSurface> surface =
context->GetFrontBufferSnapshot(/* requireAlphaPremult */ true);
if (!surface) {
return nullptr;
}

switch (originPos) {
case gl::OriginPos::BottomLeft: {
RefPtr<gfx::DataSourceSurface> dataSurface = surface->GetDataSurface();
if (!dataSurface) {
return nullptr;
}

gfx::DataSourceSurface::ScopedMap map(dataSurface,
gfx::DataSourceSurface::READ_WRITE);
if (!map.IsMapped()) {
return nullptr;
}

// The buffer we read back from WebGL has its rows inverted.
const gfx::SurfaceFormat format = surface->GetFormat();
const gfx::IntSize size = surface->GetSize();
if (!gfx::SwizzleYFlipData(map.GetData(), map.GetStride(), format,
map.GetData(), map.GetStride(), format,
size)) {
return nullptr;
}
} break;
case gl::OriginPos::TopLeft:
break;
default:
MOZ_ASSERT_UNREACHABLE("Unhandled origin position!");
break;
}

return surface.forget();
}

already_AddRefed<layers::Image> OffscreenCanvasDisplayHelper::GetAsImage() {
Expand Down
8 changes: 3 additions & 5 deletions dom/canvas/OffscreenCanvasDisplayHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class OffscreenCanvasDisplayHelper final {

RefPtr<layers::ImageContainer> GetImageContainer() const;

void UpdateContext(CanvasContextType aType, int32_t aChildId);
void UpdateContext(CanvasContextType aType, const Maybe<int32_t>& aChildId);

bool CommitFrameToCompositor(nsICanvasRenderingContextInternal* aContext,
layers::TextureType aTextureType,
Expand All @@ -60,13 +60,11 @@ class OffscreenCanvasDisplayHelper final {
mutable Mutex mMutex;
HTMLCanvasElement* MOZ_NON_OWNING_REF mCanvasElement;
RefPtr<layers::ImageContainer> mImageContainer;
RefPtr<gfx::SourceSurface> mFrontBufferSurface;
Maybe<layers::SurfaceDescriptor> mFrontBufferDesc;

OffscreenCanvasDisplayData mData;
CanvasContextType mType = CanvasContextType::NoContext;
uint32_t mContextManagerId = 0;
int32_t mContextChildId = 0;
Maybe<uint32_t> mContextManagerId;
Maybe<int32_t> mContextChildId;
mozilla::layers::ImageContainer::ProducerID mImageProducerID;
mozilla::layers::ImageContainer::FrameID mLastFrameID = 0;
bool mPendingInvalidate = false;
Expand Down
70 changes: 70 additions & 0 deletions dom/canvas/test/reftest/reftest.list
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,76 @@ fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) == webgl-color-test.ht
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
pref(webgl.force-layers-readback,true) == webgl-color-test.html?frame=6&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png

# OffscreenCanvas variant of the above.
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&________&_______&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&________&premult&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&________&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&________&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&________&premult&alpha wrapper.html?colors-premult.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&________&premult&alpha wrapper.html?colors-premult.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&__&preserve&premult&alpha wrapper.html?colors-premult.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&aa&preserve&premult&alpha wrapper.html?colors-premult.png

skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&________&_______&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&________&premult&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&________&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&________&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&________&premult&alpha wrapper.html?colors-premult.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&________&premult&alpha wrapper.html?colors-premult.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&__&preserve&premult&alpha wrapper.html?colors-premult.png
skip-if(Android) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&aa&preserve&premult&alpha wrapper.html?colors-premult.png

pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&________&premult&alpha wrapper.html?colors-premult.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=1&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png

pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&________&_______&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&________&_______&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&preserve&_______&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&preserve&_______&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&________&premult&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&________&premult&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&preserve&premult&_____ wrapper.html?colors-no-alpha.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&preserve&premult&_____ wrapper.html?colors-no-alpha.png
fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&________&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&________&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&preserve&_______&alpha wrapper.html?colors-non-premult.png
fuzzy(0-1,0-30000) pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&preserve&_______&alpha wrapper.html?colors-non-premult.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&________&premult&alpha wrapper.html?colors-premult.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&________&premult&alpha wrapper.html?colors-premult.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&__&preserve&premult&alpha wrapper.html?colors-premult.png
pref(webgl.force-layers-readback,true) pref(gfx.offscreencanvas.enabled,true) == webgl-color-offscreen-test.html?frame=6&readback&aa&preserve&premult&alpha wrapper.html?colors-premult.png


# Check for hanging bindings/state settings:
skip-if(Android) == webgl-hanging-fb-test.html?__&________ wrapper.html?green.png
skip-if(Android) == webgl-hanging-fb-test.html?aa&________ wrapper.html?green.png
Expand Down
Loading

0 comments on commit 162ffc6

Please sign in to comment.