Bug 1187440 - Implement GLX shared surfaces on the OpenGL compositor. r=jgilbert,nical

This commit is contained in:
Andrew Comminos 2015-07-30 12:40:56 -04:00
parent 80080b0e89
commit 5d264f12d4
14 changed files with 267 additions and 13 deletions

View File

@ -685,9 +685,10 @@ CreateOffscreen(GLContext* gl, const WebGLContextOptions& options,
if (!baseCaps.alpha)
baseCaps.premultAlpha = true;
if (gl->IsANGLE()) {
if (gl->IsANGLE() || gl->GetContextType() == GLContextType::GLX) {
// We can't use no-alpha formats on ANGLE yet because of:
// https://code.google.com/p/angleproject/issues/detail?id=764
// GLX only supports GL_RGBA pixmaps as well.
baseCaps.alpha = true;
}
@ -949,12 +950,12 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
mOptionsFrozen = true;
// Update our internal stuff:
if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
if (gl->WorkAroundDriverBugs()) {
if (!mOptions.alpha && gl->Caps().alpha)
mNeedsFakeNoAlpha = true;
// ANGLE doesn't quite handle this properly.
if (gl->Caps().depth && !gl->Caps().stencil)
if (gl->Caps().depth && !gl->Caps().stencil && gl->IsANGLE())
mNeedsFakeNoStencil = true;
}

View File

@ -50,6 +50,13 @@ public:
virtual bool SwapBuffers() override;
// Overrides the current GLXDrawable backing the context and makes the
// context current.
bool OverrideDrawable(GLXDrawable drawable);
// Undoes the effect of a drawable override.
bool RestoreDrawable();
virtual Maybe<gfx::IntSize> GetTargetSize() override;
private:

View File

@ -30,6 +30,7 @@
#include "GLContextGLX.h"
#include "gfxUtils.h"
#include "gfx2DGlue.h"
#include "GLScreenBuffer.h"
#include "gfxCrashReporterUtils.h"
@ -926,6 +927,21 @@ GLContextGLX::GetTargetSize()
return size;
}
bool
GLContextGLX::OverrideDrawable(GLXDrawable drawable)
{
if (Screen())
Screen()->AssureBlitted();
Bool result = mGLX->xMakeCurrent(mDisplay, drawable, mContext);
return result;
}
bool
GLContextGLX::RestoreDrawable()
{
return mGLX->xMakeCurrent(mDisplay, mDrawable, mContext);
}
GLContextGLX::GLContextGLX(
const SurfaceCaps& caps,
GLContext* shareContext,

View File

@ -790,7 +790,8 @@ ReadBuffer::SetReadBuffer(GLenum userMode) const
switch (userMode) {
case LOCAL_GL_BACK:
internalMode = (mFB == 0) ? LOCAL_GL_BACK
case LOCAL_GL_FRONT:
internalMode = (mFB == 0) ? userMode
: LOCAL_GL_COLOR_ATTACHMENT0;
break;

110
gfx/gl/SharedSurfaceGLX.cpp Normal file
View File

@ -0,0 +1,110 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SharedSurfaceGLX.h"
#include "gfxXlibSurface.h"
#include "GLXLibrary.h"
#include "GLContextProvider.h"
#include "GLContextGLX.h"
#include "GLScreenBuffer.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/layers/ShadowLayerUtilsX11.h"
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/X11Util.h"
namespace mozilla {
namespace gl {
/* static */
UniquePtr<SharedSurface_GLXDrawable>
SharedSurface_GLXDrawable::Create(GLContext* prodGL,
const SurfaceCaps& caps,
const gfx::IntSize& size,
bool deallocateClient,
bool inSameProcess)
{
UniquePtr<SharedSurface_GLXDrawable> ret;
Display* display = DefaultXDisplay();
Screen* screen = XDefaultScreenOfDisplay(display);
Visual* visual = gfxXlibSurface::FindVisual(screen, gfxImageFormat::ARGB32);
RefPtr<gfxXlibSurface> surf = gfxXlibSurface::Create(screen, visual, size);
if (!deallocateClient)
surf->ReleasePixmap();
ret.reset(new SharedSurface_GLXDrawable(prodGL, size, inSameProcess, surf));
return Move(ret);
}
SharedSurface_GLXDrawable::SharedSurface_GLXDrawable(GLContext* gl,
const gfx::IntSize& size,
bool inSameProcess,
const RefPtr<gfxXlibSurface>& xlibSurface)
: SharedSurface(SharedSurfaceType::GLXDrawable,
AttachmentType::Screen,
gl,
size,
true,
true)
, mXlibSurface(xlibSurface)
, mInSameProcess(inSameProcess)
{}
void
SharedSurface_GLXDrawable::Fence()
{
mGL->MakeCurrent();
mGL->fFlush();
}
void
SharedSurface_GLXDrawable::LockProdImpl()
{
mGL->Screen()->SetReadBuffer(LOCAL_GL_FRONT);
GLContextGLX::Cast(mGL)->OverrideDrawable(mXlibSurface->GetGLXPixmap());
}
void
SharedSurface_GLXDrawable::UnlockProdImpl()
{
GLContextGLX::Cast(mGL)->RestoreDrawable();
}
bool
SharedSurface_GLXDrawable::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
{
if (!mXlibSurface)
return false;
*out_descriptor = layers::SurfaceDescriptorX11(mXlibSurface, mInSameProcess);
return true;
}
/* static */
UniquePtr<SurfaceFactory_GLXDrawable>
SurfaceFactory_GLXDrawable::Create(GLContext* prodGL,
const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
const layers::TextureFlags& flags)
{
MOZ_ASSERT(caps.alpha, "GLX surfaces require an alpha channel!");
typedef SurfaceFactory_GLXDrawable ptrT;
UniquePtr<ptrT> ret(new ptrT(prodGL, caps, allocator,
flags & ~layers::TextureFlags::ORIGIN_BOTTOM_LEFT));
return Move(ret);
}
UniquePtr<SharedSurface>
SurfaceFactory_GLXDrawable::CreateShared(const gfx::IntSize& size)
{
bool deallocateClient = !!(mFlags & layers::TextureFlags::DEALLOCATE_CLIENT);
return SharedSurface_GLXDrawable::Create(mGL, mCaps, size, deallocateClient,
mAllocator->IsSameProcess());
}
} // namespace gl
} // namespace mozilla

67
gfx/gl/SharedSurfaceGLX.h Normal file
View File

@ -0,0 +1,67 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SHARED_SURFACE_GLX_H_
#define SHARED_SURFACE_GLX_H_
#include "SharedSurface.h"
#include "mozilla/RefPtr.h"
class gfxXlibSurface;
namespace mozilla {
namespace gl {
class SharedSurface_GLXDrawable
: public SharedSurface
{
public:
static UniquePtr<SharedSurface_GLXDrawable> Create(GLContext* prodGL,
const SurfaceCaps& caps,
const gfx::IntSize& size,
bool deallocateClient,
bool inSameProcess);
virtual void Fence() override;
virtual bool WaitSync() override { return true; }
virtual bool PollSync() override { return true; }
virtual void LockProdImpl() override;
virtual void UnlockProdImpl() override;
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
private:
SharedSurface_GLXDrawable(GLContext* gl,
const gfx::IntSize& size,
bool inSameProcess,
const RefPtr<gfxXlibSurface>& xlibSurface);
RefPtr<gfxXlibSurface> mXlibSurface;
bool mInSameProcess;
};
class SurfaceFactory_GLXDrawable
: public SurfaceFactory
{
public:
static UniquePtr<SurfaceFactory_GLXDrawable> Create(GLContext* prodGL,
const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
const layers::TextureFlags& flags);
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override;
private:
SurfaceFactory_GLXDrawable(GLContext* prodGL, const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
const layers::TextureFlags& flags)
: SurfaceFactory(SharedSurfaceType::GLXDrawable, prodGL, caps, allocator, flags)
{ }
};
} // namespace gl
} // namespace mozilla
#endif // SHARED_SURFACE_GLX_H_

View File

@ -76,6 +76,7 @@ enum class SharedSurfaceType : uint8_t {
DXGLInterop2,
Gralloc,
IOSurface,
GLXDrawable,
Max
};

View File

@ -108,6 +108,10 @@ elif gl_provider == 'GLX':
# as it includes X11 headers which cause conflicts.
SOURCES += [
'GLContextProviderGLX.cpp',
'SharedSurfaceGLX.cpp'
]
EXPORTS += [
'SharedSurfaceGLX.h'
]
else:
UNIFIED_SOURCES += [

View File

@ -32,6 +32,11 @@
#include "SharedSurfaceIO.h"
#endif
#ifdef GL_PROVIDER_GLX
#include "GLXLibrary.h"
#include "SharedSurfaceGLX.h"
#endif
using namespace mozilla::gfx;
using namespace mozilla::gl;
@ -86,6 +91,9 @@ ClientCanvasLayer::Initialize(const Data& aData)
factory = SurfaceFactory_IOSurface::Create(mGLContext, caps, forwarder, mFlags);
#elif defined(MOZ_WIDGET_GONK)
factory = MakeUnique<SurfaceFactory_Gralloc>(mGLContext, caps, forwarder, mFlags);
#elif defined(GL_PROVIDER_GLX)
if (sGLXLibrary.UseTextureFromPixmap())
factory = SurfaceFactory_GLXDrawable::Create(mGLContext, caps, forwarder, mFlags);
#else
if (mGLContext->GetContextType() == GLContextType::EGL) {
if (XRE_IsParentProcess()) {

View File

@ -62,9 +62,11 @@ GetXRenderPictFormatFromId(Display* aDisplay, PictFormat aFormatId)
return XRenderFindFormat(aDisplay, PictFormatID, &tmplate, 0);
}
SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf)
SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf,
bool aForwardGLX)
: mId(aSurf->XDrawable())
, mSize(aSurf->GetSize())
, mGLXPixmap(None)
{
const XRenderPictFormat *pictFormat = aSurf->XRenderFormat();
if (pictFormat) {
@ -72,6 +74,10 @@ SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf)
} else {
mFormat = cairo_xlib_surface_get_visual(aSurf->CairoSurface())->visualid;
}
if (aForwardGLX) {
mGLXPixmap = aSurf->GetGLXPixmap();
}
}
SurfaceDescriptorX11::SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
@ -79,6 +85,7 @@ SurfaceDescriptorX11::SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
: mId(aDrawable)
, mFormat(aFormatID)
, mSize(aSize)
, mGLXPixmap(None)
{ }
already_AddRefed<gfxXlibSurface>
@ -100,6 +107,12 @@ SurfaceDescriptorX11::OpenForeign() const
surf = new gfxXlibSurface(display, mId, visual, mSize);
}
#ifdef GL_PROVIDER_GLX
if (mGLXPixmap)
surf->BindGLXPixmap(mGLXPixmap);
#endif
return surf->CairoStatus() ? nullptr : surf.forget();
}

