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