1 //
2 // Copyright (c) 2002-2012 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/renderer/d3d/BufferD3D.h"
14 #include "libANGLE/renderer/d3d/RendererD3D.h"
15 #include "libANGLE/VertexAttribute.h"
16 
17 namespace rx
18 {
19 
20 // VertexBuffer Implementation
21 unsigned int VertexBuffer::mNextSerial = 1;
22 
VertexBuffer()23 VertexBuffer::VertexBuffer() : mRefCount(1)
24 {
25     updateSerial();
26 }
27 
~VertexBuffer()28 VertexBuffer::~VertexBuffer()
29 {
30 }
31 
updateSerial()32 void VertexBuffer::updateSerial()
33 {
34     mSerial = mNextSerial++;
35 }
36 
getSerial() const37 unsigned int VertexBuffer::getSerial() const
38 {
39     return mSerial;
40 }
41 
addRef()42 void VertexBuffer::addRef()
43 {
44     mRefCount++;
45 }
46 
release()47 void VertexBuffer::release()
48 {
49     ASSERT(mRefCount > 0);
50     mRefCount--;
51 
52     if (mRefCount == 0)
53     {
54         delete this;
55     }
56 }
57 
58 // VertexBufferInterface Implementation
VertexBufferInterface(BufferFactoryD3D * factory,bool dynamic)59 VertexBufferInterface::VertexBufferInterface(BufferFactoryD3D *factory, bool dynamic)
60     : mFactory(factory), mVertexBuffer(factory->createVertexBuffer()), mDynamic(dynamic)
61 {
62 }
63 
~VertexBufferInterface()64 VertexBufferInterface::~VertexBufferInterface()
65 {
66     if (mVertexBuffer)
67     {
68         mVertexBuffer->release();
69     }
70 }
71 
getSerial() const72 unsigned int VertexBufferInterface::getSerial() const
73 {
74     return mVertexBuffer->getSerial();
75 }
76 
getBufferSize() const77 unsigned int VertexBufferInterface::getBufferSize() const
78 {
79     return mVertexBuffer->getBufferSize();
80 }
81 
setBufferSize(unsigned int size)82 gl::Error VertexBufferInterface::setBufferSize(unsigned int size)
83 {
84     if (mVertexBuffer->getBufferSize() == 0)
85     {
86         return mVertexBuffer->initialize(size, mDynamic);
87     }
88 
89     return mVertexBuffer->setBufferSize(size);
90 }
91 
getSpaceRequired(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,GLsizei count,GLsizei instances) const92 gl::ErrorOrResult<unsigned int> VertexBufferInterface::getSpaceRequired(
93     const gl::VertexAttribute &attrib,
94     const gl::VertexBinding &binding,
95     GLsizei count,
96     GLsizei instances) const
97 {
98     unsigned int spaceRequired = 0;
99     ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, count, instances),
100                      spaceRequired);
101 
102     // Align to 16-byte boundary
103     unsigned int alignedSpaceRequired = roundUp(spaceRequired, 16u);
104 
105     if (alignedSpaceRequired < spaceRequired)
106     {
107         return gl::OutOfMemory()
108                << "Vertex buffer overflow in VertexBufferInterface::getSpaceRequired.";
109     }
110 
111     return alignedSpaceRequired;
112 }
113 
discard()114 gl::Error VertexBufferInterface::discard()
115 {
116     return mVertexBuffer->discard();
117 }
118 
getVertexBuffer() const119 VertexBuffer *VertexBufferInterface::getVertexBuffer() const
120 {
121     return mVertexBuffer;
122 }
123 
124 // StreamingVertexBufferInterface Implementation
StreamingVertexBufferInterface(BufferFactoryD3D * factory,std::size_t initialSize)125 StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory,
126                                                                std::size_t initialSize)
127     : VertexBufferInterface(factory, true), mWritePosition(0), mReservedSpace(0)
128 {
129     // TODO(jmadill): Make an initialize method that can return an error.
130     ANGLE_SWALLOW_ERR(setBufferSize(static_cast<unsigned int>(initialSize)));
131 }
132 
~StreamingVertexBufferInterface()133 StreamingVertexBufferInterface::~StreamingVertexBufferInterface()
134 {
135 }
136 
reserveSpace(unsigned int size)137 gl::Error StreamingVertexBufferInterface::reserveSpace(unsigned int size)
138 {
139     unsigned int curBufferSize = getBufferSize();
140     if (size > curBufferSize)
141     {
142         ANGLE_TRY(setBufferSize(std::max(size, 3 * curBufferSize / 2)));
143         mWritePosition = 0;
144     }
145     else if (mWritePosition + size > curBufferSize)
146     {
147         ANGLE_TRY(discard());
148         mWritePosition = 0;
149     }
150 
151     return gl::NoError();
152 }
153 
storeDynamicAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,GLenum currentValueType,GLint start,GLsizei count,GLsizei instances,unsigned int * outStreamOffset,const uint8_t * sourceData)154 gl::Error StreamingVertexBufferInterface::storeDynamicAttribute(const gl::VertexAttribute &attrib,
155                                                                 const gl::VertexBinding &binding,
156                                                                 GLenum currentValueType,
157                                                                 GLint start,
158                                                                 GLsizei count,
159                                                                 GLsizei instances,
160                                                                 unsigned int *outStreamOffset,
161                                                                 const uint8_t *sourceData)
162 {
163     unsigned int spaceRequired = 0;
164     ANGLE_TRY_RESULT(getSpaceRequired(attrib, binding, count, instances), spaceRequired);
165 
166     // Protect against integer overflow
167     angle::CheckedNumeric<unsigned int> checkedPosition(mWritePosition);
168     checkedPosition += spaceRequired;
169     if (!checkedPosition.IsValid())
170     {
171         return gl::OutOfMemory()
172                << "Internal error, new vertex buffer write position would overflow.";
173     }
174 
175     ANGLE_TRY(reserveSpace(mReservedSpace));
176     mReservedSpace = 0;
177 
178     ANGLE_TRY(mVertexBuffer->storeVertexAttributes(attrib, binding, currentValueType, start, count,
179                                                    instances, mWritePosition, sourceData));
180 
181     if (outStreamOffset)
182     {
183         *outStreamOffset = mWritePosition;
184     }
185 
186     mWritePosition += spaceRequired;
187 
188     return gl::NoError();
189 }
190 
reserveVertexSpace(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,GLsizei count,GLsizei instances)191 gl::Error StreamingVertexBufferInterface::reserveVertexSpace(const gl::VertexAttribute &attrib,
192                                                              const gl::VertexBinding &binding,
193                                                              GLsizei count,
194                                                              GLsizei instances)
195 {
196     unsigned int requiredSpace = 0;
197     ANGLE_TRY_RESULT(mFactory->getVertexSpaceRequired(attrib, binding, count, instances),
198                      requiredSpace);
199 
200     // Align to 16-byte boundary
201     auto alignedRequiredSpace = rx::CheckedRoundUp(requiredSpace, 16u);
202     alignedRequiredSpace += mReservedSpace;
203 
204     // Protect against integer overflow
205     if (!alignedRequiredSpace.IsValid())
206     {
207         return gl::OutOfMemory()
208                << "Unable to reserve " << requiredSpace
209                << " extra bytes in internal vertex buffer, it would result in an overflow.";
210     }
211 
212     mReservedSpace = alignedRequiredSpace.ValueOrDie();
213 
214     return gl::NoError();
215 }
216 
217 // StaticVertexBufferInterface Implementation
AttributeSignature()218 StaticVertexBufferInterface::AttributeSignature::AttributeSignature()
219     : type(GL_NONE), size(0), stride(0), normalized(false), pureInteger(false), offset(0)
220 {
221 }
222 
matchesAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding) const223 bool StaticVertexBufferInterface::AttributeSignature::matchesAttribute(
224     const gl::VertexAttribute &attrib,
225     const gl::VertexBinding &binding) const
226 {
227     size_t attribStride = ComputeVertexAttributeStride(attrib, binding);
228 
229     if (type != attrib.type || size != attrib.size || static_cast<GLuint>(stride) != attribStride ||
230         normalized != attrib.normalized || pureInteger != attrib.pureInteger)
231     {
232         return false;
233     }
234 
235     size_t attribOffset =
236         (static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) % attribStride);
237     return (offset == attribOffset);
238 }
239 
set(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)240 void StaticVertexBufferInterface::AttributeSignature::set(const gl::VertexAttribute &attrib,
241                                                           const gl::VertexBinding &binding)
242 {
243     type        = attrib.type;
244     size        = attrib.size;
245     normalized  = attrib.normalized;
246     pureInteger = attrib.pureInteger;
247     offset = stride = static_cast<GLuint>(ComputeVertexAttributeStride(attrib, binding));
248     offset          = static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) %
249              ComputeVertexAttributeStride(attrib, binding);
250 }
251 
StaticVertexBufferInterface(BufferFactoryD3D * factory)252 StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory)
253     : VertexBufferInterface(factory, false)
254 {
255 }
256 
~StaticVertexBufferInterface()257 StaticVertexBufferInterface::~StaticVertexBufferInterface()
258 {
259 }
260 
matchesAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding) const261 bool StaticVertexBufferInterface::matchesAttribute(const gl::VertexAttribute &attrib,
262                                                    const gl::VertexBinding &binding) const
263 {
264     return mSignature.matchesAttribute(attrib, binding);
265 }
266 
setAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)267 void StaticVertexBufferInterface::setAttribute(const gl::VertexAttribute &attrib,
268                                                const gl::VertexBinding &binding)
269 {
270     return mSignature.set(attrib, binding);
271 }
272 
storeStaticAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,GLint start,GLsizei count,GLsizei instances,const uint8_t * sourceData)273 gl::Error StaticVertexBufferInterface::storeStaticAttribute(const gl::VertexAttribute &attrib,
274                                                             const gl::VertexBinding &binding,
275                                                             GLint start,
276                                                             GLsizei count,
277                                                             GLsizei instances,
278                                                             const uint8_t *sourceData)
279 {
280     unsigned int spaceRequired = 0;
281     ANGLE_TRY_RESULT(getSpaceRequired(attrib, binding, count, instances), spaceRequired);
282     ANGLE_TRY(setBufferSize(spaceRequired));
283 
284     ASSERT(attrib.enabled);
285     ANGLE_TRY(mVertexBuffer->storeVertexAttributes(attrib, binding, GL_NONE, start, count,
286                                                    instances, 0, sourceData));
287 
288     mSignature.set(attrib, binding);
289     mVertexBuffer->hintUnmapResource();
290     return gl::NoError();
291 }
292 
293 }  // namespace rx
294