1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // VertexBuffer.cpp: Defines the abstract VertexBuffer class and VertexBufferInterface
8 // class with derivations, classes that perform graphics API agnostic vertex buffer operations.
9
10 #include "libANGLE/renderer/d3d/VertexBuffer.h"
11
12 #include "common/mathutil.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/VertexAttribute.h"
15 #include "libANGLE/renderer/d3d/BufferD3D.h"
16 #include "libANGLE/renderer/d3d/ContextD3D.h"
17
18 namespace rx
19 {
20
21 // VertexBuffer Implementation
22 unsigned int VertexBuffer::mNextSerial = 1;
23
VertexBuffer()24 VertexBuffer::VertexBuffer() : mRefCount(1)
25 {
26 updateSerial();
27 }
28
~VertexBuffer()29 VertexBuffer::~VertexBuffer() {}
30
updateSerial()31 void VertexBuffer::updateSerial()
32 {
33 mSerial = mNextSerial++;
34 }
35
getSerial() const36 unsigned int VertexBuffer::getSerial() const
37 {
38 return mSerial;
39 }
40
addRef()41 void VertexBuffer::addRef()
42 {
43 mRefCount++;
44 }
45
release()46 void VertexBuffer::release()
47 {
48 ASSERT(mRefCount > 0);
49 mRefCount--;
50
51 if (mRefCount == 0)
52 {
53 delete this;
54 }
55 }
56
57 // VertexBufferInterface Implementation
VertexBufferInterface(BufferFactoryD3D * factory,bool dynamic)58 VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic)
59 : mFactory(factory), mVertexBuffer(factory->createVertexBuffer()), mDynamic(dynamic)
60 {}
61
~VertexBufferInterface()62 VertexBufferInterface::~VertexBufferInterface()
63 {
64 if (mVertexBuffer)
65 {
66 mVertexBuffer->release();
67 mVertexBuffer = nullptr;
68 }
69 }
70
getSerial() const71 unsigned int VertexBufferInterface::getSerial() const
72 {
73 ASSERT(mVertexBuffer);
74 return mVertexBuffer->getSerial();
75 }
76
getBufferSize() const77 unsigned int VertexBufferInterface::getBufferSize() const
78 {
79 ASSERT(mVertexBuffer);
80 return mVertexBuffer->getBufferSize();
81 }
82
setBufferSize(const gl::Context * context,unsigned int size)83 angle::Result VertexBufferInterface::setBufferSize(const gl::Context *context, unsigned int size)
84 {
85 ASSERT(mVertexBuffer);
86 if (mVertexBuffer->getBufferSize() == 0)
87 {
88 return mVertexBuffer->initialize(context, size, mDynamic);
89 }
90
91 return mVertexBuffer->setBufferSize(context, size);
92 }
93
getSpaceRequired(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,size_t count,GLsizei instances,GLuint baseInstance,unsigned int * spaceInBytesOut) const94 angle::Result VertexBufferInterface::getSpaceRequired(const gl::Context *context,
95 const gl::VertexAttribute &attrib,
96 const gl::VertexBinding &binding,
97 size_t count,
98 GLsizei instances,
99 GLuint baseInstance,
100 unsigned int *spaceInBytesOut) const
101 {
102 unsigned int spaceRequired = 0;
103 ANGLE_TRY(mFactory->getVertexSpaceRequired(context, attrib, binding, count, instances,
104 baseInstance, &spaceRequired));
105
106 // Align to 16-byte boundary
107 unsigned int alignedSpaceRequired = roundUpPow2(spaceRequired, 16u);
108 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), alignedSpaceRequired >= spaceRequired);
109
110 *spaceInBytesOut = alignedSpaceRequired;
111 return angle::Result::Continue;
112 }
113
discard(const gl::Context * context)114 angle::Result VertexBufferInterface::discard(const gl::Context *context)
115 {
116 ASSERT(mVertexBuffer);
117 return mVertexBuffer->discard(context);
118 }
119
getVertexBuffer() const120 VertexBuffer *VertexBufferInterface::getVertexBuffer() const
121 {
122 ASSERT(mVertexBuffer);
123 return mVertexBuffer;
124 }
125
126 // StreamingVertexBufferInterface Implementation
StreamingVertexBufferInterface(BufferFactoryD3D * factory)127 StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory)
128 : VertexBufferInterface(factory, true), mWritePosition(0), mReservedSpace(0)
129 {}
130
initialize(const gl::Context * context,std::size_t initialSize)131 angle::Result StreamingVertexBufferInterface::initialize(const gl::Context *context,
132 std::size_t initialSize)
133 {
134 return setBufferSize(context, static_cast<unsigned int>(initialSize));
135 }
136
reset()137 void StreamingVertexBufferInterface::reset()
138 {
139 if (mVertexBuffer)
140 {
141 mVertexBuffer->release();
142 mVertexBuffer = mFactory->createVertexBuffer();
143 }
144 }
145
~StreamingVertexBufferInterface()146 StreamingVertexBufferInterface::~StreamingVertexBufferInterface() {}
147
reserveSpace(const gl::Context * context,unsigned int size)148 angle::Result StreamingVertexBufferInterface::reserveSpace(const gl::Context *context,
149 unsigned int size)
150 {
151 unsigned int curBufferSize = getBufferSize();
152 if (size > curBufferSize)
153 {
154 ANGLE_TRY(setBufferSize(context, std::max(size, 3 * curBufferSize / 2)));
155 mWritePosition = 0;
156 }
157 else if (mWritePosition + size > curBufferSize)
158 {
159 ANGLE_TRY(discard(context));
160 mWritePosition = 0;
161 }
162
163 mReservedSpace = size;
164 return angle::Result::Continue;
165 }
166
storeDynamicAttribute(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,gl::VertexAttribType currentValueType,GLint start,size_t count,GLsizei instances,GLuint baseInstance,unsigned int * outStreamOffset,const uint8_t * sourceData)167 angle::Result StreamingVertexBufferInterface::storeDynamicAttribute(
168 const gl::Context *context,
169 const gl::VertexAttribute &attrib,
170 const gl::VertexBinding &binding,
171 gl::VertexAttribType currentValueType,
172 GLint start,
173 size_t count,
174 GLsizei instances,
175 GLuint baseInstance,
176 unsigned int *outStreamOffset,
177 const uint8_t *sourceData)
178 {
179 unsigned int spaceRequired = 0;
180 ANGLE_TRY(
181 getSpaceRequired(context, attrib, binding, count, instances, baseInstance, &spaceRequired));
182
183 // Protect against integer overflow
184 angle::CheckedNumeric<unsigned int> checkedPosition(mWritePosition);
185 checkedPosition += spaceRequired;
186 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), checkedPosition.IsValid());
187
188 mReservedSpace = 0;
189
190 size_t adjustedCount = count;
191 GLuint divisor = binding.getDivisor();
192
193 if (instances != 0 && divisor != 0)
194 {
195 // The attribute is an instanced attribute and it's an draw instance call
196 // Extra number of elements are copied at the beginning to make sure
197 // the driver is referencing the correct data with non-zero baseInstance
198 adjustedCount += UnsignedCeilDivide(baseInstance, divisor);
199 }
200
201 ANGLE_TRY(mVertexBuffer->storeVertexAttributes(context, attrib, binding, currentValueType,
202 start, adjustedCount, instances, mWritePosition,
203 sourceData));
204
205 if (outStreamOffset)
206 {
207 *outStreamOffset = mWritePosition;
208 }
209
210 mWritePosition += spaceRequired;
211
212 return angle::Result::Continue;
213 }
214
reserveVertexSpace(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,size_t count,GLsizei instances,GLuint baseInstance)215 angle::Result StreamingVertexBufferInterface::reserveVertexSpace(const gl::Context *context,
216 const gl::VertexAttribute &attrib,
217 const gl::VertexBinding &binding,
218 size_t count,
219 GLsizei instances,
220 GLuint baseInstance)
221 {
222 unsigned int requiredSpace = 0;
223 ANGLE_TRY(mFactory->getVertexSpaceRequired(context, attrib, binding, count, instances,
224 baseInstance, &requiredSpace));
225
226 // Align to 16-byte boundary
227 auto alignedRequiredSpace = rx::CheckedRoundUp(requiredSpace, 16u);
228 alignedRequiredSpace += mReservedSpace;
229
230 // Protect against integer overflow
231 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), alignedRequiredSpace.IsValid());
232
233 ANGLE_TRY(reserveSpace(context, alignedRequiredSpace.ValueOrDie()));
234
235 return angle::Result::Continue;
236 }
237
238 // StaticVertexBufferInterface Implementation
AttributeSignature()239 StaticVertexBufferInterface::AttributeSignature::AttributeSignature()
240 : formatID(angle::FormatID::NONE), stride(0), offset(0)
241 {}
242
matchesAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding) const243 bool StaticVertexBufferInterface::AttributeSignature::matchesAttribute(
244 const gl::VertexAttribute &attrib,
245 const gl::VertexBinding &binding) const
246 {
247 size_t attribStride = ComputeVertexAttributeStride(attrib, binding);
248
249 if (formatID != attrib.format->id || static_cast<GLuint>(stride) != attribStride)
250 {
251 return false;
252 }
253
254 size_t attribOffset =
255 (static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) % attribStride);
256 return (offset == attribOffset);
257 }
258
set(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)259 void StaticVertexBufferInterface::AttributeSignature::set(const gl::VertexAttribute &attrib,
260 const gl::VertexBinding &binding)
261 {
262 formatID = attrib.format->id;
263 offset = stride = static_cast<GLuint>(ComputeVertexAttributeStride(attrib, binding));
264 offset = static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) %
265 ComputeVertexAttributeStride(attrib, binding);
266 }
267
StaticVertexBufferInterface(BufferFactoryD3D * factory)268 StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory)
269 : VertexBufferInterface(factory, false)
270 {}
271
~StaticVertexBufferInterface()272 StaticVertexBufferInterface::~StaticVertexBufferInterface() {}
273
matchesAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding) const274 bool StaticVertexBufferInterface::matchesAttribute(const gl::VertexAttribute &attrib,
275 const gl::VertexBinding &binding) const
276 {
277 return mSignature.matchesAttribute(attrib, binding);
278 }
279
setAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)280 void StaticVertexBufferInterface::setAttribute(const gl::VertexAttribute &attrib,
281 const gl::VertexBinding &binding)
282 {
283 return mSignature.set(attrib, binding);
284 }
285
storeStaticAttribute(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,GLint start,GLsizei count,GLsizei instances,const uint8_t * sourceData)286 angle::Result StaticVertexBufferInterface::storeStaticAttribute(const gl::Context *context,
287 const gl::VertexAttribute &attrib,
288 const gl::VertexBinding &binding,
289 GLint start,
290 GLsizei count,
291 GLsizei instances,
292 const uint8_t *sourceData)
293 {
294 unsigned int spaceRequired = 0;
295 ANGLE_TRY(getSpaceRequired(context, attrib, binding, count, instances, 0, &spaceRequired));
296 ANGLE_TRY(setBufferSize(context, spaceRequired));
297
298 ASSERT(attrib.enabled);
299 ANGLE_TRY(mVertexBuffer->storeVertexAttributes(context, attrib, binding,
300 gl::VertexAttribType::InvalidEnum, start, count,
301 instances, 0, sourceData));
302
303 mSignature.set(attrib, binding);
304 mVertexBuffer->hintUnmapResource();
305 return angle::Result::Continue;
306 }
307
308 } // namespace rx
309