View File

@ -31,7 +31,7 @@ struct SurfaceDescriptorX11 {
SurfaceDescriptorX11()
{ }
explicit SurfaceDescriptorX11(gfxXlibSurface* aSurf);
explicit SurfaceDescriptorX11(gfxXlibSurface* aSurf, bool aForwardGLX = false);
SurfaceDescriptorX11(Drawable aDrawable, XID aFormatID,
const gfx::IntSize& aSize);
@ -52,6 +52,7 @@ struct SurfaceDescriptorX11 {
Drawable mId;
XID mFormat; // either a PictFormat or VisualID
gfx::IntSize mSize;
Drawable mGLXPixmap; // used to prevent multiple bindings to the same GLXPixmap in-process
};
} // namespace layers
@ -67,12 +68,15 @@ struct ParamTraits<mozilla::layers::SurfaceDescriptorX11> {
WriteParam(aMsg, aParam.mId);
WriteParam(aMsg, aParam.mSize);
WriteParam(aMsg, aParam.mFormat);
WriteParam(aMsg, aParam.mGLXPixmap);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult) {
return (ReadParam(aMsg, aIter, &aResult->mId) &&
ReadParam(aMsg, aIter, &aResult->mSize) &&
ReadParam(aMsg, aIter, &aResult->mFormat));
ReadParam(aMsg, aIter, &aResult->mFormat) &&
ReadParam(aMsg, aIter, &aResult->mGLXPixmap)
);
}
};

