Skip to content

Commit

Permalink
Bug 1751915 - Ensure WebGLRenderingContext texImage/etc support Offsc…
Browse files Browse the repository at this point in the history
…reenCanvas as a source. r=jgilbert,webidl,smaug

This patch adds OffscreenCanvas as a texture source for texImage2D,
texSubImage2D and texSubImage2D. This applies to both
WebGLRenderingContext and WebGL2RenderingContext. This was causing
several test failures in the WebGL conformance suite with
OffscreenCanvas.

Differential Revision: https://phabricator.services.mozilla.com/D136924
  • Loading branch information
aosmond committed Jan 27, 2022
1 parent b887b0e commit 50109bb
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 0 deletions.
10 changes: 10 additions & 0 deletions dom/canvas/ClientWebGLContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3959,6 +3959,10 @@ webgl::TexUnpackBlobDesc FromImageData(GLenum target, uvec3 size,
const dom::ImageData& imageData,
dom::Uint8ClampedArray* const scopedArr);

Maybe<webgl::TexUnpackBlobDesc> FromOffscreenCanvas(
const ClientWebGLContext&, GLenum target, uvec3 size,
const dom::OffscreenCanvas& src, ErrorResult* const out_error);

Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext&,
GLenum target, uvec3 size,
const dom::Element& src,
Expand Down Expand Up @@ -4078,6 +4082,12 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
*(src.mImageData), &scopedArr));
}

if (src.mOffscreenCanvas) {
return webgl::FromOffscreenCanvas(*this, imageTarget, explicitSize,
*(src.mOffscreenCanvas),
src.mOut_error);
}

