/* -*- 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 GFX_WR_IPCRESOURCEUPDATEQUEUE_H #define GFX_WR_IPCRESOURCEUPDATEQUEUE_H #include "mozilla/layers/WebRenderMessages.h" #include "mozilla/layers/RefCountedShmem.h" #include "mozilla/layers/TextureClient.h" #include "mozilla/webrender/WebRenderTypes.h" namespace mozilla { namespace ipc { class IShmemAllocator; } namespace layers { class TextureClient; class WebRenderBridgeChild; } // namespace layers namespace wr { /// ShmSegmentsWriter pushes bytes in a sequence of fixed size shmems for small /// allocations and creates dedicated shmems for large allocations. class ShmSegmentsWriter { public: ShmSegmentsWriter(layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize); ~ShmSegmentsWriter(); ShmSegmentsWriter(ShmSegmentsWriter&& aOther) noexcept; ShmSegmentsWriter& operator=(ShmSegmentsWriter&& aOther) noexcept; ShmSegmentsWriter(const ShmSegmentsWriter& aOther) = delete; ShmSegmentsWriter& operator=(const ShmSegmentsWriter& aOther) = delete; layers::OffsetRange Write(Range aBytes); template layers::OffsetRange WriteAsBytes(Range aValues) { return Write(Range((uint8_t*)aValues.begin().get(), aValues.length() * sizeof(T))); } void Flush(nsTArray& aSmallAllocs, nsTArray& aLargeAllocs); void Clear(); bool IsEmpty() const; layers::WebRenderBridgeChild* WrBridge() const { return mShmAllocator; } size_t ChunkSize() const { return mChunkSize; } protected: bool AllocChunk(); layers::OffsetRange AllocLargeChunk(size_t aSize); nsTArray mSmallAllocs; nsTArray mLargeAllocs; layers::WebRenderBridgeChild* mShmAllocator; size_t mCursor; size_t mChunkSize; }; class ShmSegmentsReader { public: ShmSegmentsReader(const nsTArray& aSmallShmems, const nsTArray& aLargeShmems); bool Read(const layers::OffsetRange& aRange, wr::Vec& aInto); // Get a read pointer, if possible, directly into the shm. If the range has // been broken up into multiple chunks that can't be represented by a single // range, nothing will be returned to indicate failure. Maybe> GetReadPointer(const layers::OffsetRange& aRange); // Get a read pointer, if possible, directly into the shm. Otherwise, copy // it into the Vec and return a pointer to that contiguous memory instead. // If all fails, return nothing. Maybe> GetReadPointerOrCopy(const layers::OffsetRange& aRange, wr::Vec& aInto) { if (Maybe> ptr = GetReadPointer(aRange)) { return ptr; } else { size_t initialLength = aInto.Length(); if (Read(aRange, aInto)) { return Some(Range(aInto.Data() + initialLength, aInto.Length() - initialLength)); } else { return Nothing(); } } } protected: bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec& aInto); Maybe> GetReadPointerLarge(const layers::OffsetRange& aRange); const nsTArray& mSmallAllocs; const nsTArray& mLargeAllocs; size_t mChunkSize; }; class IpcResourceUpdateQueue { public: // Because we are using shmems, the size should be a multiple of the page // size. Each shmem has two guard pages, and the minimum shmem size (at least // one Windows) is 64k which is already quite large for a lot of the resources // we use here. The RefCountedShmem type used to allocate the chunks keeps a // 16 bytes header in the buffer which we account for here as well. So we pick // 64k - 2 * 4k - 16 = 57328 bytes as the default alloc size. explicit IpcResourceUpdateQueue(layers::WebRenderBridgeChild* aAllocator, size_t aChunkSize = 57328); IpcResourceUpdateQueue(IpcResourceUpdateQueue&& aOther) noexcept; IpcResourceUpdateQueue& operator=(IpcResourceUpdateQueue&& aOther) noexcept; IpcResourceUpdateQueue(const IpcResourceUpdateQueue& aOther) = delete; IpcResourceUpdateQueue& operator=(const IpcResourceUpdateQueue& aOther) = delete; // Moves over everything but the subqueues void ReplaceResources(IpcResourceUpdateQueue&& aOther); bool AddImage(wr::ImageKey aKey, const ImageDescriptor& aDescriptor, Range aBytes); bool AddBlobImage(wr::BlobImageKey aKey, const ImageDescriptor& aDescriptor, Range aBytes, ImageIntRect aVisibleRect); void AddSharedExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey); void PushExternalImageForTexture(wr::ExternalImageId aExtId, wr::ImageKey aKey, layers::TextureClient* aTexture, bool aIsUpdate); bool UpdateImageBuffer(wr::ImageKey aKey, const ImageDescriptor& aDescriptor, Range aBytes); bool UpdateBlobImage(wr::BlobImageKey aKey, const ImageDescriptor& aDescriptor, Range aBytes, ImageIntRect aVisibleRect, ImageIntRect aDirtyRect); void UpdateSharedExternalImage(ExternalImageId aExtID, ImageKey aKey, ImageIntRect aDirtyRect); void SetBlobImageVisibleArea(BlobImageKey aKey, const ImageIntRect& aArea); void DeleteImage(wr::ImageKey aKey); void DeleteBlobImage(wr::BlobImageKey aKey); bool AddRawFont(wr::FontKey aKey, Range aBytes, uint32_t aIndex); bool AddFontDescriptor(wr::FontKey aKey, Range aBytes, uint32_t aIndex); void DeleteFont(wr::FontKey aKey); void AddFontInstance(wr::FontInstanceKey aKey, wr::FontKey aFontKey, float aGlyphSize, const wr::FontInstanceOptions* aOptions, const wr::FontInstancePlatformOptions* aPlatformOptions, Range aVariations); void DeleteFontInstance(wr::FontInstanceKey aKey); void Clear(); void Flush(nsTArray& aUpdates, nsTArray& aSmallAllocs, nsTArray& aLargeAllocs); bool IsEmpty() const; static void ReleaseShmems(mozilla::ipc::IProtocol*, nsTArray& aShms); static void ReleaseShmems(mozilla::ipc::IProtocol*, nsTArray& aShms); protected: ShmSegmentsWriter mWriter; nsTArray mUpdates; }; } // namespace wr } // namespace mozilla #endif