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