diff options
Diffstat (limited to 'widget/gtk/DMABufSurface.h')
-rw-r--r-- | widget/gtk/DMABufSurface.h | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/widget/gtk/DMABufSurface.h b/widget/gtk/DMABufSurface.h new file mode 100644 index 0000000000..e432cfad49 --- /dev/null +++ b/widget/gtk/DMABufSurface.h @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 DMABufSurface_h__ +#define DMABufSurface_h__ + +#include <stdint.h> +#include "mozilla/widget/nsWaylandDisplay.h" +#include "mozilla/widget/va_drmcommon.h" +#include "GLTypes.h" + +typedef void* EGLImageKHR; +typedef void* EGLSyncKHR; + +#define DMABUF_BUFFER_PLANES 4 + +#ifndef VA_FOURCC_NV12 +# define VA_FOURCC_NV12 0x3231564E +#endif +#ifndef VA_FOURCC_YV12 +# define VA_FOURCC_YV12 0x32315659 +#endif +#ifndef VA_FOURCC_P010 +# define VA_FOURCC_P010 0x30313050 +#endif + +namespace mozilla { +namespace gfx { +class DataSourceSurface; +} +namespace layers { +class SurfaceDescriptor; +class SurfaceDescriptorDMABuf; +} // namespace layers +namespace gl { +class GLContext; +} +} // namespace mozilla + +typedef enum { + // Use alpha pixel format + DMABUF_ALPHA = 1 << 0, + // Surface is used as texture and may be also shared + DMABUF_TEXTURE = 1 << 1, + // Use modifiers. Such dmabuf surface may have more planes + // and complex internal structure (tiling/compression/etc.) + // so we can't do direct rendering to it. + DMABUF_USE_MODIFIERS = 1 << 3, +} DMABufSurfaceFlags; + +class DMABufSurfaceRGBA; +class DMABufSurfaceYUV; + +class DMABufSurface { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DMABufSurface) + + enum SurfaceType { + SURFACE_RGBA, + SURFACE_NV12, + SURFACE_YUV420, + }; + + // Import surface from SurfaceDescriptor. This is usually + // used to copy surface from another process over IPC. + // When a global reference counter was created for the surface + // (see bellow) it's automatically referenced. + static already_AddRefed<DMABufSurface> CreateDMABufSurface( + const mozilla::layers::SurfaceDescriptor& aDesc); + + // Export surface to another process via. SurfaceDescriptor. + virtual bool Serialize( + mozilla::layers::SurfaceDescriptor& aOutDescriptor) = 0; + + virtual int GetWidth(int aPlane = 0) = 0; + virtual int GetHeight(int aPlane = 0) = 0; + virtual mozilla::gfx::SurfaceFormat GetFormat() = 0; + virtual mozilla::gfx::SurfaceFormat GetFormatGL() = 0; + + virtual bool CreateTexture(mozilla::gl::GLContext* aGLContext, + int aPlane = 0) = 0; + virtual void ReleaseTextures() = 0; + virtual GLuint GetTexture(int aPlane = 0) = 0; + virtual EGLImageKHR GetEGLImage(int aPlane = 0) = 0; + + SurfaceType GetSurfaceType() { return mSurfaceType; }; + virtual int GetTextureCount() = 0; + + bool IsMapped(int aPlane = 0) { return (mMappedRegion[aPlane] != nullptr); }; + void Unmap(int aPlane = 0); + + virtual DMABufSurfaceRGBA* GetAsDMABufSurfaceRGBA() { return nullptr; } + virtual DMABufSurfaceYUV* GetAsDMABufSurfaceYUV() { return nullptr; } + virtual already_AddRefed<mozilla::gfx::DataSourceSurface> + GetAsSourceSurface() { + return nullptr; + } + + virtual mozilla::gfx::YUVColorSpace GetYUVColorSpace() { + return mozilla::gfx::YUVColorSpace::Default; + }; + + bool IsFullRange() { return mColorRange == mozilla::gfx::ColorRange::FULL; }; + void SetColorRange(mozilla::gfx::ColorRange aColorRange) { + mColorRange = aColorRange; + }; + + void FenceSet(); + void FenceWait(); + void FenceDelete(); + + // Set and get a global surface UID. The UID is shared across process + // and it's used to track surface lifetime in various parts of rendering + // engine. + uint32_t GetUID() const { return mUID; }; + + // Creates a global reference counter objects attached to the surface. + // It's created as unreferenced, i.e. IsGlobalRefSet() returns false + // right after GlobalRefCountCreate() call. + // + // The counter is shared by all surface instances across processes + // so it tracks global surface usage. + // + // The counter is automatically referenced when a new surface instance is + // created with SurfaceDescriptor (usually copied to another process over IPC) + // and it's unreferenced when surface is deleted. + // + // So without any additional GlobalRefAdd()/GlobalRefRelease() calls + // the IsGlobalRefSet() returns true if any other process use the surface. + void GlobalRefCountCreate(); + + // If global reference counter was created by GlobalRefCountCreate() + // returns true when there's an active surface reference. + bool IsGlobalRefSet() const; + + // Add/Remove additional reference to the surface global reference counter. + void GlobalRefAdd(); + void GlobalRefRelease(); + + // Release all underlying data. + virtual void ReleaseSurface() = 0; + +#ifdef DEBUG + virtual void DumpToFile(const char* pFile){}; +#endif + + DMABufSurface(SurfaceType aSurfaceType); + + protected: + virtual bool Create(const mozilla::layers::SurfaceDescriptor& aDesc) = 0; + + // Import global ref count from IPC by file descriptor. + void GlobalRefCountImport(int aFd); + // Export global ref count by file descriptor. This adds global ref count + // reference to the surface. + // It's used when dmabuf surface is shared with another process via. IPC. + int GlobalRefCountExport(); + void GlobalRefCountDelete(); + + void ReleaseDMABuf(); + + void* MapInternal(uint32_t aX, uint32_t aY, uint32_t aWidth, uint32_t aHeight, + uint32_t* aStride, int aGbmFlags, int aPlane = 0); + + // We want to keep number of opened file descriptors low so open/close + // DMABuf file handles only when we need them, i.e. when DMABuf is exported + // to another process or to EGL. + virtual bool OpenFileDescriptorForPlane( + const mozilla::MutexAutoLock& aProofOfLock, int aPlane) = 0; + virtual void CloseFileDescriptorForPlane( + const mozilla::MutexAutoLock& aProofOfLock, int aPlane, + bool aForceClose = false) = 0; + bool OpenFileDescriptors(const mozilla::MutexAutoLock& aProofOfLock); + void CloseFileDescriptors(const mozilla::MutexAutoLock& aProofOfLock, + bool aForceClose = false); + + virtual ~DMABufSurface(); + + SurfaceType mSurfaceType; + uint64_t mBufferModifiers[DMABUF_BUFFER_PLANES]; + + int mBufferPlaneCount; + int mDmabufFds[DMABUF_BUFFER_PLANES]; + int32_t mDrmFormats[DMABUF_BUFFER_PLANES]; + int32_t mStrides[DMABUF_BUFFER_PLANES]; + int32_t mOffsets[DMABUF_BUFFER_PLANES]; + + struct gbm_bo* mGbmBufferObject[DMABUF_BUFFER_PLANES]; + void* mMappedRegion[DMABUF_BUFFER_PLANES]; + void* mMappedRegionData[DMABUF_BUFFER_PLANES]; + uint32_t mMappedRegionStride[DMABUF_BUFFER_PLANES]; + + int mSyncFd; + EGLSyncKHR mSync; + RefPtr<mozilla::gl::GLContext> mGL; + + int mGlobalRefCountFd; + uint32_t mUID; + mozilla::Mutex mSurfaceLock MOZ_UNANNOTATED; + + mozilla::gfx::ColorRange mColorRange = mozilla::gfx::ColorRange::LIMITED; +}; + +class DMABufSurfaceRGBA : public DMABufSurface { + public: + static already_AddRefed<DMABufSurfaceRGBA> CreateDMABufSurface( + int aWidth, int aHeight, int aDMABufSurfaceFlags); + + static already_AddRefed<DMABufSurface> CreateDMABufSurface( + mozilla::gl::GLContext* aGLContext, const EGLImageKHR aEGLImage, + int aWidth, int aHeight); + + bool Serialize(mozilla::layers::SurfaceDescriptor& aOutDescriptor); + + DMABufSurfaceRGBA* GetAsDMABufSurfaceRGBA() { return this; } + + void Clear(); + + void ReleaseSurface(); + + bool CopyFrom(class DMABufSurface* aSourceSurface); + + int GetWidth(int aPlane = 0) { return mWidth; }; + int GetHeight(int aPlane = 0) { return mHeight; }; + mozilla::gfx::SurfaceFormat GetFormat(); + mozilla::gfx::SurfaceFormat GetFormatGL(); + bool HasAlpha(); + + void* MapReadOnly(uint32_t aX, uint32_t aY, uint32_t aWidth, uint32_t aHeight, + uint32_t* aStride = nullptr); + void* MapReadOnly(uint32_t* aStride = nullptr); + void* Map(uint32_t aX, uint32_t aY, uint32_t aWidth, uint32_t aHeight, + uint32_t* aStride = nullptr); + void* Map(uint32_t* aStride = nullptr); + void* GetMappedRegion(int aPlane = 0) { return mMappedRegion[aPlane]; }; + uint32_t GetMappedRegionStride(int aPlane = 0) { + return mMappedRegionStride[aPlane]; + }; + + bool CreateTexture(mozilla::gl::GLContext* aGLContext, int aPlane = 0); + void ReleaseTextures(); + GLuint GetTexture(int aPlane = 0) { return mTexture; }; + EGLImageKHR GetEGLImage(int aPlane = 0) { return mEGLImage; }; + + bool CreateWlBuffer(); + void ReleaseWlBuffer(); + wl_buffer* GetWlBuffer() { return mWlBuffer; }; + + int GetTextureCount() { return 1; }; + +#ifdef DEBUG + virtual void DumpToFile(const char* pFile); +#endif + + DMABufSurfaceRGBA(); + + private: + ~DMABufSurfaceRGBA(); + + bool Create(int aWidth, int aHeight, int aDMABufSurfaceFlags); + bool Create(const mozilla::layers::SurfaceDescriptor& aDesc); + bool Create(mozilla::gl::GLContext* aGLContext, const EGLImageKHR aEGLImage, + int aWidth, int aHeight); + + bool ImportSurfaceDescriptor(const mozilla::layers::SurfaceDescriptor& aDesc); + + bool OpenFileDescriptorForPlane(const mozilla::MutexAutoLock& aProofOfLock, + int aPlane); + void CloseFileDescriptorForPlane(const mozilla::MutexAutoLock& aProofOfLock, + int aPlane, bool aForceClose); + + private: + int mSurfaceFlags; + + int mWidth; + int mHeight; + mozilla::widget::GbmFormat* mGmbFormat; + + EGLImageKHR mEGLImage; + GLuint mTexture; + uint32_t mGbmBufferFlags; + wl_buffer* mWlBuffer; +}; + +class DMABufSurfaceYUV : public DMABufSurface { + public: + static already_AddRefed<DMABufSurfaceYUV> CreateYUVSurface( + int aWidth, int aHeight, void** aPixelData = nullptr, + int* aLineSizes = nullptr); + + static already_AddRefed<DMABufSurfaceYUV> CreateYUVSurface( + const VADRMPRIMESurfaceDescriptor& aDesc, int aWidth, int aHeight); + + bool Serialize(mozilla::layers::SurfaceDescriptor& aOutDescriptor); + + DMABufSurfaceYUV* GetAsDMABufSurfaceYUV() { return this; }; + already_AddRefed<mozilla::gfx::DataSourceSurface> GetAsSourceSurface(); + + int GetWidth(int aPlane = 0) { return mWidth[aPlane]; } + int GetHeight(int aPlane = 0) { return mHeight[aPlane]; } + mozilla::gfx::SurfaceFormat GetFormat(); + mozilla::gfx::SurfaceFormat GetFormatGL(); + + bool CreateTexture(mozilla::gl::GLContext* aGLContext, int aPlane = 0); + void ReleaseTextures(); + + void ReleaseSurface(); + + GLuint GetTexture(int aPlane = 0) { return mTexture[aPlane]; }; + EGLImageKHR GetEGLImage(int aPlane = 0) { return mEGLImage[aPlane]; }; + + int GetTextureCount(); + + void SetYUVColorSpace(mozilla::gfx::YUVColorSpace aColorSpace) { + mColorSpace = aColorSpace; + } + mozilla::gfx::YUVColorSpace GetYUVColorSpace() { return mColorSpace; } + + DMABufSurfaceYUV(); + + bool UpdateYUVData(void** aPixelData, int* aLineSizes); + bool UpdateYUVData(const VADRMPRIMESurfaceDescriptor& aDesc, int aWidth, + int aHeight); + + bool VerifyTextureCreation(); + + private: + ~DMABufSurfaceYUV(); + + bool Create(const mozilla::layers::SurfaceDescriptor& aDesc); + bool Create(int aWidth, int aHeight, void** aPixelData, int* aLineSizes); + bool CreateYUVPlane(int aPlane, int aWidth, int aHeight, int aDrmFormat); + void UpdateYUVPlane(int aPlane, void* aPixelData, int aLineSize); + + bool ImportSurfaceDescriptor( + const mozilla::layers::SurfaceDescriptorDMABuf& aDesc); + + bool OpenFileDescriptorForPlane(const mozilla::MutexAutoLock& aProofOfLock, + int aPlane); + void CloseFileDescriptorForPlane(const mozilla::MutexAutoLock& aProofOfLock, + int aPlane, bool aForceClose); + + bool CreateEGLImage(mozilla::gl::GLContext* aGLContext, int aPlane); + void ReleaseEGLImages(mozilla::gl::GLContext* aGLContext); + + int mWidth[DMABUF_BUFFER_PLANES]; + int mHeight[DMABUF_BUFFER_PLANES]; + // Aligned size of the surface imported from VADRMPRIMESurfaceDescriptor. + // It's used only internally to create EGLImage as some GL drivers + // needs that (Bug 1724385). + int mWidthAligned[DMABUF_BUFFER_PLANES]; + int mHeightAligned[DMABUF_BUFFER_PLANES]; + EGLImageKHR mEGLImage[DMABUF_BUFFER_PLANES]; + GLuint mTexture[DMABUF_BUFFER_PLANES]; + mozilla::gfx::YUVColorSpace mColorSpace = + mozilla::gfx::YUVColorSpace::Default; +}; + +#endif |