/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* 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 MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ #define MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_ #include "LayersTypes.h" #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/Mutex.h" #include "nsCOMPtr.h" // for nsCOMPtr class nsICanvasRenderingContextInternal; class nsIInputStream; class nsIThread; namespace mozilla { namespace gfx { class DataSourceSurface; } namespace gl { class GLContext; } namespace dom { class HTMLCanvasElement; } namespace layers { class CanvasClient; class TextureClient; /** * Since HTMLCanvasElement and OffscreenCanvas are not thread-safe, we create * AsyncCanvasRenderer which is thread-safe wrapper object for communicating * among main, worker and ImageBridgeChild threads. * * Each HTMLCanvasElement object is responsible for creating * AsyncCanvasRenderer object. Once Canvas is transfered to worker, * OffscreenCanvas will keep reference pointer of this object. * * Sometimes main thread needs AsyncCanvasRenderer's result, such as layers * fallback to BasicLayerManager or calling toDataURL in Javascript. Simply call * GetSurface() in main thread will readback the result to mSurface. * * If layers backend is LAYERS_CLIENT, this object will pass to ImageBridgeChild * for submitting frames to Compositor. */ class AsyncCanvasRenderer final { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncCanvasRenderer) public: AsyncCanvasRenderer(); void NotifyElementAboutAttributesChanged(); void NotifyElementAboutInvalidation(); void SetCanvasClient(CanvasClient* aClient); void SetWidth(uint32_t aWidth) { mWidth = aWidth; } void SetHeight(uint32_t aHeight) { mHeight = aHeight; } void SetIsAlphaPremultiplied(bool aIsAlphaPremultiplied) { mIsAlphaPremultiplied = aIsAlphaPremultiplied; } // Active thread means the thread which spawns GLContext. void SetActiveThread(); void ResetActiveThread(); // This will readback surface and return the surface // in the DataSourceSurface. // Can be called in main thread only. already_AddRefed<gfx::DataSourceSurface> GetSurface(); // For SharedSurface_Basic case, before the frame sending to the compositor, // we readback it to a texture client because SharedSurface_Basic cannot shared. // We don't want to readback it again here, so just copy the content of that // texture client here to avoid readback again. void CopyFromTextureClient(TextureClient *aClient); // Readback current WebGL's content and convert it to InputStream. This // function called GetSurface implicitly and GetSurface handles only get // called in the main thread. So this function can be called in main thread. nsresult GetInputStream(const char *aMimeType, const char16_t *aEncoderOptions, nsIInputStream **aStream); gfx::IntSize GetSize() const { return gfx::IntSize(mWidth, mHeight); } uint64_t GetCanvasClientAsyncID() const { return mCanvasClientAsyncID; } CanvasClient* GetCanvasClient() const { return mCanvasClient; } already_AddRefed<nsIThread> GetActiveThread(); // The lifetime is controllered by HTMLCanvasElement. // Only accessed in main thread. dom::HTMLCanvasElement* mHTMLCanvasElement; // Only accessed in active thread. nsICanvasRenderingContextInternal* mContext; // We need to keep a reference to the context around here, otherwise the // canvas' surface texture destructor will deref and destroy it too early // Only accessed in active thread. RefPtr<gl::GLContext> mGLContext; private: virtual ~AsyncCanvasRenderer(); // Readback current WebGL's content and return it as DataSourceSurface. already_AddRefed<gfx::DataSourceSurface> UpdateTarget(); bool mIsAlphaPremultiplied; uint32_t mWidth; uint32_t mHeight; uint64_t mCanvasClientAsyncID; // The lifetime of this pointer is controlled by OffscreenCanvas // Can be accessed in active thread and ImageBridge thread. // But we never accessed it at the same time on both thread. So no // need to protect this member. CanvasClient* mCanvasClient; // When backend is LAYER_BASIC and SharedSurface type is Basic. // CanvasClient will readback the GLContext to a TextureClient // in order to send frame to compositor. To avoid readback again, // we copy from this TextureClient to this mSurfaceForBasic directly // by calling CopyFromTextureClient(). RefPtr<gfx::DataSourceSurface> mSurfaceForBasic; // Protect non thread-safe objects. Mutex mMutex; // Can be accessed in any thread, need protect by mutex. nsCOMPtr<nsIThread> mActiveThread; }; } // namespace layers } // namespace mozilla #endif // MOZILLA_LAYERS_ASYNCCANVASRENDERER_H_