/* -*- 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/gfx/SourceSurfaceCairo.h" #include "mozilla/layers/LayersSurfaces.h" #include "mozilla/layers/ShadowLayerUtilsX11.h" #include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/TextureForwarder.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, gfx::SurfaceFormat::A8R8G8B8_UINT32); 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::ProducerReleaseImpl() { 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; } bool SharedSurface_GLXDrawable::ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) { MOZ_ASSERT(out_surface); RefPtr<gfx::DataSourceSurface> dataSurf = new gfx::DataSourceSurfaceCairo(mXlibSurface->CairoSurface()); gfx::DataSourceSurface::ScopedMap mapSrc(dataSurf, gfx::DataSourceSurface::READ); if (!mapSrc.IsMapped()) { return false; } gfx::DataSourceSurface::ScopedMap mapDest(out_surface, gfx::DataSourceSurface::WRITE); if (!mapDest.IsMapped()) { return false; } if (mapDest.GetStride() == mapSrc.GetStride()) { memcpy(mapDest.GetData(), mapSrc.GetData(), out_surface->GetSize().height * mapDest.GetStride()); } else { for (int32_t i = 0; i < dataSurf->GetSize().height; i++) { memcpy(mapDest.GetData() + i * mapDest.GetStride(), mapSrc.GetData() + i * mapSrc.GetStride(), std::min(mapSrc.GetStride(), mapDest.GetStride())); } } return true; } /* static */ UniquePtr<SurfaceFactory_GLXDrawable> SurfaceFactory_GLXDrawable::Create(GLContext* prodGL, const SurfaceCaps& caps, const RefPtr<layers::LayersIPCChannel>& 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