Bug 1614568 [Wayland] Implement fence sync to dmabuf surfaces for WebGL rendering, r=jgilbert

Use ANDROID_native_fence_sync to synchronize WebGL renderin. It's similar to KHR_fence_sync
but it the fence can be exported to file descriptor and shared among processes so we can create
the fence by WebGL producer and then wait in renderer.

Use glFinish() as a fallback when ANDROID_native_fence_sync is not available.

Differential Revision: https://phabricator.services.mozilla.com/D62712

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Martin Stransky 2020-02-19 15:13:28 +00:00
parent fd033029ab
commit 905e0e97e8
5 changed files with 121 additions and 24 deletions

View File

@ -45,11 +45,7 @@ SharedSurface_DMABUF::~SharedSurface_DMABUF() {
mSurface->ReleaseTextures();
}
void SharedSurface_DMABUF::ProducerReleaseImpl() {
mGL->MakeCurrent();
// We don't have a better sync mechanism here so use glFinish() at least.
mGL->fFinish();
}
void SharedSurface_DMABUF::ProducerReleaseImpl() { mSurface->FenceSet(); }
bool SharedSurface_DMABUF::ToSurfaceDescriptor(
layers::SurfaceDescriptor* const out_descriptor) {

View File

@ -70,6 +70,7 @@ struct SurfaceDescriptorDMABuf {
uint32_t[] strides;
uint32_t[] offsets;
YUVColorSpace yUVColorSpace;
FileDescriptor fence;
};
struct SurfaceTextureDescriptor {

View File

@ -59,6 +59,8 @@ bool WaylandDMABUFTextureHostOGL::Lock() {
prev = next;
}
}
mSurface->FenceWait();
return true;
}

View File