View File

@ -33,6 +33,9 @@
#include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
#endif
#ifdef GL_PROVIDER_GLX
#include "mozilla/layers/X11TextureHost.h"
#endif
using namespace mozilla::gl;
using namespace mozilla::gfx;
@ -93,6 +96,14 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
break;
}
#endif
#ifdef GL_PROVIDER_GLX
case SurfaceDescriptor::TSurfaceDescriptorX11: {
const auto& desc = aDesc.get_SurfaceDescriptorX11();
result = new X11TextureHost(aFlags, desc);
break;
#endif
}
default: return nullptr;
}
return result.forget();

View File

@ -80,13 +80,13 @@ gfxXlibSurface::gfxXlibSurface(cairo_surface_t *csurf)
gfxXlibSurface::~gfxXlibSurface()
{
#if defined(GL_PROVIDER_GLX)
if (mGLXPixmap) {
gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap);
}
#endif
// gfxASurface's destructor calls RecordMemoryFreed().
if (mPixmapTaken) {
#if defined(GL_PROVIDER_GLX)
if (mGLXPixmap) {
gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap);
}
#endif
XFreePixmap (mDisplay, mDrawable);
}
}
@ -271,7 +271,7 @@ void
gfxXlibSurface::Finish()
{
#if defined(GL_PROVIDER_GLX)
if (mGLXPixmap) {
if (mPixmapTaken && mGLXPixmap) {
gl::sGLXLibrary.DestroyPixmap(mDisplay, mGLXPixmap);
mGLXPixmap = None;
}
@ -605,4 +605,12 @@ gfxXlibSurface::GetGLXPixmap()
}
return mGLXPixmap;
}
void
gfxXlibSurface::BindGLXPixmap(GLXPixmap aPixmap)
{
MOZ_ASSERT(!mGLXPixmap, "A GLXPixmap is already bound!");
mGLXPixmap = aPixmap;
}
#endif

View File

@ -87,6 +87,9 @@ public:
#if defined(GL_PROVIDER_GLX)
GLXPixmap GetGLXPixmap();
// Binds a GLXPixmap backed by this context's surface.
// Primarily for use in sharing surfaces.
void BindGLXPixmap(GLXPixmap aPixmap);
#endif
// Return true if cairo will take its slow path when this surface is used