Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; 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 : #include "SharedBufferMLGPU.h"
7 : #include "BufferCache.h"
8 : #include "MLGDevice.h"
9 :
10 : using namespace std;
11 :
12 : namespace mozilla {
13 : namespace layers {
14 :
15 0 : SharedBufferMLGPU::SharedBufferMLGPU(MLGDevice* aDevice, MLGBufferType aType, size_t aDefaultSize)
16 : : mDevice(aDevice),
17 : mType(aType),
18 : mDefaultSize(aDefaultSize),
19 : mCanUseOffsetAllocation(true),
20 : mCurrentPosition(0),
21 : mMaxSize(0),
22 : mMapped(false),
23 : mBytesUsedThisFrame(0),
24 0 : mNumSmallFrames(0)
25 : {
26 0 : MOZ_COUNT_CTOR(SharedBufferMLGPU);
27 0 : }
28 :
29 0 : SharedBufferMLGPU::~SharedBufferMLGPU()
30 : {
31 0 : MOZ_COUNT_DTOR(SharedBufferMLGPU);
32 0 : Unmap();
33 0 : }
34 :
35 : bool
36 0 : SharedBufferMLGPU::Init()
37 : {
38 : // If we can't use buffer offset binding, we never allocated shared buffers.
39 0 : if (!mCanUseOffsetAllocation) {
40 0 : return true;
41 : }
42 :
43 : // If we can use offset binding, allocate an initial shared buffer now.
44 0 : if (!GrowBuffer(mDefaultSize)) {
45 0 : return false;
46 : }
47 0 : return true;
48 : }
49 :
50 : void
51 0 : SharedBufferMLGPU::Reset()
52 : {
53 : // We shouldn't be mapped here, but just in case, unmap now.
54 0 : Unmap();
55 0 : mBytesUsedThisFrame = 0;
56 :
57 : // If we allocated a large buffer for a particularly heavy layer tree,
58 : // but have not used most of the buffer again for many frames, we
59 : // discard the buffer. This is to prevent having to perform large
60 : // pointless uploads after visiting a single havy page - it also
61 : // lessens ping-ponging between large and small buffers.
62 0 : if (mBuffer &&
63 0 : (mBuffer->GetSize() > mDefaultSize * 4) &&
64 0 : mNumSmallFrames >= 10)
65 : {
66 0 : mBuffer = nullptr;
67 : }
68 :
69 : // Note that we do not aggressively map a new buffer. There's no reason to,
70 : // and it'd cause unnecessary uploads when painting empty frames.
71 0 : }
72 :
73 : bool
74 0 : SharedBufferMLGPU::EnsureMappedBuffer(size_t aBytes)
75 : {
76 0 : if (!mBuffer || (mMaxSize - mCurrentPosition < aBytes)) {
77 0 : if (!GrowBuffer(aBytes)) {
78 0 : return false;
79 : }
80 : }
81 0 : if (!mMapped && !Map()) {
82 0 : return false;
83 : }
84 0 : return true;
85 : }
86 :
87 : // We don't want to cache large buffers, since it results in larger uploads
88 : // that might not be needed.
89 : static const size_t kMaxCachedBufferSize = 128 * 1024;
90 :
91 : bool
92 0 : SharedBufferMLGPU::GrowBuffer(size_t aBytes)
93 : {
94 : // We only pre-allocate buffers if we can use offset allocation.
95 0 : MOZ_ASSERT(mCanUseOffsetAllocation);
96 :
97 : // Unmap the previous buffer. This will retain mBuffer, but free up the
98 : // address space used by its mapping.
99 0 : Unmap();
100 :
101 0 : size_t maybeSize = mDefaultSize;
102 0 : if (mBuffer) {
103 : // Try to first grow the previous allocation size.
104 0 : maybeSize = std::min(kMaxCachedBufferSize, mBuffer->GetSize() * 2);
105 : }
106 :
107 0 : size_t bytes = std::max(aBytes, maybeSize);
108 0 : mBuffer = mDevice->CreateBuffer(mType, bytes, MLGUsage::Dynamic);
109 0 : if (!mBuffer) {
110 0 : return false;
111 : }
112 :
113 0 : mCurrentPosition = 0;
114 0 : mMaxSize = mBuffer->GetSize();
115 0 : return true;
116 : }
117 :
118 : void
119 0 : SharedBufferMLGPU::PrepareForUsage()
120 : {
121 0 : Unmap();
122 :
123 0 : if (mBytesUsedThisFrame <= mDefaultSize) {
124 0 : mNumSmallFrames++;
125 : } else {
126 0 : mNumSmallFrames = 0;
127 : }
128 0 : }
129 :
130 : bool
131 0 : SharedBufferMLGPU::Map()
132 : {
133 0 : MOZ_ASSERT(mBuffer);
134 0 : MOZ_ASSERT(!mMapped);
135 :
136 0 : if (!mDevice->Map(mBuffer, MLGMapType::WRITE_DISCARD, &mMap)) {
137 : // Don't retain the buffer, it's useless if we can't map it.
138 0 : mBuffer = nullptr;
139 0 : return false;
140 : }
141 :
142 0 : mCurrentPosition = 0;
143 0 : mMapped = true;
144 0 : return true;
145 : }
146 :
147 : void
148 0 : SharedBufferMLGPU::Unmap()
149 : {
150 0 : if (!mMapped) {
151 0 : return;
152 : }
153 :
154 0 : mBytesUsedThisFrame += mCurrentPosition;
155 :
156 0 : mDevice->Unmap(mBuffer);
157 0 : mMap = MLGMappedResource();
158 0 : mMapped = false;
159 : }
160 :
161 0 : SharedVertexBuffer::SharedVertexBuffer(MLGDevice* aDevice, size_t aDefaultSize)
162 0 : : SharedBufferMLGPU(aDevice, MLGBufferType::Vertex, aDefaultSize)
163 : {
164 0 : }
165 :
166 0 : SharedConstantBuffer::SharedConstantBuffer(MLGDevice* aDevice, size_t aDefaultSize)
167 0 : : SharedBufferMLGPU(aDevice, MLGBufferType::Constant, aDefaultSize)
168 : {
169 0 : mMaxConstantBufferBindSize = aDevice->GetMaxConstantBufferBindSize();
170 0 : mCanUseOffsetAllocation = aDevice->CanUseConstantBufferOffsetBinding();
171 0 : }
172 :
173 : uint8_t*
174 0 : SharedConstantBuffer::AllocateNewBuffer(size_t aBytes, ptrdiff_t* aOutOffset, RefPtr<MLGBuffer>* aOutBuffer)
175 : {
176 0 : RefPtr<MLGBuffer> buffer;
177 0 : if (BufferCache* cache = mDevice->GetConstantBufferCache()) {
178 0 : buffer = cache->GetOrCreateBuffer(aBytes);
179 : } else {
180 0 : buffer = mDevice->CreateBuffer(MLGBufferType::Constant, aBytes, MLGUsage::Dynamic);
181 : }
182 0 : if (!buffer) {
183 0 : return nullptr;
184 : }
185 :
186 : MLGMappedResource map;
187 0 : if (!mDevice->Map(buffer, MLGMapType::WRITE_DISCARD, &map)) {
188 0 : return nullptr;
189 : }
190 :
191 : // Signal that offsetting is not supported.
192 0 : *aOutOffset = -1;
193 0 : *aOutBuffer = buffer;
194 0 : return reinterpret_cast<uint8_t*>(map.mData);
195 : }
196 :
197 : void
198 0 : AutoBufferUploadBase::UnmapBuffer()
199 : {
200 0 : mDevice->Unmap(mBuffer);
201 0 : }
202 :
203 : } // namespace layers
204 : } // namespace mozilla
|