@ -57,17 +57,6 @@ using namespace mozilla::layers;
# define VA_FOURCC_NV12 0x3231564E
#endif
WaylandDMABufSurface::WaylandDMABufSurface(SurfaceType aSurfaceType)
: mSurfaceType(aSurfaceType),
mBufferModifier(0),
mBufferPlaneCount(0),
mStrides(),
mOffsets() {
for (int i = 0; i < DMABUF_BUFFER_PLANES; i++) {
mDmabufFds[i] = -1;
}
}
already_AddRefed<WaylandDMABufSurface>
WaylandDMABufSurface::CreateDMABufSurface(
const mozilla::layers::SurfaceDescriptor& aDesc) {
@ -91,6 +80,69 @@ WaylandDMABufSurface::CreateDMABufSurface(
return surf.forget();
}
void WaylandDMABufSurface::FenceDelete() {
auto* egl = gl::GLLibraryEGL::Get();
if (mSync) {
// We can't call this unless we have the ext, but we will always have
// the ext if we have something to destroy.
egl->fDestroySync(egl->Display(), mSync);
mSync = nullptr;
}
}
void WaylandDMABufSurface::FenceSet() {
if (!mGL || !mGL->MakeCurrent()) {
return;
}
auto* egl = gl::GLLibraryEGL::Get();
if (egl->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) &&
egl->IsExtensionSupported(GLLibraryEGL::ANDROID_native_fence_sync)) {
if (mSync) {
MOZ_ALWAYS_TRUE(egl->fDestroySync(egl->Display(), mSync));
mSync = nullptr;
}
mSync = egl->fCreateSync(egl->Display(),
LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
if (mSync) {
mGL->fFlush();
return;
}
}
// ANDROID_native_fence_sync may not be supported so call glFinish()
// as a slow path.
mGL->fFinish();
}
void WaylandDMABufSurface::FenceWait() {
auto* egl = gl::GLLibraryEGL::Get();
// Wait on the fence, because presumably we're going to want to read this
// surface
if (mSync) {
egl->fClientWaitSync(egl->Display(), mSync, 0, LOCAL_EGL_FOREVER);
}
}
bool WaylandDMABufSurface::FenceCreate(int aFd) {
MOZ_ASSERT(aFd > 0);
auto* egl = gl::GLLibraryEGL::Get();
const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, aFd,
LOCAL_EGL_NONE};
mSync = egl->fCreateSync(egl->Display(), LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID,
attribs);
if (!mSync) {
MOZ_ASSERT(false, "Failed to create GLFence!");
return false;
}
return true;
}
void WaylandDMABufSurfaceRGBA::SetWLBuffer(struct wl_buffer* aWLBuffer) {
MOZ_ASSERT(mWLBuffer == nullptr, "WLBuffer already assigned!");
mWLBuffer = aWLBuffer;
@ -275,6 +327,13 @@ void WaylandDMABufSurfaceRGBA::ImportSurfaceDescriptor(
mStrides[i] = desc.strides()[i];
mOffsets[i] = desc.offsets()[i];
}
int fd = desc.fence().ClonePlatformHandle().release();
if (fd > 0) {
if (!FenceCreate(fd)) {
close(fd);
}
}
}
bool WaylandDMABufSurfaceRGBA::Create(const SurfaceDescriptor& aDesc) {
@ -314,6 +373,7 @@ bool WaylandDMABufSurfaceRGBA::Serialize(
AutoTArray<uint32_t, DMABUF_BUFFER_PLANES> strides;
AutoTArray<uint32_t, DMABUF_BUFFER_PLANES> offsets;
AutoTArray<uintptr_t, DMABUF_BUFFER_PLANES> images;
ipc::FileDescriptor fenceFD;
width.AppendElement(mWidth);
height.AppendElement(mHeight);
@ -324,9 +384,15 @@ bool WaylandDMABufSurfaceRGBA::Serialize(
offsets.AppendElement(mOffsets[i]);
}
if (mSync) {
auto* egl = gl::GLLibraryEGL::Get();
fenceFD = ipc::FileDescriptor(
egl->fDupNativeFenceFDANDROID(egl->Display(), mSync));
}
aOutDescriptor = SurfaceDescriptorDMABuf(
mSurfaceType, mBufferModifier, mGbmBufferFlags, fds, width, height,
format, strides, offsets, GetYUVColorSpace());
format, strides, offsets, GetYUVColorSpace(), fenceFD);
return true;
}
@ -420,6 +486,8 @@ bool WaylandDMABufSurfaceRGBA::CreateTexture(GLContext* aGLContext,
}
void WaylandDMABufSurfaceRGBA::ReleaseTextures() {
FenceDelete();
if (mTexture && mGL->MakeCurrent()) {
mGL->fDeleteTextures(1, &mTexture);
mTexture = 0;
@ -639,6 +707,13 @@ void WaylandDMABufSurfaceNV12::ImportSurfaceDescriptor(
mStrides[i] = aDesc.strides()[i];
mOffsets[i] = aDesc.offsets()[i];
}
int fd = aDesc.fence().ClonePlatformHandle().release();
if (fd > 0) {
if (!FenceCreate(fd)) {
close(fd);
}
}
}
bool WaylandDMABufSurfaceNV12::Serialize(
@ -649,6 +724,7 @@ bool WaylandDMABufSurfaceNV12::Serialize(
AutoTArray<ipc::FileDescriptor, DMABUF_BUFFER_PLANES> fds;
AutoTArray<uint32_t, DMABUF_BUFFER_PLANES> strides;
AutoTArray<uint32_t, DMABUF_BUFFER_PLANES> offsets;
ipc::FileDescriptor fenceFD;
for (int i = 0; i < mBufferPlaneCount; i++) {
width.AppendElement(mWidth[i]);
@ -659,10 +735,15 @@ bool WaylandDMABufSurfaceNV12::Serialize(
offsets.AppendElement(mOffsets[i]);
}
aOutDescriptor =
SurfaceDescriptorDMABuf(mSurfaceType, mBufferModifier, 0, fds, width,
height, format, strides, offsets, mColorSpace);
if (mSync) {
auto* egl = gl::GLLibraryEGL::Get();
fenceFD = ipc::FileDescriptor(
egl->fDupNativeFenceFDANDROID(egl->Display(), mSync));
}
aOutDescriptor = SurfaceDescriptorDMABuf(mSurfaceType, mBufferModifier, 0,
fds, width, height, format, strides,
offsets, mColorSpace, fenceFD);
return true;
}
@ -743,6 +824,8 @@ bool WaylandDMABufSurfaceNV12::CreateTexture(GLContext* aGLContext,
}
void WaylandDMABufSurfaceNV12::ReleaseTextures() {
FenceDelete();
if (mGL->MakeCurrent()) {
for (int i = 0; i < mBufferPlaneCount; i++) {
if (mTexture[i]) {

View File

@ -13,6 +13,7 @@
#include "mozilla/widget/nsWaylandDisplay.h"
typedef void* EGLImageKHR;
typedef void* EGLSyncKHR;
#define DMABUF_BUFFER_PLANES 4
@ -77,13 +78,28 @@ class WaylandDMABufSurface {
};
virtual bool IsFullRange() { return false; };
WaylandDMABufSurface(SurfaceType aSurfaceType);
void FenceSet();
void FenceWait();
void FenceDelete();
WaylandDMABufSurface(SurfaceType aSurfaceType)
: mSurfaceType(aSurfaceType),
mBufferModifier(0),
mBufferPlaneCount(0),
mStrides(),
mOffsets(),
mSync(0) {
for (auto& slot : mDmabufFds) {
slot = -1;
}
}
protected:
virtual bool Create(const mozilla::layers::SurfaceDescriptor& aDesc) = 0;
virtual void ReleaseSurface() = 0;
bool FenceCreate(int aFd);
virtual ~WaylandDMABufSurface(){};
virtual ~WaylandDMABufSurface() { FenceDelete(); };
SurfaceType mSurfaceType;
uint64_t mBufferModifier;
@ -93,6 +109,7 @@ class WaylandDMABufSurface {
uint32_t mStrides[DMABUF_BUFFER_PLANES];
uint32_t mOffsets[DMABUF_BUFFER_PLANES];
EGLSyncKHR mSync;
RefPtr<mozilla::gl::GLContext> mGL;
};
@ -172,7 +189,6 @@ class WaylandDMABufSurfaceRGBA : public WaylandDMABufSurface {
struct gbm_bo* mGbmBufferObject;
uint32_t mGbmBufferFlags;
RefPtr<mozilla::gl::GLContext> mGL;
EGLImageKHR mEGLImage;
GLuint mTexture;
@ -227,7 +243,6 @@ class WaylandDMABufSurfaceNV12 : public WaylandDMABufSurface {
EGLImageKHR mEGLImage[DMABUF_BUFFER_PLANES];
GLuint mTexture[DMABUF_BUFFER_PLANES];
mozilla::gfx::YUVColorSpace mColorSpace;
RefPtr<mozilla::gl::GLContext> mGL;
};
#endif