/src/mozilla-central/gfx/layers/mlgpu/SharedBufferMLGPU.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef mozilla_gfx_layers_mlgpu_SharedBufferMLGPU_h |
8 | | #define mozilla_gfx_layers_mlgpu_SharedBufferMLGPU_h |
9 | | |
10 | | #include "ShaderDefinitionsMLGPU.h" |
11 | | #include "MLGDevice.h" |
12 | | #include "MLGDeviceTypes.h" |
13 | | #include "StagingBuffer.h" |
14 | | #include "mozilla/gfx/Logging.h" |
15 | | |
16 | | namespace mozilla { |
17 | | namespace layers { |
18 | | |
19 | | class MLGBuffer; |
20 | | |
21 | | class SharedBufferMLGPU |
22 | | { |
23 | | public: |
24 | | virtual ~SharedBufferMLGPU(); |
25 | | |
26 | | bool Init(); |
27 | | |
28 | | // Call before starting a new frame. |
29 | | void Reset(); |
30 | | |
31 | | // Call to finish any pending uploads. |
32 | | void PrepareForUsage(); |
33 | | |
34 | | protected: |
35 | | SharedBufferMLGPU(MLGDevice* aDevice, MLGBufferType aType, size_t aDefaultSize); |
36 | | |
37 | | bool EnsureMappedBuffer(size_t aBytes); |
38 | | bool GrowBuffer(size_t aBytes); |
39 | | void ForgetBuffer(); |
40 | | bool Map(); |
41 | | void Unmap(); |
42 | | |
43 | | uint8_t* GetBufferPointer(size_t aBytes, ptrdiff_t* aOutOffset, RefPtr<MLGBuffer>* aOutBuffer); |
44 | | |
45 | | protected: |
46 | | // Note: RefPtr here would cause a cycle. Only MLGDevice should own |
47 | | // SharedBufferMLGPU objects for now. |
48 | | MLGDevice* mDevice; |
49 | | MLGBufferType mType; |
50 | | size_t mDefaultSize; |
51 | | bool mCanUseOffsetAllocation; |
52 | | |
53 | | // When |mBuffer| is non-null, mMaxSize is the buffer size. If mapped, the |
54 | | // position is between 0 and mMaxSize, otherwise it is always 0. |
55 | | RefPtr<MLGBuffer> mBuffer; |
56 | | ptrdiff_t mCurrentPosition; |
57 | | size_t mMaxSize; |
58 | | |
59 | | MLGMappedResource mMap; |
60 | | bool mMapped; |
61 | | |
62 | | // These are used to track how many frames come in under the default |
63 | | // buffer size in a row. |
64 | | size_t mBytesUsedThisFrame; |
65 | | size_t mNumSmallFrames; |
66 | | }; |
67 | | |
68 | | class VertexBufferSection final |
69 | | { |
70 | | friend class SharedVertexBuffer; |
71 | | public: |
72 | | VertexBufferSection(); |
73 | | |
74 | 0 | uint32_t Stride() const { |
75 | 0 | return mStride; |
76 | 0 | } |
77 | 0 | MLGBuffer* GetBuffer() const { |
78 | 0 | return mBuffer; |
79 | 0 | } |
80 | 0 | ptrdiff_t Offset() const { |
81 | 0 | MOZ_ASSERT(IsValid()); |
82 | 0 | return mOffset; |
83 | 0 | } |
84 | 0 | size_t NumVertices() const { |
85 | 0 | return mNumVertices; |
86 | 0 | } |
87 | 0 | bool IsValid() const { |
88 | 0 | return !!mBuffer; |
89 | 0 | } |
90 | | |
91 | | protected: |
92 | | void Init(MLGBuffer* aBuffer, ptrdiff_t aOffset, size_t aNumVertices, size_t aStride); |
93 | | |
94 | | protected: |
95 | | RefPtr<MLGBuffer> mBuffer; |
96 | | ptrdiff_t mOffset; |
97 | | size_t mNumVertices; |
98 | | size_t mStride; |
99 | | }; |
100 | | |
101 | | class ConstantBufferSection final |
102 | | { |
103 | | friend class SharedConstantBuffer; |
104 | | |
105 | | public: |
106 | | ConstantBufferSection(); |
107 | | |
108 | 0 | uint32_t NumConstants() const { |
109 | 0 | return NumConstantsForBytes(mNumBytes); |
110 | 0 | } |
111 | 0 | size_t NumItems() const { |
112 | 0 | return mNumItems; |
113 | 0 | } |
114 | 0 | uint32_t Offset() const { |
115 | 0 | MOZ_ASSERT(IsValid()); |
116 | 0 | return mOffset / 16; |
117 | 0 | } |
118 | 0 | MLGBuffer* GetBuffer() const { |
119 | 0 | return mBuffer; |
120 | 0 | } |
121 | 0 | bool IsValid() const { |
122 | 0 | return !!mBuffer; |
123 | 0 | } |
124 | 0 | bool HasOffset() const { |
125 | 0 | return mOffset != -1; |
126 | 0 | } |
127 | | |
128 | | protected: |
129 | 0 | static constexpr size_t NumConstantsForBytes(size_t aBytes) { |
130 | 0 | return (aBytes + ((256 - (aBytes % 256)) % 256)) / 16; |
131 | 0 | } |
132 | | |
133 | | void Init(MLGBuffer* aBuffer, ptrdiff_t aOffset, size_t aBytes, size_t aNumItems); |
134 | | |
135 | | protected: |
136 | | RefPtr<MLGBuffer> mBuffer; |
137 | | ptrdiff_t mOffset; |
138 | | size_t mNumBytes; |
139 | | size_t mNumItems; |
140 | | }; |
141 | | |
142 | | // Vertex buffers don't need special alignment. |
143 | | typedef StagingBuffer<0> VertexStagingBuffer; |
144 | | |
145 | | class SharedVertexBuffer final : public SharedBufferMLGPU |
146 | | { |
147 | | public: |
148 | | SharedVertexBuffer(MLGDevice* aDevice, size_t aDefaultSize); |
149 | | |
150 | | // Allocate a buffer that can be uploaded immediately. |
151 | 0 | bool Allocate(VertexBufferSection* aHolder, const VertexStagingBuffer& aStaging) { |
152 | 0 | return Allocate(aHolder, |
153 | 0 | aStaging.NumItems(), |
154 | 0 | aStaging.SizeOfItem(), |
155 | 0 | aStaging.GetBufferStart()); |
156 | 0 | } |
157 | | |
158 | | // Allocate a buffer that can be uploaded immediately. This is the |
159 | | // direct access version, for cases where a StagingBuffer is not |
160 | | // needed. |
161 | | bool Allocate(VertexBufferSection* aHolder, |
162 | | size_t aNumItems, |
163 | | size_t aSizeOfItem, |
164 | | const void* aData); |
165 | | |
166 | | template <typename T> |
167 | | bool Allocate(VertexBufferSection* aHolder, const T& aItem) { |
168 | | return Allocate(aHolder, 1, sizeof(T), &aItem); |
169 | | } |
170 | | }; |
171 | | |
172 | | // To support older Direct3D versions, we need to support one-off MLGBuffers, |
173 | | // where data is uploaded immediately rather than at the end of all batch |
174 | | // preparation. We achieve this through a small helper class. |
175 | | // |
176 | | // Note: the unmap is not inline sincce we don't include MLGDevice.h. |
177 | | class MOZ_STACK_CLASS AutoBufferUploadBase |
178 | | { |
179 | | public: |
180 | | AutoBufferUploadBase(); |
181 | | ~AutoBufferUploadBase(); |
182 | | |
183 | 0 | void Init(void* aPtr) { |
184 | 0 | MOZ_ASSERT(!mPtr && aPtr); |
185 | 0 | mPtr = aPtr; |
186 | 0 | } |
187 | | void Init(void* aPtr, MLGDevice* aDevice, MLGBuffer* aBuffer); |
188 | 0 | void* get() { |
189 | 0 | return const_cast<void*>(mPtr); |
190 | 0 | } |
191 | | |
192 | | private: |
193 | | void UnmapBuffer(); |
194 | | |
195 | | protected: |
196 | | RefPtr<MLGDevice> mDevice; |
197 | | RefPtr<MLGBuffer> mBuffer; |
198 | | void* mPtr; |
199 | | }; |
200 | | |
201 | | // This is a typed helper for AutoBufferUploadBase. |
202 | | template <typename T> |
203 | | class AutoBufferUpload : public AutoBufferUploadBase |
204 | | { |
205 | | public: |
206 | | AutoBufferUpload() |
207 | 0 | {} |
208 | | |
209 | 0 | T* operator ->() const { |
210 | 0 | return reinterpret_cast<T*>(mPtr); |
211 | 0 | } |
212 | | }; |
213 | | |
214 | | class SharedConstantBuffer final : public SharedBufferMLGPU |
215 | | { |
216 | | public: |
217 | | SharedConstantBuffer(MLGDevice* aDevice, size_t aDefaultSize); |
218 | | |
219 | | // Allocate a buffer that can be immediately uploaded. |
220 | 0 | bool Allocate(ConstantBufferSection* aHolder, const ConstantStagingBuffer& aStaging) { |
221 | 0 | MOZ_ASSERT(aStaging.NumItems() * aStaging.SizeOfItem() == aStaging.NumBytes()); |
222 | 0 | return Allocate(aHolder, aStaging.NumItems(), aStaging.SizeOfItem(), aStaging.GetBufferStart()); |
223 | 0 | } |
224 | | |
225 | | // Allocate a buffer of one item that can be immediately uploaded. |
226 | | template <typename T> |
227 | 0 | bool Allocate(ConstantBufferSection* aHolder, const T& aItem) { |
228 | 0 | return Allocate(aHolder, 1, sizeof(aItem), &aItem); |
229 | 0 | } Unexecuted instantiation: bool mozilla::layers::SharedConstantBuffer::Allocate<mozilla::layers::mlg::MaskInformation>(mozilla::layers::ConstantBufferSection*, mozilla::layers::mlg::MaskInformation const&) Unexecuted instantiation: bool mozilla::layers::SharedConstantBuffer::Allocate<mozilla::layers::mlg::WorldConstants>(mozilla::layers::ConstantBufferSection*, mozilla::layers::mlg::WorldConstants const&) Unexecuted instantiation: bool mozilla::layers::SharedConstantBuffer::Allocate<mozilla::layers::mlg::ClearConstants>(mozilla::layers::ConstantBufferSection*, mozilla::layers::mlg::ClearConstants const&) |
230 | | |
231 | | // Allocate a buffer of N items that can be immediately uploaded. |
232 | | template <typename T> |
233 | 0 | bool Allocate(ConstantBufferSection* aHolder, const T* aItems, size_t aNumItems) { |
234 | 0 | return Allocate(aHolder, aNumItems, sizeof(T), aItems); |
235 | 0 | } Unexecuted instantiation: bool mozilla::layers::SharedConstantBuffer::Allocate<mozilla::layers::mlg::LayerConstants>(mozilla::layers::ConstantBufferSection*, mozilla::layers::mlg::LayerConstants const*, unsigned long) Unexecuted instantiation: bool mozilla::layers::SharedConstantBuffer::Allocate<mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> >(mozilla::layers::ConstantBufferSection*, mozilla::gfx::RectTyped<mozilla::gfx::UnknownUnits, float> const*, unsigned long) |
236 | | |
237 | | // Allocate a buffer that is uploaded after the caller has finished writing |
238 | | // to it. This should method should generally not be used unless copying T |
239 | | // is expensive, since the default immediate-upload version has an implicit |
240 | | // extra copy to the GPU. This version exposes the mapped memory directly. |
241 | | template <typename T> |
242 | 0 | bool Allocate(ConstantBufferSection* aHolder, AutoBufferUpload<T>* aPtr) { |
243 | 0 | MOZ_ASSERT(sizeof(T) % 16 == 0, "Items must be padded to 16 bytes"); |
244 | 0 |
|
245 | 0 | return Allocate(aHolder, aPtr, 1, sizeof(T)); |
246 | 0 | } |
247 | | |
248 | | private: |
249 | | bool Allocate(ConstantBufferSection* aHolder, |
250 | | size_t aNumItems, |
251 | | size_t aSizeOfItem, |
252 | | const void* aData) |
253 | 0 | { |
254 | 0 | AutoBufferUploadBase ptr; |
255 | 0 | if (!Allocate(aHolder, &ptr, aNumItems, aSizeOfItem)) { |
256 | 0 | return false; |
257 | 0 | } |
258 | 0 | memcpy(ptr.get(), aData, aNumItems * aSizeOfItem); |
259 | 0 | return true; |
260 | 0 | } |
261 | | |
262 | | bool Allocate(ConstantBufferSection* aHolder, |
263 | | AutoBufferUploadBase* aPtr, |
264 | | size_t aNumItems, |
265 | | size_t aSizeOfItem); |
266 | | |
267 | | bool GetBufferPointer(AutoBufferUploadBase* aPtr, |
268 | | size_t aBytes, |
269 | | ptrdiff_t* aOutOffset, |
270 | | RefPtr<MLGBuffer>* aOutBuffer) |
271 | 0 | { |
272 | 0 | if (!mCanUseOffsetAllocation) { |
273 | 0 | uint8_t* ptr = AllocateNewBuffer(aBytes, aOutOffset, aOutBuffer); |
274 | 0 | if (!ptr) { |
275 | 0 | return false; |
276 | 0 | } |
277 | 0 | aPtr->Init(ptr, mDevice, *aOutBuffer); |
278 | 0 | return true; |
279 | 0 | } |
280 | 0 | |
281 | 0 | // Align up the allocation to 256 bytes, since D3D11 requires that |
282 | 0 | // constant buffers start at multiples of 16 elements. |
283 | 0 | size_t alignedBytes = AlignUp<256>::calc(aBytes); |
284 | 0 |
|
285 | 0 | uint8_t* ptr = SharedBufferMLGPU::GetBufferPointer(alignedBytes, aOutOffset, aOutBuffer); |
286 | 0 | if (!ptr) { |
287 | 0 | return false; |
288 | 0 | } |
289 | 0 | |
290 | 0 | aPtr->Init(ptr); |
291 | 0 | return true; |
292 | 0 | } |
293 | | |
294 | | uint8_t* AllocateNewBuffer(size_t aBytes, ptrdiff_t* aOutOffset, RefPtr<MLGBuffer>* aOutBuffer); |
295 | | |
296 | | private: |
297 | | size_t mMaxConstantBufferBindSize; |
298 | | }; |
299 | | |
300 | | } // namespace layers |
301 | | } // namespace mozilla |
302 | | |
303 | | #endif // mozilla_gfx_layers_mlgpu_SharedBufferMLGPU_h |