1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef DMABufSurface_h__
8 #define DMABufSurface_h__
9 
10 #include <stdint.h>
11 #include "mozilla/widget/nsWaylandDisplay.h"
12 #include "mozilla/widget/va_drmcommon.h"
13 #include "GLTypes.h"
14 
15 typedef void* EGLImageKHR;
16 typedef void* EGLSyncKHR;
17 
18 #define DMABUF_BUFFER_PLANES 4
19 
20 namespace mozilla {
21 namespace layers {
22 class SurfaceDescriptor;
23 class SurfaceDescriptorDMABuf;
24 }  // namespace layers
25 namespace gl {
26 class GLContext;
27 }
28 }  // namespace mozilla
29 
30 typedef enum {
31   // Use alpha pixel format
32   DMABUF_ALPHA = 1 << 0,
33   // Surface is used as texture and may be also shared
34   DMABUF_TEXTURE = 1 << 1,
35   // Use modifiers. Such dmabuf surface may have more planes
36   // and complex internal structure (tiling/compression/etc.)
37   // so we can't do direct rendering to it.
38   DMABUF_USE_MODIFIERS = 1 << 3,
39 } DMABufSurfaceFlags;
40 
41 class DMABufSurfaceRGBA;
42 class DMABufSurfaceYUV;
43 
44 class DMABufSurface {
45  public:
46   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DMABufSurface)
47 
48   enum SurfaceType {
49     SURFACE_RGBA,
50     SURFACE_NV12,
51     SURFACE_YUV420,
52   };
53 
54   // Import surface from SurfaceDescriptor. This is usually
55   // used to copy surface from another process over IPC.
56   // When a global reference counter was created for the surface
57   // (see bellow) it's automatically referenced.
58   static already_AddRefed<DMABufSurface> CreateDMABufSurface(
59       const mozilla::layers::SurfaceDescriptor& aDesc);
60 
61   // Export surface to another process via. SurfaceDescriptor.
62   virtual bool Serialize(
63       mozilla::layers::SurfaceDescriptor& aOutDescriptor) = 0;
64 
65   virtual int GetWidth(int aPlane = 0) = 0;
66   virtual int GetHeight(int aPlane = 0) = 0;
67   virtual mozilla::gfx::SurfaceFormat GetFormat() = 0;
68   virtual mozilla::gfx::SurfaceFormat GetFormatGL() = 0;
69 
70   virtual bool CreateTexture(mozilla::gl::GLContext* aGLContext,
71                              int aPlane = 0) = 0;
72   virtual void ReleaseTextures() = 0;
73   virtual GLuint GetTexture(int aPlane = 0) = 0;
74   virtual EGLImageKHR GetEGLImage(int aPlane = 0) = 0;
75 
GetSurfaceType()76   SurfaceType GetSurfaceType() { return mSurfaceType; };
77   virtual uint32_t GetTextureCount() = 0;
78 
79   bool IsMapped(int aPlane = 0) { return (mMappedRegion[aPlane] != nullptr); };
80   void Unmap(int aPlane = 0);
81 
GetAsDMABufSurfaceRGBA()82   virtual DMABufSurfaceRGBA* GetAsDMABufSurfaceRGBA() { return nullptr; }
GetAsDMABufSurfaceYUV()83   virtual DMABufSurfaceYUV* GetAsDMABufSurfaceYUV() { return nullptr; }
84 
GetYUVColorSpace()85   virtual mozilla::gfx::YUVColorSpace GetYUVColorSpace() {
86     return mozilla::gfx::YUVColorSpace::Default;
87   };
IsFullRange()88   virtual bool IsFullRange() { return false; };
89 
90   void FenceSet();
91   void FenceWait();
92   void FenceDelete();
93 
94   // Set and get a global surface UID. The UID is shared across process
95   // and it's used to track surface lifetime in various parts of rendering
96   // engine.
GetUID()97   uint32_t GetUID() const { return mUID; };
98 
99   // Creates a global reference counter objects attached to the surface.
100   // It's created as unreferenced, i.e. IsGlobalRefSet() returns false
101   // right after GlobalRefCountCreate() call.
102   //
103   // The counter is shared by all surface instances across processes
104   // so it tracks global surface usage.
105   //
106   // The counter is automatically referenced when a new surface instance is
107   // created with SurfaceDescriptor (usually copied to another process over IPC)
108   // and it's unreferenced when surface is deleted.
109   //
110   // So without any additional GlobalRefAdd()/GlobalRefRelease() calls
111   // the IsGlobalRefSet() returns true if any other process use the surface.
112   void GlobalRefCountCreate();
113 
114   // If global reference counter was created by GlobalRefCountCreate()
115   // returns true when there's an active surface reference.
116   bool IsGlobalRefSet() const;
117 
118   // Add/Remove additional reference to the surface global reference counter.
119   void GlobalRefAdd();
120   void GlobalRefRelease();
121 
122   // Release all underlying data.
123   virtual void ReleaseSurface() = 0;
124 
125 #ifdef DEBUG
DumpToFile(const char * pFile)126   virtual void DumpToFile(const char* pFile){};
127 #endif
128 
129   DMABufSurface(SurfaceType aSurfaceType);
130 
131  protected:
132   virtual bool Create(const mozilla::layers::SurfaceDescriptor& aDesc) = 0;
133   bool FenceImportFromFd();
134 
135   void GlobalRefCountImport(int aFd);
136   void GlobalRefCountDelete();
137 
138   void ReleaseDMABuf();
139 
140   void* MapInternal(uint32_t aX, uint32_t aY, uint32_t aWidth, uint32_t aHeight,
141                     uint32_t* aStride, int aGbmFlags, int aPlane = 0);
142 
143   // We want to keep number of opened file descriptors low so open/close
144   // DMABuf file handles only when we need them, i.e. when DMABuf is exported
145   // to another process or to EGL.
146   virtual bool OpenFileDescriptorForPlane(int aPlane) = 0;
147   virtual void CloseFileDescriptorForPlane(int aPlane,
148                                            bool aForceClose = false) = 0;
149   bool OpenFileDescriptors();
150   void CloseFileDescriptors(bool aForceClose = false);
151 
152   virtual ~DMABufSurface();
153 
154   SurfaceType mSurfaceType;
155   uint64_t mBufferModifier;
156 
157   int mBufferPlaneCount;
158   int mDmabufFds[DMABUF_BUFFER_PLANES];
159   uint32_t mDrmFormats[DMABUF_BUFFER_PLANES];
160   uint32_t mStrides[DMABUF_BUFFER_PLANES];
161   uint32_t mOffsets[DMABUF_BUFFER_PLANES];
162 
163   struct gbm_bo* mGbmBufferObject[DMABUF_BUFFER_PLANES];
164   void* mMappedRegion[DMABUF_BUFFER_PLANES];
165   void* mMappedRegionData[DMABUF_BUFFER_PLANES];
166   uint32_t mMappedRegionStride[DMABUF_BUFFER_PLANES];
167 
168   int mSyncFd;
169   EGLSyncKHR mSync;
170   RefPtr<mozilla::gl::GLContext> mGL;
171 
172   int mGlobalRefCountFd;
173   uint32_t mUID;
174   mozilla::Mutex mSurfaceLock;
175 };
176 
177 class DMABufSurfaceRGBA : public DMABufSurface {
178  public:
179   static already_AddRefed<DMABufSurfaceRGBA> CreateDMABufSurface(
180       int aWidth, int aHeight, int aDMABufSurfaceFlags);
181 
182   bool Serialize(mozilla::layers::SurfaceDescriptor& aOutDescriptor);
183 
GetAsDMABufSurfaceRGBA()184   DMABufSurfaceRGBA* GetAsDMABufSurfaceRGBA() { return this; }
185 
186   void Clear();
187 
188   void ReleaseSurface();
189 
190   bool CopyFrom(class DMABufSurface* aSourceSurface);
191 
192   int GetWidth(int aPlane = 0) { return mWidth; };
193   int GetHeight(int aPlane = 0) { return mHeight; };
194   mozilla::gfx::SurfaceFormat GetFormat();
195   mozilla::gfx::SurfaceFormat GetFormatGL();
196   bool HasAlpha();
197 
198   void* MapReadOnly(uint32_t aX, uint32_t aY, uint32_t aWidth, uint32_t aHeight,
199                     uint32_t* aStride = nullptr);
200   void* MapReadOnly(uint32_t* aStride = nullptr);
201   void* Map(uint32_t aX, uint32_t aY, uint32_t aWidth, uint32_t aHeight,
202             uint32_t* aStride = nullptr);
203   void* Map(uint32_t* aStride = nullptr);
204   void* GetMappedRegion(int aPlane = 0) { return mMappedRegion[aPlane]; };
205   uint32_t GetMappedRegionStride(int aPlane = 0) {
206     return mMappedRegionStride[aPlane];
207   };
208 
209   bool CreateTexture(mozilla::gl::GLContext* aGLContext, int aPlane = 0);
210   void ReleaseTextures();
211   GLuint GetTexture(int aPlane = 0) { return mTexture; };
212   EGLImageKHR GetEGLImage(int aPlane = 0) { return mEGLImage; };
213 
GetTextureCount()214   uint32_t GetTextureCount() { return 1; };
215 
216 #ifdef DEBUG
217   virtual void DumpToFile(const char* pFile);
218 #endif
219 
220   DMABufSurfaceRGBA();
221 
222  private:
223   ~DMABufSurfaceRGBA();
224 
225   bool Create(int aWidth, int aHeight, int aDMABufSurfaceFlags);
226   bool Create(const mozilla::layers::SurfaceDescriptor& aDesc);
227 
228   bool ImportSurfaceDescriptor(const mozilla::layers::SurfaceDescriptor& aDesc);
229 
230   bool OpenFileDescriptorForPlane(int aPlane);
231   void CloseFileDescriptorForPlane(int aPlane, bool aForceClose);
232 
233  private:
234   int mSurfaceFlags;
235 
236   int mWidth;
237   int mHeight;
238   mozilla::widget::GbmFormat* mGmbFormat;
239 
240   EGLImageKHR mEGLImage;
241   GLuint mTexture;
242   uint32_t mGbmBufferFlags;
243 };
244 
245 class DMABufSurfaceYUV : public DMABufSurface {
246  public:
247   static already_AddRefed<DMABufSurfaceYUV> CreateYUVSurface(
248       int aWidth, int aHeight, void** aPixelData = nullptr,
249       int* aLineSizes = nullptr);
250 
251   static already_AddRefed<DMABufSurfaceYUV> CreateYUVSurface(
252       const VADRMPRIMESurfaceDescriptor& aDesc);
253 
254   bool Serialize(mozilla::layers::SurfaceDescriptor& aOutDescriptor);
255 
GetAsDMABufSurfaceYUV()256   DMABufSurfaceYUV* GetAsDMABufSurfaceYUV() { return this; };
257 
258   int GetWidth(int aPlane = 0) { return mWidth[aPlane]; }
259   int GetHeight(int aPlane = 0) { return mHeight[aPlane]; }
260   mozilla::gfx::SurfaceFormat GetFormat();
261   mozilla::gfx::SurfaceFormat GetFormatGL();
262 
263   bool CreateTexture(mozilla::gl::GLContext* aGLContext, int aPlane = 0);
264   void ReleaseTextures();
265 
266   void ReleaseSurface();
267 
268   GLuint GetTexture(int aPlane = 0) { return mTexture[aPlane]; };
269   EGLImageKHR GetEGLImage(int aPlane = 0) { return mEGLImage[aPlane]; };
270 
271   uint32_t GetTextureCount();
272 
SetYUVColorSpace(mozilla::gfx::YUVColorSpace aColorSpace)273   void SetYUVColorSpace(mozilla::gfx::YUVColorSpace aColorSpace) {
274     mColorSpace = aColorSpace;
275   }
GetYUVColorSpace()276   mozilla::gfx::YUVColorSpace GetYUVColorSpace() { return mColorSpace; }
277 
IsFullRange()278   bool IsFullRange() { return true; }
279 
280   DMABufSurfaceYUV();
281 
282   bool UpdateYUVData(void** aPixelData, int* aLineSizes);
283   bool UpdateYUVData(const VADRMPRIMESurfaceDescriptor& aDesc);
284 
285  private:
286   ~DMABufSurfaceYUV();
287 
288   bool Create(const mozilla::layers::SurfaceDescriptor& aDesc);
289   bool Create(int aWidth, int aHeight, void** aPixelData, int* aLineSizes);
290   bool CreateYUVPlane(int aPlane, int aWidth, int aHeight, int aDrmFormat);
291   void UpdateYUVPlane(int aPlane, void* aPixelData, int aLineSize);
292 
293   bool ImportSurfaceDescriptor(
294       const mozilla::layers::SurfaceDescriptorDMABuf& aDesc);
295 
296   bool OpenFileDescriptorForPlane(int aPlane);
297   void CloseFileDescriptorForPlane(int aPlane, bool aForceClose);
298 
299   int mWidth[DMABUF_BUFFER_PLANES];
300   int mHeight[DMABUF_BUFFER_PLANES];
301   EGLImageKHR mEGLImage[DMABUF_BUFFER_PLANES];
302   GLuint mTexture[DMABUF_BUFFER_PLANES];
303   mozilla::gfx::YUVColorSpace mColorSpace =
304       mozilla::gfx::YUVColorSpace::Default;
305 };
306 
307 #endif
308