mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1755780 - Support CopyToSwapChain on WebGLContext. r=jgilbert
For use within accelerated Canvas2D, it is expedient to have a variant of Present that explicitly acknowledges that there is a copy from a supplied WebGL framebuffer into the swap chain back buffer, as is usually the case when remoting, so that it can be relied upon for format conversions or other concerns. This allows Present to remain simple and assume rendering happened directly to the back buffer, without need of a copy. This backs out some of the earlier changes to Present in 1754130 in favor of separating the new copy behavior into an explicit CopyToSwapChain interface, which supports a format swizzle that is useful for converting between Canvas2D and WebGL swap chain formats. The behavior of CopyToSwapChain, as noted, assumes that there is a supplied WebGL framebuffer that must be copied to the swap chain back buffer before any compositing should occur. Differential Revision: https://phabricator.services.mozilla.com/D138954
This commit is contained in:
parent
1896f79ed4
commit
46a74c07ea
@ -377,12 +377,15 @@ void ClientWebGLContext::EndComposition() {
|
||||
|
||||
// -
|
||||
|
||||
void ClientWebGLContext::Present(WebGLFramebufferJS* const xrFb,
|
||||
const bool webvr) {
|
||||
layers::TextureType ClientWebGLContext::GetTexTypeForSwapChain() const {
|
||||
const RefPtr<layers::ImageBridgeChild> imageBridge =
|
||||
layers::ImageBridgeChild::GetSingleton();
|
||||
return layers::TexTypeForWebgl(imageBridge);
|
||||
}
|
||||
|
||||
const auto texType = layers::TexTypeForWebgl(imageBridge);
|
||||
void ClientWebGLContext::Present(WebGLFramebufferJS* const xrFb,
|
||||
const bool webvr) {
|
||||
const auto texType = GetTexTypeForSwapChain();
|
||||
Present(xrFb, texType, webvr);
|
||||
}
|
||||
|
||||
@ -397,6 +400,18 @@ void ClientWebGLContext::Present(WebGLFramebufferJS* const xrFb,
|
||||
Run<RPROC(Present)>(xrFb ? xrFb->mId : 0, type, webvr);
|
||||
}
|
||||
|
||||
void ClientWebGLContext::CopyToSwapChain(
|
||||
WebGLFramebufferJS* const fb, const webgl::SwapChainOptions& options) {
|
||||
CancelAutoFlush();
|
||||
const auto texType = GetTexTypeForSwapChain();
|
||||
Run<RPROC(CopyToSwapChain)>(fb ? fb->mId : 0, texType, options);
|
||||
}
|
||||
|
||||
void ClientWebGLContext::EndOfFrame() {
|
||||
CancelAutoFlush();
|
||||
Run<RPROC(EndOfFrame)>();
|
||||
}
|
||||
|
||||
Maybe<layers::SurfaceDescriptor> ClientWebGLContext::GetFrontBuffer(
|
||||
WebGLFramebufferJS* const fb, bool vr) {
|
||||
const auto notLost = mNotLost;
|
||||
|
@ -1014,9 +1014,14 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
||||
}
|
||||
void GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval);
|
||||
|
||||
layers::TextureType GetTexTypeForSwapChain() const;
|
||||
void Present(WebGLFramebufferJS*, const bool webvr = false);
|
||||
void Present(WebGLFramebufferJS*, layers::TextureType,
|
||||
const bool webvr = false);
|
||||
void CopyToSwapChain(
|
||||
WebGLFramebufferJS*,
|
||||
const webgl::SwapChainOptions& options = webgl::SwapChainOptions());
|
||||
void EndOfFrame();
|
||||
Maybe<layers::SurfaceDescriptor> GetFrontBuffer(
|
||||
WebGLFramebufferJS*, const bool webvr = false) override;
|
||||
Maybe<layers::SurfaceDescriptor> PresentFrontBuffer(
|
||||
|
@ -172,6 +172,11 @@ class HostWebGLContext final : public SupportsWeakPtr {
|
||||
const bool webvr) const {
|
||||
return (void)mContext->Present(AutoResolve(xrFb), t, webvr);
|
||||
}
|
||||
void CopyToSwapChain(const ObjectId fb, const layers::TextureType t,
|
||||
const webgl::SwapChainOptions& options) const {
|
||||
return (void)mContext->CopyToSwapChain(AutoResolve(fb), t, options);
|
||||
}
|
||||
void EndOfFrame() const { return (void)mContext->EndOfFrame(); }
|
||||
Maybe<layers::SurfaceDescriptor> GetFrontBuffer(ObjectId xrFb,
|
||||
const bool webvr) const;
|
||||
|
||||
|
@ -793,7 +793,7 @@ void WebGLContext::OnEndOfFrame() {
|
||||
|
||||
void WebGLContext::BlitBackbufferToCurDriverFB(
|
||||
WebGLFramebuffer* const srcAsWebglFb,
|
||||
const gl::MozFramebuffer* const srcAsMozFb) const {
|
||||
const gl::MozFramebuffer* const srcAsMozFb, bool srcIsBGRA) const {
|
||||
DoColorMask(0x0f);
|
||||
|
||||
if (mScissorTestEnabled) {
|
||||
@ -818,19 +818,25 @@ void WebGLContext::BlitBackbufferToCurDriverFB(
|
||||
size = mozFb->mSize;
|
||||
}
|
||||
|
||||
if (gl->IsSupported(gl::GLFeature::framebuffer_blit)) {
|
||||
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fbo);
|
||||
gl->fBlitFramebuffer(0, 0, size.width, size.height, 0, 0, size.width,
|
||||
size.height, LOCAL_GL_COLOR_BUFFER_BIT,
|
||||
LOCAL_GL_NEAREST);
|
||||
return;
|
||||
}
|
||||
if (mDefaultFB->mSamples &&
|
||||
gl->IsExtensionSupported(
|
||||
gl::GLContext::APPLE_framebuffer_multisample)) {
|
||||
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fbo);
|
||||
gl->fResolveMultisampleFramebufferAPPLE();
|
||||
return;
|
||||
// If no format conversion is necessary, then attempt to directly blit
|
||||
// between framebuffers. Otherwise, if we need to convert to RGBA from
|
||||
// the source format, then we will need to use the texture blit path
|
||||
// below.
|
||||
if (!srcIsBGRA) {
|
||||
if (gl->IsSupported(gl::GLFeature::framebuffer_blit)) {
|
||||
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fbo);
|
||||
gl->fBlitFramebuffer(0, 0, size.width, size.height, 0, 0, size.width,
|
||||
size.height, LOCAL_GL_COLOR_BUFFER_BIT,
|
||||
LOCAL_GL_NEAREST);
|
||||
return;
|
||||
}
|
||||
if (mDefaultFB->mSamples &&
|
||||
gl->IsExtensionSupported(
|
||||
gl::GLContext::APPLE_framebuffer_multisample)) {
|
||||
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fbo);
|
||||
gl->fResolveMultisampleFramebufferAPPLE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint colorTex = 0;
|
||||
@ -841,7 +847,8 @@ void WebGLContext::BlitBackbufferToCurDriverFB(
|
||||
} else {
|
||||
colorTex = mozFb->ColorTex();
|
||||
}
|
||||
gl->BlitHelper()->DrawBlitTextureToFramebuffer(colorTex, size, size);
|
||||
gl->BlitHelper()->DrawBlitTextureToFramebuffer(
|
||||
colorTex, size, size, LOCAL_GL_TEXTURE_2D, srcIsBGRA);
|
||||
}();
|
||||
|
||||
if (mScissorTestEnabled) {
|
||||
@ -860,26 +867,13 @@ constexpr auto MakeArray(Args... args) -> std::array<T, sizeof...(Args)> {
|
||||
|
||||
// For an overview of how WebGL compositing works, see:
|
||||
// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
|
||||
bool WebGLContext::PresentInto(gl::SwapChain& swapChain,
|
||||
WebGLFramebuffer* const srcFb) {
|
||||
bool WebGLContext::PresentInto(gl::SwapChain& swapChain) {
|
||||
OnEndOfFrame();
|
||||
|
||||
if (!ValidateAndInitFB(srcFb)) return false;
|
||||
if (!ValidateAndInitFB(nullptr)) return false;
|
||||
|
||||
{
|
||||
GLuint fbo = 0;
|
||||
gfx::IntSize size;
|
||||
if (srcFb) {
|
||||
fbo = srcFb->mGLName;
|
||||
const auto* info = srcFb->GetCompletenessInfo();
|
||||
MOZ_ASSERT(info);
|
||||
size = gfx::IntSize(info->width, info->height);
|
||||
} else {
|
||||
fbo = mDefaultFB->mFB;
|
||||
size = mDefaultFB->mSize;
|
||||
}
|
||||
|
||||
auto presenter = swapChain.Acquire(size);
|
||||
auto presenter = swapChain.Acquire(mDefaultFB->mSize);
|
||||
if (!presenter) {
|
||||
GenerateWarning("Swap chain surface creation failed.");
|
||||
LoseContext();
|
||||
@ -889,19 +883,17 @@ bool WebGLContext::PresentInto(gl::SwapChain& swapChain,
|
||||
const auto destFb = presenter->Fb();
|
||||
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
|
||||
|
||||
BlitBackbufferToCurDriverFB(srcFb);
|
||||
BlitBackbufferToCurDriverFB();
|
||||
|
||||
if (!mOptions.preserveDrawingBuffer) {
|
||||
if (gl->IsSupported(gl::GLFeature::invalidate_framebuffer)) {
|
||||
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fbo);
|
||||
gl->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, mDefaultFB->mFB);
|
||||
constexpr auto attachments = MakeArray<GLenum>(
|
||||
LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
|
||||
gl->fInvalidateFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
|
||||
attachments.size(), attachments.data());
|
||||
}
|
||||
if (!srcFb) {
|
||||
mDefaultFB_IsInvalid = true;
|
||||
}
|
||||
mDefaultFB_IsInvalid = true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -948,6 +940,22 @@ bool WebGLContext::PresentIntoXR(gl::SwapChain& swapChain,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialize a swap chain's surface factory given the desired surface type.
|
||||
void InitSwapChain(gl::GLContext& gl, gl::SwapChain& swapChain,
|
||||
const layers::TextureType consumerType) {
|
||||
if (!swapChain.mFactory) {
|
||||
auto typedFactory = gl::SurfaceFactory::Create(&gl, consumerType);
|
||||
if (typedFactory) {
|
||||
swapChain.mFactory = std::move(typedFactory);
|
||||
}
|
||||
}
|
||||
if (!swapChain.mFactory) {
|
||||
NS_WARNING("Failed to make an ideal SurfaceFactory.");
|
||||
swapChain.mFactory = MakeUnique<gl::SurfaceFactory_Basic>(gl);
|
||||
}
|
||||
MOZ_ASSERT(swapChain.mFactory);
|
||||
}
|
||||
|
||||
void WebGLContext::Present(WebGLFramebuffer* const xrFb,
|
||||
const layers::TextureType consumerType,
|
||||
const bool webvr) {
|
||||
@ -966,25 +974,54 @@ void WebGLContext::Present(WebGLFramebuffer* const xrFb,
|
||||
mResolvedDefaultFB = nullptr;
|
||||
}
|
||||
|
||||
if (!swapChain->mFactory) {
|
||||
auto typedFactory = gl::SurfaceFactory::Create(gl, consumerType);
|
||||
if (typedFactory) {
|
||||
swapChain->mFactory = std::move(typedFactory);
|
||||
}
|
||||
}
|
||||
if (!swapChain->mFactory) {
|
||||
NS_WARNING("Failed to make an ideal SurfaceFactory.");
|
||||
swapChain->mFactory = MakeUnique<gl::SurfaceFactory_Basic>(*gl);
|
||||
}
|
||||
MOZ_ASSERT(swapChain->mFactory);
|
||||
InitSwapChain(*gl, *swapChain, consumerType);
|
||||
|
||||
if (maybeFB) {
|
||||
(void)PresentIntoXR(*swapChain, *maybeFB);
|
||||
} else {
|
||||
(void)PresentInto(*swapChain, xrFb);
|
||||
(void)PresentInto(*swapChain);
|
||||
}
|
||||
}
|
||||
|
||||
void WebGLContext::CopyToSwapChain(WebGLFramebuffer* const srcFb,
|
||||
const layers::TextureType consumerType,
|
||||
const webgl::SwapChainOptions& options) {
|
||||
const FuncScope funcScope(*this, "<CopyToSwapChain>");
|
||||
if (IsContextLost()) return;
|
||||
|
||||
OnEndOfFrame();
|
||||
|
||||
if (!srcFb) return;
|
||||
const auto* info = srcFb->GetCompletenessInfo();
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
gfx::IntSize size(info->width, info->height);
|
||||
|
||||
InitSwapChain(*gl, srcFb->mSwapChain, consumerType);
|
||||
|
||||
auto presenter = srcFb->mSwapChain.Acquire(size);
|
||||
if (!presenter) {
|
||||
GenerateWarning("Swap chain surface creation failed.");
|
||||
LoseContext();
|
||||
return;
|
||||
}
|
||||
|
||||
const ScopedFBRebinder saveFB(this);
|
||||
|
||||
const auto destFb = presenter->Fb();
|
||||
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, destFb);
|
||||
|
||||
BlitBackbufferToCurDriverFB(srcFb, nullptr, options.bgra);
|
||||
}
|
||||
|
||||
void WebGLContext::EndOfFrame() {
|
||||
const FuncScope funcScope(*this, "<EndOfFrame>");
|
||||
if (IsContextLost()) return;
|
||||
|
||||
OnEndOfFrame();
|
||||
}
|
||||
|
||||
Maybe<layers::SurfaceDescriptor> WebGLContext::GetFrontBuffer(
|
||||
WebGLFramebuffer* const xrFb, const bool webvr) {
|
||||
auto swapChain = webvr ? &mWebVRSwapChain : &mSwapChain;
|
||||
|
@ -479,11 +479,35 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
|
||||
|
||||
// Present to compositor
|
||||
private:
|
||||
bool PresentInto(gl::SwapChain& swapChain, WebGLFramebuffer* srcFb = nullptr);
|
||||
bool PresentInto(gl::SwapChain& swapChain);
|
||||
bool PresentIntoXR(gl::SwapChain& swapChain, const gl::MozFramebuffer& xrFb);
|
||||
|
||||
public:
|
||||
// Present swaps the front and back buffers of the swap chain for compositing.
|
||||
// This assumes the framebuffer may directly alias with the back buffer,
|
||||
// dependent on remoting state or other concerns. Framebuffer and swap chain
|
||||
// surface formats are assumed to be similar to enable this aliasing. As such,
|
||||
// the back buffer may be invalidated by this swap with the front buffer,
|
||||
// unless overriden by explicitly setting the preserveDrawingBuffer option,
|
||||
// which may incur a further copy to preserve the back buffer.
|
||||
void Present(WebGLFramebuffer*, layers::TextureType, const bool webvr);
|
||||
// CopyToSwapChain forces a copy from the supplied framebuffer into the back
|
||||
// buffer before swapping the front and back buffers of the swap chain for
|
||||
// compositing. The formats of the framebuffer and the swap chain buffers
|
||||
// may differ subject to available format conversion options. Since this
|
||||
// operation uses an explicit copy, it inherently preserves the framebuffer
|
||||
// without need to set the preserveDrawingBuffer option.
|
||||
void CopyToSwapChain(
|
||||
WebGLFramebuffer*, layers::TextureType,
|
||||
const webgl::SwapChainOptions& options = webgl::SwapChainOptions());
|
||||
// In use cases where a framebuffer is used as an offscreen framebuffer and
|
||||
// does not need to be committed to the swap chain, it may still be useful
|
||||
// for the implementation to delineate distinct frames, such as when sharing
|
||||
// a single WebGLContext amongst many distinct users. EndOfFrame signals that
|
||||
// frame rendering is complete so that any implementation side-effects such
|
||||
// as resetting internal profile counters or resource queues may be handled
|
||||
// appropriately.
|
||||
void EndOfFrame();
|
||||
RefPtr<gfx::DataSourceSurface> GetFrontBufferSnapshot();
|
||||
Maybe<uvec2> FrontBufferSnapshotInto(Maybe<Range<uint8_t>>);
|
||||
Maybe<layers::SurfaceDescriptor> GetFrontBuffer(WebGLFramebuffer*,
|
||||
@ -1214,7 +1238,8 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
|
||||
void DoColorMask(uint8_t bitmask) const;
|
||||
void BlitBackbufferToCurDriverFB(
|
||||
WebGLFramebuffer* const srcAsWebglFb = nullptr,
|
||||
const gl::MozFramebuffer* const srcAsMozFb = nullptr) const;
|
||||
const gl::MozFramebuffer* const srcAsMozFb = nullptr,
|
||||
bool srcIsBGRA = false) const;
|
||||
bool BindDefaultFBForRead();
|
||||
|
||||
// --
|
||||
|
@ -144,6 +144,8 @@ DEFINE_ASYNC(HostWebGLContext::EndQuery)
|
||||
DEFINE_ASYNC(HostWebGLContext::QueryCounter)
|
||||
DEFINE_ASYNC(HostWebGLContext::SetFramebufferIsInOpaqueRAF)
|
||||
DEFINE_ASYNC(HostWebGLContext::ClearVRSwapChain)
|
||||
DEFINE_ASYNC(HostWebGLContext::CopyToSwapChain)
|
||||
DEFINE_ASYNC(HostWebGLContext::EndOfFrame)
|
||||
|
||||
#undef DEFINE_ASYNC
|
||||
#undef DEFINE_METHOD_DISPATCHER
|
||||
|
@ -75,6 +75,8 @@ struct IsTriviallySerializable<webgl::ReadPixelsDesc> : std::true_type {};
|
||||
// struct IsTriviallySerializable<layers::SurfaceDescriptor> : std::true_type
|
||||
// {};
|
||||
// SurfaceDescriptorBuffer is *not* trivial.
|
||||
template <>
|
||||
struct IsTriviallySerializable<webgl::SwapChainOptions> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct QueueParamTraits<RawBuffer<T>> {
|
||||
|
@ -657,6 +657,12 @@ struct OpaqueFramebufferOptions final {
|
||||
|
||||
// -
|
||||
|
||||
struct SwapChainOptions final {
|
||||
bool bgra = false;
|
||||
};
|
||||
|
||||
// -
|
||||
|
||||
struct ActiveInfo {
|
||||
GLenum elemType = 0; // `type`
|
||||
uint32_t elemCount = 0; // `size`
|
||||
|
@ -88,6 +88,16 @@ const char* const kFragBody_RGBA =
|
||||
FRAG_COLOR = TEXTURE(uTex0, vTexCoord0); \n\
|
||||
} \n\
|
||||
";
|
||||
const char* const kFragBody_BGRA =
|
||||
"\
|
||||
VARYING vec2 vTexCoord0; \n\
|
||||
uniform SAMPLER uTex0; \n\
|
||||
\n\
|
||||
void main(void) \n\
|
||||
{ \n\
|
||||
FRAG_COLOR = TEXTURE(uTex0, vTexCoord0).bgra; \n\
|
||||
} \n\
|
||||
";
|
||||
const char* const kFragBody_CrYCb =
|
||||
"\
|
||||
VARYING vec2 vTexCoord0; \n\
|
||||
@ -1120,8 +1130,9 @@ bool GLBlitHelper::BlitImage(MacIOSurface* const iosurf,
|
||||
void GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex,
|
||||
const gfx::IntSize& srcSize,
|
||||
const gfx::IntSize& destSize,
|
||||
const GLenum srcTarget) const {
|
||||
const char* fragHeader;
|
||||
const GLenum srcTarget,
|
||||
const bool srcIsBGRA) const {
|
||||
const char* fragHeader = nullptr;
|
||||
Mat3 texMatrix0;
|
||||
switch (srcTarget) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
@ -1136,7 +1147,8 @@ void GLBlitHelper::DrawBlitTextureToFramebuffer(const GLuint srcTex,
|
||||
gfxCriticalError() << "Unexpected srcTarget: " << srcTarget;
|
||||
return;
|
||||
}
|
||||
const auto& prog = GetDrawBlitProg({fragHeader, kFragBody_RGBA});
|
||||
const char* fragBody = srcIsBGRA ? kFragBody_BGRA : kFragBody_RGBA;
|
||||
const auto& prog = GetDrawBlitProg({fragHeader, fragBody});
|
||||
|
||||
const ScopedSaveMultiTex saveTex(mGL, 1, srcTarget);
|
||||
mGL->fBindTexture(srcTarget, srcTex);
|
||||
|
@ -217,9 +217,10 @@ class GLBlitHelper final {
|
||||
GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
|
||||
GLenum destTarget = LOCAL_GL_TEXTURE_2D) const;
|
||||
|
||||
void DrawBlitTextureToFramebuffer(
|
||||
GLuint srcTex, const gfx::IntSize& srcSize, const gfx::IntSize& destSize,
|
||||
GLenum srcTarget = LOCAL_GL_TEXTURE_2D) const;
|
||||
void DrawBlitTextureToFramebuffer(GLuint srcTex, const gfx::IntSize& srcSize,
|
||||
const gfx::IntSize& destSize,
|
||||
GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
|
||||
bool srcIsBGRA = false) const;
|
||||
|
||||
bool BlitImageToFramebuffer(layers::Image* srcImage,
|
||||
const gfx::IntSize& destSize,
|
||||
|
Loading…
Reference in New Issue
Block a user