Buffer.h (5952B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef GPU_BUFFER_H_ 7 #define GPU_BUFFER_H_ 8 9 #include <memory> 10 11 #include "ObjectModel.h" 12 #include "js/RootingAPI.h" 13 #include "mozilla/dom/Nullable.h" 14 #include "mozilla/ipc/SharedMemoryMapping.h" 15 #include "mozilla/webgpu/WebGPUTypes.h" 16 #include "nsTArray.h" 17 18 namespace mozilla { 19 namespace webgpu { 20 struct MappedView; 21 } // namespace webgpu 22 } // namespace mozilla 23 24 // Give `nsTArray` some advice on how to handle `MappedInfo::mViews`. 25 // 26 // In the `mozilla::webgpu` namespace, `MappedInfo::mViews` is an 27 // `nsTArray<MappedView>`, and `MappedView::mArrayBuffer` is a `JS::Heap` 28 // pointer. This arrangement requires special handling. 29 // 30 // Normally, `nsTArray` wants its element type to be movable with simple byte 31 // copies, so that an `nsTArray` can efficiently resize its element buffer. 32 // However, `JS::Heap` is marked `MOZ_NON_MEMMOVABLE`, meaning that it cannot be 33 // safely moved by a simple byte-by-byte copy. Normally, this would cause 34 // `nsTArray` to reject `JS::Heap` as an element type, but `nsTArray.h` 35 // specializes `nsTArray_RelocationStrategy` to indicate that `JS::Heap` can be 36 // moved safely using its move constructor. This causes `nsTArray<JS::Heap<T>>` 37 // to perform element buffer moves using element-by-element move constructor 38 // application: slower, but safe for `JS::Heap`. 39 // 40 // However, while `MappedView` is automatically marked `MOZ_NON_MEMMOVABLE` 41 // because of its `mArrayBuffer` member, the `nsTArray_RelocationStrategy` 42 // specialization is not somehow similarly magically carried over from 43 // `JS::Heap` to `MappedView`. To use `MappedView` in `nsTArray`, we must spell 44 // out a relocation strategy for it. 45 template <> 46 struct nsTArray_RelocationStrategy<mozilla::webgpu::MappedView> { 47 // The default move constructors are fine for MappedView. 48 using Type = 49 nsTArray_RelocateUsingMoveConstructor<mozilla::webgpu::MappedView>; 50 }; 51 52 namespace mozilla { 53 class ErrorResult; 54 55 namespace dom { 56 struct GPUBufferDescriptor; 57 template <typename T> 58 class Optional; 59 enum class GPUBufferMapState : uint8_t; 60 } // namespace dom 61 62 namespace webgpu { 63 64 class Device; 65 66 // A portion of the current mapped buffer range that is currently 67 // visible to JS as an ArrayBuffer. 68 struct MappedView { 69 BufferAddress mOffset; 70 BufferAddress mRangeEnd; 71 JS::Heap<JSObject*> mArrayBuffer; 72 73 MappedView(BufferAddress aOffset, BufferAddress aRangeEnd, 74 JSObject* aArrayBuffer) 75 : mOffset(aOffset), mRangeEnd(aRangeEnd), mArrayBuffer(aArrayBuffer) {} 76 }; 77 78 struct MappedInfo { 79 // True if mapping is requested for writing. 80 bool mWritable = false; 81 // Populated by `GetMappedRange`. 82 nsTArray<MappedView> mViews; 83 BufferAddress mOffset; 84 BufferAddress mSize; 85 MappedInfo() = default; 86 MappedInfo(const MappedInfo&) = delete; 87 }; 88 89 class Buffer final : public nsWrapperCache, 90 public ObjectBase, 91 public ChildOf<Device> { 92 public: 93 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Buffer) 94 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Buffer) 95 GPU_DECL_JS_WRAP(Buffer) 96 97 static already_AddRefed<Buffer> Create(Device* aDevice, RawId aDeviceId, 98 const dom::GPUBufferDescriptor& aDesc, 99 ErrorResult& aRv); 100 101 already_AddRefed<dom::Promise> MapAsync(uint32_t aMode, uint64_t aOffset, 102 const dom::Optional<uint64_t>& aSize, 103 ErrorResult& aRv); 104 void GetMappedRange(JSContext* aCx, uint64_t aOffset, 105 const dom::Optional<uint64_t>& aSize, 106 JS::Rooted<JSObject*>* aObject, ErrorResult& aRv); 107 void Unmap(JSContext* aCx, ErrorResult& aRv); 108 void Destroy(JSContext* aCx, ErrorResult& aRv); 109 110 uint64_t Size() const { return mSize; } 111 uint32_t Usage() const { return mUsage; } 112 dom::GPUBufferMapState MapState() const; 113 114 void ResolveMapRequest(dom::Promise* aPromise, BufferAddress aOffset, 115 BufferAddress aSize, bool aWritable); 116 void RejectMapRequest(dom::Promise* aPromise, const nsACString& message); 117 void RejectMapRequestWithAbortError(dom::Promise* aPromise); 118 119 private: 120 Buffer(Device* const aParent, RawId aId, BufferAddress aSize, uint32_t aUsage, 121 ipc::SharedMemoryMapping&& aShmem); 122 virtual ~Buffer(); 123 void Cleanup(); 124 void UnmapArrayBuffers(JSContext* aCx, ErrorResult& aRv); 125 void AbortMapRequest(); 126 void SetMapped(BufferAddress aOffset, BufferAddress aSize, bool aWritable); 127 128 bool mValid = true; 129 // Note: we can't map a buffer with the size that don't fit into `size_t` 130 // (which may be smaller than `BufferAddress`), but general not all buffers 131 // are mapped. 132 const BufferAddress mSize; 133 const uint32_t mUsage; 134 nsString mLabel; 135 // Information about the currently active mapping. 136 Maybe<MappedInfo> mMapped; 137 RefPtr<dom::Promise> mMapRequest; 138 139 // A shared memory mapping for the entire buffer, or a zero-length 140 // mapping. 141 // 142 // If `mUsage` contains `MAP_READ` or `MAP_WRITE`, this mapping is 143 // created at `Buffer` construction, and destroyed at `Buffer` 144 // destruction. 145 // 146 // If `mUsage` contains neither of those flags, but `this` is mapped 147 // at creation, this mapping is created at `Buffer` construction, 148 // and destroyed when we first unmap the buffer, by clearing this 149 // `shared_ptr`. 150 // 151 // Otherwise, this points to `SharedMemoryMapping()` (the default 152 // constructor), a zero-length mapping that doesn't point to any shared 153 // memory. 154 std::shared_ptr<ipc::SharedMemoryMapping> mShmem; 155 }; 156 157 } // namespace webgpu 158 } // namespace mozilla 159 160 #endif // GPU_BUFFER_H_