summaryrefslogtreecommitdiffstats
path: root/gfx/layers/wr/IpcResourceUpdateQueue.h
blob: 6096ddbddb38d6a3f3fb46f8d3492ce7ccea6d57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/* -*- 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<uint8_t> aBytes);

  template <typename T>
  layers::OffsetRange WriteAsBytes(Range<T> aValues) {
    return Write(Range<uint8_t>((uint8_t*)aValues.begin().get(),
                                aValues.length() * sizeof(T)));
  }

  void Flush(nsTArray<layers::RefCountedShmem>& aSmallAllocs,
             nsTArray<mozilla::ipc::Shmem>& 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<layers::RefCountedShmem> mSmallAllocs;
  nsTArray<mozilla::ipc::Shmem> mLargeAllocs;
  layers::WebRenderBridgeChild* mShmAllocator;
  size_t mCursor;
  size_t mChunkSize;
};

class ShmSegmentsReader {
 public:
  ShmSegmentsReader(const nsTArray<layers::RefCountedShmem>& aSmallShmems,
                    const nsTArray<mozilla::ipc::Shmem>& aLargeShmems);

  bool Read(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& 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<Range<uint8_t>> 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<Range<uint8_t>> GetReadPointerOrCopy(const layers::OffsetRange& aRange,
                                             wr::Vec<uint8_t>& aInto) {
    if (Maybe<Range<uint8_t>> ptr = GetReadPointer(aRange)) {
      return ptr;
    } else {
      size_t initialLength = aInto.Length();
      if (Read(aRange, aInto)) {
        return Some(Range<uint8_t>(aInto.Data() + initialLength,
                                   aInto.Length() - initialLength));
      } else {
        return Nothing();
      }
    }
  }

 protected:
  bool ReadLarge(const layers::OffsetRange& aRange, wr::Vec<uint8_t>& aInto);

  Maybe<Range<uint8_t>> GetReadPointerLarge(const layers::OffsetRange& aRange);

  const nsTArray<layers::RefCountedShmem>& mSmallAllocs;
  const nsTArray<mozilla::ipc::Shmem>& 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<uint8_t> aBytes);

  bool AddBlobImage(wr::BlobImageKey aKey, const ImageDescriptor& aDescriptor,
                    Range<uint8_t> 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<uint8_t> aBytes);

  bool UpdateBlobImage(wr::BlobImageKey aKey,
                       const ImageDescriptor& aDescriptor,
                       Range<uint8_t> 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<uint8_t> aBytes, uint32_t aIndex);

  bool AddFontDescriptor(wr::FontKey aKey, Range<uint8_t> 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<const gfx::FontVariation> aVariations);

  void DeleteFontInstance(wr::FontInstanceKey aKey);

  void Clear();

  void Flush(nsTArray<layers::OpUpdateResource>& aUpdates,
             nsTArray<layers::RefCountedShmem>& aSmallAllocs,
             nsTArray<mozilla::ipc::Shmem>& aLargeAllocs);

  bool IsEmpty() const;

  static void ReleaseShmems(mozilla::ipc::IProtocol*,
                            nsTArray<layers::RefCountedShmem>& aShms);
  static void ReleaseShmems(mozilla::ipc::IProtocol*,
                            nsTArray<mozilla::ipc::Shmem>& aShms);

 protected:
  ShmSegmentsWriter mWriter;
  nsTArray<layers::OpUpdateResource> mUpdates;
};

}  // namespace wr
}  // namespace mozilla

#endif