diff --git a/gfx/2d/InlineTranslator.h b/gfx/2d/InlineTranslator.h index 202853f807f6..5a2656d0e7d1 100644 --- a/gfx/2d/InlineTranslator.h +++ b/gfx/2d/InlineTranslator.h @@ -126,13 +126,13 @@ class InlineTranslator : public Translator { mNativeFontResources.Put(aKey, aScaledFontResouce); } - void RemoveDrawTarget(ReferencePtr aRefPtr) final { + void RemoveDrawTarget(ReferencePtr aRefPtr) override { mDrawTargets.Remove(aRefPtr); } void RemovePath(ReferencePtr aRefPtr) final { mPaths.Remove(aRefPtr); } - void RemoveSourceSurface(ReferencePtr aRefPtr) final { + void RemoveSourceSurface(ReferencePtr aRefPtr) override { mSourceSurfaces.Remove(aRefPtr); } @@ -154,7 +154,7 @@ class InlineTranslator : public Translator { already_AddRefed CreateDrawTarget( ReferencePtr aRefPtr, const gfx::IntSize& aSize, - gfx::SurfaceFormat aFormat) final; + gfx::SurfaceFormat aFormat) override; mozilla::gfx::DrawTarget* GetReferenceDrawTarget() final { return mBaseDT; } diff --git a/gfx/2d/Logging.h b/gfx/2d/Logging.h index 600e7a67abb1..29dbe1a7f506 100644 --- a/gfx/2d/Logging.h +++ b/gfx/2d/Logging.h @@ -135,7 +135,8 @@ enum class LogReason : int { NativeFontResourceNotFound, UnscaledFontNotFound, ScaledFontNotFound, - InvalidLayerType, + InvalidLayerType, // 40 + PlayEventFailed, // End MustBeLessThanThis = 101, }; diff --git a/gfx/2d/RecordedEvent.h b/gfx/2d/RecordedEvent.h index 1210bbc963e9..4826702bbf3c 100644 --- a/gfx/2d/RecordedEvent.h +++ b/gfx/2d/RecordedEvent.h @@ -13,6 +13,8 @@ #include #include +#include "RecordingTypes.h" + namespace mozilla { namespace gfx { @@ -392,6 +394,35 @@ class RecordedEvent { std::vector mDashPatternStorage; }; +template +class RecordedEventDerived : public RecordedEvent { + using RecordedEvent::RecordedEvent; + + public: + void RecordToStream(std::ostream& aStream) const override { + WriteElement(aStream, this->mType); + static_cast(this)->Record(aStream); + } + void RecordToStream(EventStream& aStream) const override { + WriteElement(aStream, this->mType); + static_cast(this)->Record(aStream); + } + void RecordToStream(EventRingBuffer& aStream) const final { + aStream.RecordEvent(static_cast(this)); + } + void RecordToStream(MemStream& aStream) const override { + SizeCollector size; + WriteElement(size, this->mType); + static_cast(this)->Record(size); + + aStream.Resize(aStream.mLength + size.mTotalSize); + + MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize); + WriteElement(writer, this->mType); + static_cast(this)->Record(writer); + } +}; + } // namespace gfx } // namespace mozilla diff --git a/gfx/2d/RecordedEventImpl.h b/gfx/2d/RecordedEventImpl.h index c78cb9dba1e9..07d084897e36 100644 --- a/gfx/2d/RecordedEventImpl.h +++ b/gfx/2d/RecordedEventImpl.h @@ -20,35 +20,6 @@ namespace mozilla { namespace gfx { -template -class RecordedEventDerived : public RecordedEvent { - using RecordedEvent::RecordedEvent; - - public: - void RecordToStream(std::ostream& aStream) const override { - WriteElement(aStream, this->mType); - static_cast(this)->Record(aStream); - } - void RecordToStream(EventStream& aStream) const override { - WriteElement(aStream, this->mType); - static_cast(this)->Record(aStream); - } - void RecordToStream(EventRingBuffer& aStream) const final { - aStream.RecordEvent(static_cast(this)); - } - void RecordToStream(MemStream& aStream) const override { - SizeCollector size; - WriteElement(size, this->mType); - static_cast(this)->Record(size); - - aStream.Resize(aStream.mLength + size.mTotalSize); - - MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize); - WriteElement(writer, this->mType); - static_cast(this)->Record(writer); - } -}; - template class RecordedDrawingEvent : public RecordedEventDerived { public: diff --git a/gfx/layers/CanvasTranslator.cpp b/gfx/layers/CanvasTranslator.cpp new file mode 100644 index 000000000000..1bb3a6d997c4 --- /dev/null +++ b/gfx/layers/CanvasTranslator.cpp @@ -0,0 +1,238 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#include "CanvasTranslator.h" + +#include "mozilla/gfx/Logging.h" +#include "RecordedCanvasEventImpl.h" + +#if defined(XP_WIN) +# include "mozilla/gfx/DeviceManagerDx.h" +# include "mozilla/layers/TextureD3D11.h" +#endif + +namespace mozilla { +namespace layers { + +// When in a transaction we wait for a short time because we're expecting more +// events from the content process. We don't want to wait for too long in case +// other content processes are waiting for events to process. +static const TimeDuration kReadEventTimeout = TimeDuration::FromMilliseconds(5); + +static TextureData* CreateTextureData(TextureType aTextureType, + const gfx::IntSize& aSize, + gfx::SurfaceFormat aFormat) { + TextureData* textureData = nullptr; + switch (aTextureType) { +#ifdef XP_WIN + case TextureType::D3D11: { + RefPtr device = + gfx::DeviceManagerDx::Get()->GetCanvasDevice(); + MOZ_RELEASE_ASSERT(device, "Failed to get a device for canvas drawing."); + textureData = + D3D11TextureData::Create(aSize, aFormat, ALLOC_CLEAR_BUFFER, device); + break; + } +#endif + default: + MOZ_CRASH("Unsupported TextureType for CanvasTranslator."); + } + + if (!textureData) { + MOZ_CRASH("Failed to create TextureData."); + } + + return textureData; +} + +/* static */ +UniquePtr CanvasTranslator::Create( + const TextureType& aTextureType, + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem) { + TextureData* textureData = CreateTextureData(aTextureType, gfx::IntSize(1, 1), + gfx::SurfaceFormat::B8G8R8A8); + textureData->Lock(OpenMode::OPEN_READ_WRITE); + RefPtr dt = textureData->BorrowDrawTarget(); + return UniquePtr(new CanvasTranslator( + aTextureType, textureData, dt, aReadHandle, aReaderSem, aWriterSem)); +} + +CanvasTranslator::CanvasTranslator( + const TextureType& aTextureType, TextureData* aTextureData, + gfx::DrawTarget* aDT, const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem) + : gfx::InlineTranslator(aDT), + mTextureType(aTextureType), + mReferenceTextureData(aTextureData) { + mStream.InitReader(aReadHandle, aReaderSem, aWriterSem); +} + +CanvasTranslator::~CanvasTranslator() { mReferenceTextureData->Unlock(); } + +bool CanvasTranslator::TranslateRecording() { + int32_t eventType = mStream.ReadNextEvent(); + while (mStream.good()) { + bool success = RecordedEvent::DoWithEventFromStream( + mStream, static_cast(eventType), + [&](RecordedEvent* recordedEvent) -> bool { + // Make sure that the whole event was read from the stream. + if (!mStream.good()) { + return false; + } + + return recordedEvent->PlayEvent(this); + }); + + if (!success && !HandleExtensionEvent(eventType)) { + gfxDevCrash(gfx::LogReason::PlayEventFailed) + << "Failed to play canvas event type: " << eventType; + mIsValid = false; + return true; + } + + if (!mIsInTransaction) { + return mStream.StopIfEmpty(); + } + + if (!mStream.HasDataToRead()) { + // We're going to wait for the next event, so take the opportunity to + // flush the rendering. + Flush(); + if (!mStream.WaitForDataToRead(kReadEventTimeout)) { + return true; + } + } + + eventType = mStream.ReadNextEvent(); + } + + mIsValid = false; + return true; +} + +#define READ_AND_PLAY_CANVAS_EVENT_TYPE(_typeenum, _class) \ + case _typeenum: { \ + auto e = _class(mStream); \ + if (!mStream.good()) { \ + return false; \ + } \ + return e.PlayCanvasEvent(this); \ + } + +bool CanvasTranslator::HandleExtensionEvent(int32_t aType) { + // This is where we handle extensions to the Moz2D Recording events to handle + // canvas specific things. + switch (aType) { + FOR_EACH_CANVAS_EVENT(READ_AND_PLAY_CANVAS_EVENT_TYPE) + default: + return false; + } +} + +void CanvasTranslator::BeginTransaction() { mIsInTransaction = true; } + +void CanvasTranslator::Flush() { +#if defined(XP_WIN) + RefPtr device = gfx::DeviceManagerDx::Get()->GetCanvasDevice(); + RefPtr deviceContext; + device->GetImmediateContext(getter_AddRefs(deviceContext)); + deviceContext->Flush(); +#endif +} + +void CanvasTranslator::EndTransaction() { + Flush(); + mIsInTransaction = false; +} + +void CanvasTranslator::AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr, + TextureData* aTextureData) { + UniquePtr descriptor = MakeUnique(); + if (!aTextureData->Serialize(*descriptor)) { + MOZ_CRASH("Failed to serialize"); + } + + MonitorAutoLock lock(mSurfaceDescriptorsMonitor); + mSurfaceDescriptors[aRefPtr] = std::move(descriptor); + mSurfaceDescriptorsMonitor.Notify(); +} + +already_AddRefed CanvasTranslator::CreateDrawTarget( + gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize, + gfx::SurfaceFormat aFormat) { + TextureData* textureData = CreateTextureData(mTextureType, aSize, aFormat); + textureData->Lock(OpenMode::OPEN_READ_WRITE); + mTextureDatas[aRefPtr] = UniquePtr(textureData); + AddSurfaceDescriptor(aRefPtr, textureData); + RefPtr dt = textureData->BorrowDrawTarget(); + AddDrawTarget(aRefPtr, dt); + + return dt.forget(); +} + +void CanvasTranslator::RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) { + InlineTranslator::RemoveDrawTarget(aDrawTarget); + mTextureDatas.erase(aDrawTarget); +} + +TextureData* CanvasTranslator::LookupTextureData( + gfx::ReferencePtr aDrawTarget) { + TextureMap::const_iterator result = mTextureDatas.find(aDrawTarget); + if (result == mTextureDatas.end()) { + return nullptr; + } + return result->second.get(); +} + +UniquePtr CanvasTranslator::WaitForSurfaceDescriptor( + gfx::ReferencePtr aDrawTarget) { + MonitorAutoLock lock(mSurfaceDescriptorsMonitor); + DescriptorMap::iterator result; + while ((result = mSurfaceDescriptors.find(aDrawTarget)) == + mSurfaceDescriptors.end()) { + mSurfaceDescriptorsMonitor.Wait(); + } + + UniquePtr descriptor = std::move(result->second); + mSurfaceDescriptors.erase(aDrawTarget); + return descriptor; +} + +gfx::DataSourceSurface* CanvasTranslator::LookupDataSurface( + gfx::ReferencePtr aRefPtr) { + return mDataSurfaces.GetWeak(aRefPtr); +} + +void CanvasTranslator::AddDataSurface( + gfx::ReferencePtr aRefPtr, RefPtr&& aSurface) { + mDataSurfaces.Put(aRefPtr, aSurface); +} + +void CanvasTranslator::RemoveDataSurface(gfx::ReferencePtr aRefPtr) { + mDataSurfaces.Remove(aRefPtr); +} + +void CanvasTranslator::SetPreparedMap( + gfx::ReferencePtr aSurface, + UniquePtr aMap) { + mMappedSurface = aSurface; + mPreparedMap = std::move(aMap); +} + +UniquePtr CanvasTranslator::GetPreparedMap( + gfx::ReferencePtr aSurface) { + MOZ_RELEASE_ASSERT(mMappedSurface == aSurface, + "aSurface must match previously stored surface."); + + mMappedSurface = nullptr; + return std::move(mPreparedMap); +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/CanvasTranslator.h b/gfx/layers/CanvasTranslator.h new file mode 100644 index 000000000000..9d7f5e55cb5f --- /dev/null +++ b/gfx/layers/CanvasTranslator.h @@ -0,0 +1,216 @@ +/* -*- 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_layers_CanvasTranslator_h +#define mozilla_layers_CanvasTranslator_h + +#include +#include + +#include "mozilla/gfx/InlineTranslator.h" +#include "mozilla/layers/CanvasDrawEventRecorder.h" +#include "mozilla/layers/LayersSurfaces.h" +#include "mozilla/ipc/CrossProcessSemaphore.h" +#include "mozilla/Monitor.h" +#include "mozilla/UniquePtr.h" + +namespace mozilla { +namespace layers { + +class TextureData; + +class CanvasTranslator final : public gfx::InlineTranslator { + public: + /** + * Create a canvas translator for a particular TextureType, which translates + * events from a CanvasEventRingBuffer. + * + * @param aTextureType the TextureType the translator will create + * @param aReadHandle handle to the shared memory for the + * CanvasEventRingBuffer + * @param aReaderSem reading blocked semaphore for the CanvasEventRingBuffer + * @param aWriterSem writing blocked semaphore for the CanvasEventRingBuffer + * @returns the new CanvasTranslator + */ + static UniquePtr Create( + const TextureType& aTextureType, + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem); + + ~CanvasTranslator(); + + bool IsValid() { return mIsValid; } + + /** + * Translates events until no more are available or the end of a transaction + * If this returns false the caller of this is responsible for re-calling + * this function. + * + * @returns true if all events are processed and false otherwise. + */ + bool TranslateRecording(); + + /** + * Marks the beginning of rendering for a transaction. While in a transaction + * the translator will wait for a short time for events before returning. + * When not in a transaction the translator will only translate one event at a + * time. + */ + void BeginTransaction(); + + /** + * Marks the end of a transaction. + */ + void EndTransaction(); + + /** + * Flushes canvas drawing, for example to a device. + */ + void Flush(); + + /** + * Used to send data back to the writer. This is done through the same shared + * memory so the writer must wait and read the response after it has submitted + * the event that uses this. + * + * @param aData the data to be written back to the writer + * @param aSize the number of chars to write + */ + void ReturnWrite(const char* aData, size_t aSize) { + mStream.ReturnWrite(aData, aSize); + } + + /** + * Used during playback of events to create DrawTargets. For the + * CanvasTranslator this means creating TextureDatas and getting the + * DrawTargets from those. + * + * @param aRefPtr the key to store the created DrawTarget against + * @param aSize the size of the DrawTarget + * @param aFormat the surface format for the DrawTarget + * @returns the new DrawTarget + */ + already_AddRefed CreateDrawTarget( + gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize, + gfx::SurfaceFormat aFormat) final; + + /** + * Get the TextureData associated with a DrawTarget from another process. + * + * @param aDrawTarget the key used to find the TextureData + * @returns the TextureData found + */ + TextureData* LookupTextureData(gfx::ReferencePtr aDrawTarget); + + /** + * Waits for the SurfaceDescriptor associated with a DrawTarget from another + * process to be created and then returns it. + * + * @param aDrawTarget the key used to find the TextureData + * @returns the SurfaceDescriptor found + */ + UniquePtr WaitForSurfaceDescriptor( + gfx::ReferencePtr aDrawTarget); + + /** + * Removes the DrawTarget and other objects associated with a DrawTarget from + * another process. + * + * @param aDrawTarget the key to the objects to remove + */ + void RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) final; + + /** + * Removes the SourceSurface and other objects associated with a SourceSurface + * from another process. + * + * @param aRefPtr the key to the objects to remove + */ + void RemoveSourceSurface(gfx::ReferencePtr aRefPtr) final { + RemoveDataSurface(aRefPtr); + InlineTranslator::RemoveSourceSurface(aRefPtr); + } + + /** + * Gets the cached DataSourceSurface, if it exists, associated with a + * SourceSurface from another process. + * + * @param aRefPtr the key used to find the DataSourceSurface + * @returns the DataSourceSurface or nullptr if not found + */ + gfx::DataSourceSurface* LookupDataSurface(gfx::ReferencePtr aRefPtr); + + /** + * Used to cache the DataSourceSurface from a SourceSurface associated with a + * SourceSurface from another process. This is to improve performance if we + * require the data for that SourceSurface. + * + * @param aRefPtr the key used to store the DataSourceSurface + * @param aSurface the DataSourceSurface to store + */ + void AddDataSurface(gfx::ReferencePtr aRefPtr, + RefPtr&& aSurface); + + /** + * Gets the cached DataSourceSurface, if it exists, associated with a + * SourceSurface from another process. + * + * @param aRefPtr the key used to find the DataSourceSurface + * @returns the DataSourceSurface or nullptr if not found + */ + void RemoveDataSurface(gfx::ReferencePtr aRefPtr); + + /** + * Sets a ScopedMap, to be used in a later event. + * + * @param aSurface the associated surface in the other process + * @param aMap the ScopedMap to store + */ + void SetPreparedMap(gfx::ReferencePtr aSurface, + UniquePtr aMap); + + /** + * Gets the ScopedMap stored using SetPreparedMap. + * + * @param aSurface must match the surface from the SetPreparedMap call + * @returns the ScopedMap if aSurface matches otherwise nullptr + */ + UniquePtr GetPreparedMap( + gfx::ReferencePtr aSurface); + + private: + CanvasTranslator(const TextureType& aTextureType, TextureData* aTextureData, + gfx::DrawTarget* aDrawTarget, + const ipc::SharedMemoryBasic::Handle& aReadHandle, + const CrossProcessSemaphoreHandle& aReaderSem, + const CrossProcessSemaphoreHandle& aWriterSem); + + void AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr, + TextureData* atextureData); + + bool HandleExtensionEvent(int32_t aType); + + CanvasEventRingBuffer mStream; + TextureType mTextureType = TextureType::Unknown; + UniquePtr mReferenceTextureData; + typedef std::unordered_map> TextureMap; + TextureMap mTextureDatas; + nsRefPtrHashtable, gfx::DataSourceSurface> mDataSurfaces; + gfx::ReferencePtr mMappedSurface; + UniquePtr mPreparedMap; + typedef std::unordered_map> DescriptorMap; + DescriptorMap mSurfaceDescriptors; + Monitor mSurfaceDescriptorsMonitor{ + "CanvasTranslator::mSurfaceDescriptorsMonitor"}; + bool mIsValid = true; + bool mIsInTransaction = false; +}; + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_CanvasTranslator_h diff --git a/gfx/layers/RecordedCanvasEventImpl.h b/gfx/layers/RecordedCanvasEventImpl.h new file mode 100644 index 000000000000..7708dd83b8dc --- /dev/null +++ b/gfx/layers/RecordedCanvasEventImpl.h @@ -0,0 +1,380 @@ +/* -*- 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 mozilla_layers_RecordedCanvasEventImpl_h +#define mozilla_layers_RecordedCanvasEventImpl_h + +#include "mozilla/gfx/RecordedEvent.h" +#include "mozilla/gfx/RecordingTypes.h" +#include "mozilla/layers/CanvasTranslator.h" +#include "mozilla/layers/CompositorTypes.h" +#include "mozilla/layers/TextureClient.h" + +namespace mozilla { +namespace layers { + +using gfx::DrawTarget; +using gfx::IntSize; +using gfx::RecordedEvent; +using gfx::RecordedEventDerived; +using EventType = gfx::RecordedEvent::EventType; +using gfx::ReadElement; +using gfx::ReferencePtr; +using gfx::SurfaceFormat; +using gfx::WriteElement; +using ipc::SharedMemoryBasic; + +const EventType CANVAS_BEGIN_TRANSACTION = EventType::LAST; +const EventType CANVAS_END_TRANSACTION = EventType(EventType::LAST + 1); +const EventType CANVAS_FLUSH = EventType(EventType::LAST + 2); +const EventType TEXTURE_LOCK = EventType(EventType::LAST + 3); +const EventType TEXTURE_UNLOCK = EventType(EventType::LAST + 4); +const EventType CACHE_DATA_SURFACE = EventType(EventType::LAST + 5); +const EventType PREPARE_DATA_FOR_SURFACE = EventType(EventType::LAST + 6); +const EventType GET_DATA_FOR_SURFACE = EventType(EventType::LAST + 7); + +class RecordedCanvasBeginTransaction final + : public RecordedEventDerived { + public: + RecordedCanvasBeginTransaction() + : RecordedEventDerived(CANVAS_BEGIN_TRANSACTION) {} + + template + MOZ_IMPLICIT RecordedCanvasBeginTransaction(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedCanvasBeginTransaction"; } +}; + +inline bool RecordedCanvasBeginTransaction::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + aTranslator->BeginTransaction(); + return true; +} + +template +void RecordedCanvasBeginTransaction::Record(S& aStream) const {} + +template +RecordedCanvasBeginTransaction::RecordedCanvasBeginTransaction(S& aStream) + : RecordedEventDerived(CANVAS_BEGIN_TRANSACTION) {} + +class RecordedCanvasEndTransaction final + : public RecordedEventDerived { + public: + RecordedCanvasEndTransaction() + : RecordedEventDerived(CANVAS_END_TRANSACTION) {} + + template + MOZ_IMPLICIT RecordedCanvasEndTransaction(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedCanvasEndTransaction"; } +}; + +inline bool RecordedCanvasEndTransaction::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + aTranslator->EndTransaction(); + return true; +} + +template +void RecordedCanvasEndTransaction::Record(S& aStream) const {} + +template +RecordedCanvasEndTransaction::RecordedCanvasEndTransaction(S& aStream) + : RecordedEventDerived(CANVAS_END_TRANSACTION) {} + +class RecordedCanvasFlush final + : public RecordedEventDerived { + public: + RecordedCanvasFlush() : RecordedEventDerived(CANVAS_FLUSH) {} + + template + MOZ_IMPLICIT RecordedCanvasFlush(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedCanvasFlush"; } +}; + +inline bool RecordedCanvasFlush::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + aTranslator->Flush(); + return true; +} + +template +void RecordedCanvasFlush::Record(S& aStream) const {} + +template +RecordedCanvasFlush::RecordedCanvasFlush(S& aStream) + : RecordedEventDerived(CANVAS_FLUSH) {} + +class RecordedTextureLock final + : public RecordedEventDerived { + public: + RecordedTextureLock(DrawTarget* aDT, const OpenMode aMode) + : RecordedEventDerived(TEXTURE_LOCK), mDT(aDT), mMode(aMode) {} + + template + MOZ_IMPLICIT RecordedTextureLock(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "TextureLock"; } + + private: + ReferencePtr mDT; + OpenMode mMode; +}; + +inline bool RecordedTextureLock::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + TextureData* textureData = aTranslator->LookupTextureData(mDT); + if (!textureData) { + return false; + } + + textureData->Lock(mMode); + return true; +} + +template +void RecordedTextureLock::Record(S& aStream) const { + WriteElement(aStream, mDT); + WriteElement(aStream, mMode); +} + +template +RecordedTextureLock::RecordedTextureLock(S& aStream) + : RecordedEventDerived(TEXTURE_LOCK) { + ReadElement(aStream, mDT); + ReadElement(aStream, mMode); +} + +class RecordedTextureUnlock final + : public RecordedEventDerived { + public: + explicit RecordedTextureUnlock(DrawTarget* aDT) + : RecordedEventDerived(TEXTURE_UNLOCK), mDT(aDT) {} + + template + MOZ_IMPLICIT RecordedTextureUnlock(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "TextureUnlock"; } + + private: + ReferencePtr mDT; +}; + +inline bool RecordedTextureUnlock::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + TextureData* textureData = aTranslator->LookupTextureData(mDT); + if (!textureData) { + return false; + } + + textureData->Unlock(); + return true; +} + +template +void RecordedTextureUnlock::Record(S& aStream) const { + WriteElement(aStream, mDT); +} + +template +RecordedTextureUnlock::RecordedTextureUnlock(S& aStream) + : RecordedEventDerived(TEXTURE_UNLOCK) { + ReadElement(aStream, mDT); +} + +class RecordedCacheDataSurface final + : public RecordedEventDerived { + public: + explicit RecordedCacheDataSurface(gfx::SourceSurface* aSurface) + : RecordedEventDerived(CACHE_DATA_SURFACE), mSurface(aSurface) {} + + template + MOZ_IMPLICIT RecordedCacheDataSurface(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedCacheDataSurface"; } + + private: + ReferencePtr mSurface; +}; + +inline bool RecordedCacheDataSurface::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + RefPtr surface = + aTranslator->LookupSourceSurface(mSurface); + + RefPtr dataSurface = surface->GetDataSurface(); + + aTranslator->AddDataSurface(mSurface, std::move(dataSurface)); + return true; +} + +template +void RecordedCacheDataSurface::Record(S& aStream) const { + WriteElement(aStream, mSurface); +} + +template +RecordedCacheDataSurface::RecordedCacheDataSurface(S& aStream) + : RecordedEventDerived(CACHE_DATA_SURFACE) { + ReadElement(aStream, mSurface); +} + +class RecordedPrepareDataForSurface final + : public RecordedEventDerived { + public: + explicit RecordedPrepareDataForSurface(const gfx::SourceSurface* aSurface) + : RecordedEventDerived(PREPARE_DATA_FOR_SURFACE), mSurface(aSurface) {} + + template + MOZ_IMPLICIT RecordedPrepareDataForSurface(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedPrepareDataForSurface"; } + + private: + ReferencePtr mSurface; +}; + +inline bool RecordedPrepareDataForSurface::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + RefPtr dataSurface = + aTranslator->LookupDataSurface(mSurface); + if (!dataSurface) { + RefPtr surface = + aTranslator->LookupSourceSurface(mSurface); + if (!surface) { + return false; + } + + dataSurface = surface->GetDataSurface(); + if (!dataSurface) { + return false; + } + } + + auto preparedMap = MakeUnique( + dataSurface, gfx::DataSourceSurface::READ); + aTranslator->SetPreparedMap(mSurface, std::move(preparedMap)); + + return true; +} + +template +void RecordedPrepareDataForSurface::Record(S& aStream) const { + WriteElement(aStream, mSurface); +} + +template +RecordedPrepareDataForSurface::RecordedPrepareDataForSurface(S& aStream) + : RecordedEventDerived(PREPARE_DATA_FOR_SURFACE) { + ReadElement(aStream, mSurface); +} + +class RecordedGetDataForSurface final + : public RecordedEventDerived { + public: + explicit RecordedGetDataForSurface(const gfx::SourceSurface* aSurface) + : RecordedEventDerived(GET_DATA_FOR_SURFACE), mSurface(aSurface) {} + + template + MOZ_IMPLICIT RecordedGetDataForSurface(S& aStream); + + bool PlayCanvasEvent(CanvasTranslator* aTranslator) const; + + template + void Record(S& aStream) const; + + std::string GetName() const final { return "RecordedGetDataForSurface"; } + + private: + ReferencePtr mSurface; +}; + +inline bool RecordedGetDataForSurface::PlayCanvasEvent( + CanvasTranslator* aTranslator) const { + RefPtr surface = + aTranslator->LookupSourceSurface(mSurface); + if (!surface) { + return false; + } + + UniquePtr map = + aTranslator->GetPreparedMap(mSurface); + + gfx::IntSize ssSize = surface->GetSize(); + size_t dataFormatWidth = ssSize.width * BytesPerPixel(surface->GetFormat()); + int32_t srcStride = map->GetStride(); + char* src = reinterpret_cast(map->GetData()); + char* endSrc = src + (ssSize.height * srcStride); + while (src < endSrc) { + aTranslator->ReturnWrite(src, dataFormatWidth); + src += srcStride; + } + + return true; +} + +template +void RecordedGetDataForSurface::Record(S& aStream) const { + WriteElement(aStream, mSurface); +} + +template +RecordedGetDataForSurface::RecordedGetDataForSurface(S& aStream) + : RecordedEventDerived(GET_DATA_FOR_SURFACE) { + ReadElement(aStream, mSurface); +} + +#define FOR_EACH_CANVAS_EVENT(f) \ + f(CANVAS_BEGIN_TRANSACTION, RecordedCanvasBeginTransaction); \ + f(CANVAS_END_TRANSACTION, RecordedCanvasEndTransaction); \ + f(CANVAS_FLUSH, RecordedCanvasFlush); \ + f(TEXTURE_LOCK, RecordedTextureLock); \ + f(TEXTURE_UNLOCK, RecordedTextureUnlock); \ + f(CACHE_DATA_SURFACE, RecordedCacheDataSurface); \ + f(PREPARE_DATA_FOR_SURFACE, RecordedPrepareDataForSurface); \ + f(GET_DATA_FOR_SURFACE, RecordedGetDataForSurface); + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_RecordedCanvasEventImpl_h