/* -*- 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/. */ /* SharedSurface abstracts an actual surface (can be a GL texture, but * not necessarily) that handles sharing. * Its specializations are: * SharedSurface_Basic (client-side bitmap, does readback) * SharedSurface_GLTexture * SharedSurface_EGLImage * SharedSurface_ANGLEShareHandle */ #ifndef SHARED_SURFACE_H_ #define SHARED_SURFACE_H_ #include <queue> #include <set> #include <stdint.h> #include "GLContextTypes.h" #include "GLDefs.h" #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" #include "mozilla/gfx/Point.h" #include "mozilla/Mutex.h" #include "mozilla/UniquePtr.h" #include "mozilla/WeakPtr.h" #include "ScopedGLHelpers.h" #include "SurfaceTypes.h" class nsIThread; namespace mozilla { namespace gfx { class DataSourceSurface; class DrawTarget; } // namespace gfx namespace layers { class LayersIPCChannel; class SharedSurfaceTextureClient; enum class TextureFlags : uint32_t; class SurfaceDescriptor; class TextureClient; } // namespace layers namespace gl { class GLContext; class SurfaceFactory; class ShSurfHandle; class SharedSurface { public: static void ProdCopy(SharedSurface* src, SharedSurface* dest, SurfaceFactory* factory); const SharedSurfaceType mType; const AttachmentType mAttachType; const WeakPtr<GLContext> mGL; const gfx::IntSize mSize; const bool mHasAlpha; const bool mCanRecycle; protected: bool mIsLocked; bool mIsProducerAcquired; #ifdef DEBUG nsIThread* const mOwningThread; #endif SharedSurface(SharedSurfaceType type, AttachmentType attachType, GLContext* gl, const gfx::IntSize& size, bool hasAlpha, bool canRecycle); public: virtual ~SharedSurface() { } // Specifies to the TextureClient any flags which // are required by the SharedSurface backend. virtual layers::TextureFlags GetTextureFlags() const; bool IsLocked() const { return mIsLocked; } bool IsProducerAcquired() const { return mIsProducerAcquired; } // This locks the SharedSurface as the production buffer for the context. // This is needed by backends which use PBuffers and/or EGLSurfaces. void LockProd(); // Unlocking is harmless if we're already unlocked. void UnlockProd(); protected: virtual void LockProdImpl() = 0; virtual void UnlockProdImpl() = 0; virtual void ProducerAcquireImpl() = 0; virtual void ProducerReleaseImpl() = 0; virtual void ProducerReadAcquireImpl() { ProducerAcquireImpl(); } virtual void ProducerReadReleaseImpl() { ProducerReleaseImpl(); } public: void ProducerAcquire() { MOZ_ASSERT(!mIsProducerAcquired); ProducerAcquireImpl(); mIsProducerAcquired = true; } void ProducerRelease() { MOZ_ASSERT(mIsProducerAcquired); ProducerReleaseImpl(); mIsProducerAcquired = false; } void ProducerReadAcquire() { MOZ_ASSERT(!mIsProducerAcquired); ProducerReadAcquireImpl(); mIsProducerAcquired = true; } void ProducerReadRelease() { MOZ_ASSERT(mIsProducerAcquired); ProducerReadReleaseImpl(); mIsProducerAcquired = false; } // This function waits until the buffer is no longer being used. // To optimize the performance, some implementaions recycle SharedSurfaces // even when its buffer is still being used. virtual void WaitForBufferOwnership() {} // For use when AttachType is correct. virtual GLenum ProdTextureTarget() const { MOZ_ASSERT(mAttachType == AttachmentType::GLTexture); return LOCAL_GL_TEXTURE_2D; } virtual GLuint ProdTexture() { MOZ_ASSERT(mAttachType == AttachmentType::GLTexture); MOZ_CRASH("GFX: Did you forget to override this function?"); } virtual GLuint ProdRenderbuffer() { MOZ_ASSERT(mAttachType == AttachmentType::GLRenderbuffer); MOZ_CRASH("GFX: Did you forget to override this function?"); } virtual bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { return false; } virtual bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) { return false; } virtual bool NeedsIndirectReads() const { return false; } virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) = 0; virtual bool ReadbackBySharedHandle(gfx::DataSourceSurface* out_surface) { return false; } }; template<typename T> class RefSet { std::set<T*> mSet; public: ~RefSet() { clear(); } auto begin() -> decltype(mSet.begin()) { return mSet.begin(); } void clear() { for (auto itr = mSet.begin(); itr != mSet.end(); ++itr) { (*itr)->Release(); } mSet.clear(); } bool empty() const { return mSet.empty(); } bool insert(T* x) { if (mSet.insert(x).second) { x->AddRef(); return true; } return false; } bool erase(T* x) { if (mSet.erase(x)) { x->Release(); return true; } return false; } }; template<typename T> class RefQueue { std::queue<T*> mQueue; public: ~RefQueue() { clear(); } void clear() { while (!empty()) { pop(); } } bool empty() const { return mQueue.empty(); } size_t size() const { return mQueue.size(); } void push(T* x) { mQueue.push(x); x->AddRef(); } T* front() const { return mQueue.front(); } void pop() { T* x = mQueue.front(); x->Release(); mQueue.pop(); } }; class SurfaceFactory : public SupportsWeakPtr<SurfaceFactory> { public: // Should use the VIRTUAL version, but it's currently incompatible // with SupportsWeakPtr. (bug 1049278) MOZ_DECLARE_WEAKREFERENCE_TYPENAME(SurfaceFactory) const SharedSurfaceType mType; GLContext* const mGL; const SurfaceCaps mCaps; const RefPtr<layers::LayersIPCChannel> mAllocator; const layers::TextureFlags mFlags; const GLFormats mFormats; Mutex mMutex; protected: SurfaceCaps mDrawCaps; SurfaceCaps mReadCaps; RefQueue<layers::SharedSurfaceTextureClient> mRecycleFreePool; RefSet<layers::SharedSurfaceTextureClient> mRecycleTotalPool; SurfaceFactory(SharedSurfaceType type, GLContext* gl, const SurfaceCaps& caps, const RefPtr<layers::LayersIPCChannel>& allocator, const layers::TextureFlags& flags); public: virtual ~SurfaceFactory(); const SurfaceCaps& DrawCaps() const { return mDrawCaps; } const SurfaceCaps& ReadCaps() const { return mReadCaps; } protected: virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) = 0; void StartRecycling(layers::SharedSurfaceTextureClient* tc); void SetRecycleCallback(layers::SharedSurfaceTextureClient* tc); void StopRecycling(layers::SharedSurfaceTextureClient* tc); public: UniquePtr<SharedSurface> NewSharedSurface(const gfx::IntSize& size); //already_AddRefed<ShSurfHandle> NewShSurfHandle(const gfx::IntSize& size); already_AddRefed<layers::SharedSurfaceTextureClient> NewTexClient(const gfx::IntSize& size); static void RecycleCallback(layers::TextureClient* tc, void* /*closure*/); // Auto-deletes surfs of the wrong type. bool Recycle(layers::SharedSurfaceTextureClient* texClient); }; class ScopedReadbackFB { GLContext* const mGL; ScopedBindFramebuffer mAutoFB; GLuint mTempFB; GLuint mTempTex; SharedSurface* mSurfToUnlock; SharedSurface* mSurfToLock; public: explicit ScopedReadbackFB(SharedSurface* src); ~ScopedReadbackFB(); }; bool ReadbackSharedSurface(SharedSurface* src, gfx::DrawTarget* dst); uint32_t ReadPixel(SharedSurface* src); } // namespace gl } // namespace mozilla #endif // SHARED_SURFACE_H_