if (src.mDomElem) {
return webgl::FromDomElem(*this, imageTarget, explicitSize,
*(src.mDomElem), src.mOut_error);
Expand Down
5 changes: 5 additions & 0 deletions dom/canvas/ClientWebGLContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,11 @@ struct TexImageSourceAdapter final : public TexImageSource {
mImageData = imageData;
}

TexImageSourceAdapter(const dom::OffscreenCanvas* offscreenCanvas,
ErrorResult*) {
mOffscreenCanvas = offscreenCanvas;
}

TexImageSourceAdapter(const dom::Element* domElem,
ErrorResult* const out_error) {
mDomElem = domElem;
Expand Down
44 changes: 44 additions & 0 deletions dom/canvas/WebGLTextureUpload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "mozilla/dom/HTMLVideoElement.h"
#include "mozilla/dom/ImageBitmap.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/OffscreenCanvas.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/Scoped.h"
#include "mozilla/ScopeExit.h"
Expand Down Expand Up @@ -147,6 +148,49 @@ static layers::SurfaceDescriptor Flatten(const layers::SurfaceDescriptor& sd) {
MOZ_CRASH("unreachable");
}

Maybe<webgl::TexUnpackBlobDesc> FromOffscreenCanvas(
const ClientWebGLContext& webgl, const GLenum target, uvec3 size,
const dom::OffscreenCanvas& canvas, ErrorResult* const out_error) {
if (canvas.IsWriteOnly()) {
webgl.EnqueueWarning(
"OffscreenCanvas is write-only, thus cannot be uploaded.");
out_error->ThrowSecurityError(
"OffscreenCanvas is write-only, thus cannot be uploaded.");
return {};
}

// The canvas spec says that drawImage should draw the first frame of
// animated images. The webgl spec doesn't mention the issue, so we do the
// same as drawImage.
uint32_t flags = nsLayoutUtils::SFE_WANT_FIRST_FRAME_IF_IMAGE;
auto sfer = nsLayoutUtils::SurfaceFromOffscreenCanvas(
const_cast<dom::OffscreenCanvas*>(&canvas), flags);

RefPtr<gfx::DataSourceSurface> dataSurf;
if (sfer.GetSourceSurface()) {
dataSurf = sfer.GetSourceSurface()->GetDataSurface();
}

if (!dataSurf) {
webgl.EnqueueWarning("Resource has no data (yet?). Uploading zeros.");
return Some(TexUnpackBlobDesc{target, size, gfxAlphaType::NonPremult});
}

// We checked this above before we requested the surface.
MOZ_RELEASE_ASSERT(!sfer.mIsWriteOnly);

uvec2 canvasSize = *uvec2::FromSize(dataSurf->GetSize());
if (!size.x) {
size.x = canvasSize.x;
}
if (!size.y) {
size.y = canvasSize.y;
}

return Some(TexUnpackBlobDesc{
target, size, sfer.mAlphaType, {}, {}, canvasSize, {}, {}, dataSurf});
}

Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext& webgl,
const GLenum target, uvec3 size,
const dom::Element& elem,
Expand Down
3 changes: 3 additions & 0 deletions dom/canvas/WebGLTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,7 @@ namespace dom {
class Element;
class ImageBitmap;
class ImageData;
class OffscreenCanvas;
} // namespace dom

struct TexImageSource {
Expand All @@ -945,6 +946,8 @@ struct TexImageSource {
const dom::ImageBitmap* mImageBitmap = nullptr;
const dom::ImageData* mImageData = nullptr;

const dom::OffscreenCanvas* mOffscreenCanvas = nullptr;

const dom::Element* mDomElem = nullptr;
ErrorResult* mOut_error = nullptr;
};
Expand Down
22 changes: 22 additions & 0 deletions dom/webidl/WebGL2RenderingContext.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,9 @@ interface mixin WebGL2RenderingContextBase
[Throws] // Another overhead throws.
void texImage2D(GLenum target, GLint level, GLint internalformat,
GLenum format, GLenum type, ImageData source);
[Throws] // Another overhead throws.
void texImage2D(GLenum target, GLint level, GLint internalformat,
GLenum format, GLenum type, OffscreenCanvas source);

[Throws] // Another overhead throws.
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
Expand All @@ -396,6 +399,9 @@ interface mixin WebGL2RenderingContextBase
[Throws] // Another overhead throws.
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, ImageData source);
[Throws] // Another overhead throws.
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, OffscreenCanvas source);

// WebGL2 entrypoints:
[Throws] // Another overhead throws.
Expand All @@ -422,6 +428,10 @@ interface mixin WebGL2RenderingContextBase
GLint border, GLenum format, GLenum type,
ImageData source);
[Throws] // Another overhead throws.
void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type,
OffscreenCanvas source);
[Throws] // Another overhead throws.
void texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData,
GLuint srcOffset);
Expand Down Expand Up @@ -450,6 +460,10 @@ interface mixin WebGL2RenderingContextBase
GLsizei depth, GLint border, GLenum format, GLenum type,
ImageData source);
[Throws] // Another overhead throws.
void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
GLsizei depth, GLint border, GLenum format, GLenum type,
OffscreenCanvas source);
[Throws] // Another overhead throws.
void texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
GLsizei depth, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView? srcData);
[Throws] // Another overhead throws.
Expand Down Expand Up @@ -481,6 +495,10 @@ interface mixin WebGL2RenderingContextBase
GLsizei height, GLenum format, GLenum type,
ImageData source);
[Throws] // Another overhead throws.
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
GLsizei height, GLenum format, GLenum type,
OffscreenCanvas source);
[Throws] // Another overhead throws.
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData,
GLuint srcOffset);
Expand Down Expand Up @@ -510,6 +528,10 @@ interface mixin WebGL2RenderingContextBase
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
ImageData source);
[Throws] // Another overhead throws.
void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
OffscreenCanvas source);
[Throws] // Another overhead throws.
void texSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
[AllowShared] ArrayBufferView? srcData, optional GLuint srcOffset = 0);
Expand Down
6 changes: 6 additions & 0 deletions dom/webidl/WebGLRenderingContext.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,9 @@ interface WebGLRenderingContext {
[Throws]
void texImage2D(GLenum target, GLint level, GLint internalformat,
GLenum format, GLenum type, HTMLVideoElement video); // May throw DOMException
[Throws]
void texImage2D(GLenum target, GLint level, GLint internalformat,
GLenum format, GLenum type, OffscreenCanvas canvas); // May throw DOMException

// texSubImage2D has WebGL2 overloads.
[Throws] // Can't actually throw.
Expand All @@ -783,6 +786,9 @@ interface WebGLRenderingContext {
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, HTMLVideoElement video); // May throw DOMException
[Throws]
void texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset,
GLenum format, GLenum type, OffscreenCanvas canvas); // May throw DOMException

// uniform*fv have WebGL2 overloads, or rather extensions, that are not
// distinguishable from the WebGL1 versions when called with two arguments.
Expand Down

0 comments on commit 50109bb

Please sign in to comment.