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 27, 2022
1 parent 0ed592a commit b887b0e
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 15 deletions.
13 changes: 4 additions & 9 deletions dom/canvas/OffscreenCanvasDisplayHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,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 +140,6 @@ bool OffscreenCanvasDisplayHelper::CommitFrameToCompositor(
mImageContainer->ClearAllImages();
}

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

Expand Down Expand Up @@ -187,11 +187,6 @@ OffscreenCanvasDisplayHelper::GetSurfaceSnapshot() {

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

hasAlpha = !mData.mIsOpaque;
managerId = mContextManagerId;
childId = mContextChildId;
Expand Down
2 changes: 0 additions & 2 deletions dom/canvas/OffscreenCanvasDisplayHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ 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;
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
124 changes: 124 additions & 0 deletions dom/canvas/test/reftest/webgl-color-offscreen-test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<!DOCTYPE html>
<meta charset='UTF-8'>
<!--
Color Test
Clear the four quadrants of the canvas as follows:
+------+------+
| blue |black |
| | |
+------+------+
| red |green |
| | |
+------+------+
Clear with a given alpha value. What effect this has depends on the
context-creation args passed to this page.
-->
<html class='reftest-wait'>

<head>
<script type='text/javascript' src='webgl-utils.js'></script>
<script type='text/javascript'>
'use strict';

var COLOR_VALUE = 127.0 / 255.0;
var ALPHA_VALUE = 127.0 / 255.0;

function renderFrame(gl) {
gl.enable(gl.SCISSOR_TEST);

gl.scissor(0, 0, 100, 100);
gl.clearColor(COLOR_VALUE, 0.0, 0.0, ALPHA_VALUE);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.scissor(100, 0, 100, 100);
gl.clearColor(0.0, COLOR_VALUE, 0.0, ALPHA_VALUE);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.scissor(0, 100, 100, 100);
gl.clearColor(0.0, 0.0, COLOR_VALUE, ALPHA_VALUE);
gl.clear(gl.COLOR_BUFFER_BIT);

gl.scissor(100, 100, 100, 100);
gl.clearColor(0.0, 0.0, 0.0, ALPHA_VALUE);
gl.clear(gl.COLOR_BUFFER_BIT);
}

////////////////////////////////////////////////////////////////////////////////
// Boilerplate

var TIMEOUT_MS = 30 * 1000;

function setStatus(text) {
var elem = document.getElementById('status');
elem.innerHTML = text;
}

var gIsComplete = false;

function markComplete(statusText) {
if (!statusText)
statusText = '';

if (gIsComplete)
return;
gIsComplete = true;

setStatus(statusText);
document.documentElement.removeAttribute('class');
}

function markError(text) {
markComplete('Error: ' + text);
}

function markTimedOut() {
markError('Timed out waiting on test completion.');
}

function runFrame(gl, frameCount, maxFrameCount) {
renderFrame(gl);
frameCount++;

if (frameCount >= maxFrameCount) {
console.log('Rendered ' + frameCount + ' frames.');
markComplete();
return;
}

requestAnimationFrame(function(){
runFrame(gl, frameCount, maxFrameCount);
});
}

function runTest() {
var canvas = document.getElementById('canvas');
var offscreenCanvas = canvas.transferControlToOffscreen();

var gl = initGL(offscreenCanvas);
if (!gl) {
markError('WebGL context creation failed.');
return;
}

var maxFrameCount = arg('frame', 1);
if (maxFrameCount < 1) {
markError('Invalid `frame` arg: ' + maxFrameCount);
return;
}

setStatus('Waiting...');

runFrame(gl, 0, maxFrameCount);
setTimeout(markTimedOut, TIMEOUT_MS);
}
</script>
</head>

<body onload='runTest();'>
<canvas id='canvas' width='200' height='200'></canvas>
<div id='status'></div>
</body>

</html>
2 changes: 1 addition & 1 deletion dom/canvas/test/reftest/webgl-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ function initGL(canvas) {
premultipliedAlpha: withPremult,
preserveDrawingBuffer: withPreserve,
};
gl = canvas.getContext("experimental-webgl", argDict);
gl = canvas.getContext("webgl", argDict);
} catch(e) {}

return gl;
Expand Down
25 changes: 22 additions & 3 deletions gfx/ipc/CanvasManagerChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Swizzle.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/layers/CompositorManagerChild.h"

Expand Down Expand Up @@ -164,9 +165,10 @@ already_AddRefed<DataSourceSurface> CanvasManagerChild::GetSnapshot(
return nullptr;
}

SurfaceFormat format =
aHasAlpha ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
RefPtr<DataSourceSurface> surface =
Factory::CreateDataSourceSurfaceWithStride(size, SurfaceFormat::B8G8R8A8,
stride.value(),
Factory::CreateDataSourceSurfaceWithStride(size, format, stride.value(),
/* aZero */ false);
if (!surface) {
return nullptr;
Expand All @@ -178,7 +180,24 @@ already_AddRefed<DataSourceSurface> CanvasManagerChild::GetSnapshot(
return nullptr;
}

memcpy(map.GetData(), res.shmem->get<uint8_t>(), res.shmem->Size<uint8_t>());
// The buffer we read back from WebGL is R8G8B8A8, not premultiplied and has
// its rows inverted. For the general case, we want surfaces represented as
// premultiplied B8G8R8A8, with its rows ordered top to bottom. Given this
// path is used for screenshots/SurfaceFromElement, that's the representation
// we need.
if (aHasAlpha) {
if (!PremultiplyYFlipData(res.shmem->get<uint8_t>(), stride.value(),
SurfaceFormat::R8G8B8A8, map.GetData(),
map.GetStride(), format, size)) {
return nullptr;
}
} else {
if (!SwizzleYFlipData(res.shmem->get<uint8_t>(), stride.value(),
SurfaceFormat::R8G8B8X8, map.GetData(),
map.GetStride(), format, size)) {
return nullptr;
}
}
return surface.forget();
}

Expand Down

0 comments on commit b887b0e

Please sign in to comment.