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,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 unsigned int *spaceInBytesOut) const
100 {
101 unsigned int spaceRequired = 0;
102 ANGLE_TRY(mFactory->getVertexSpaceRequired(context, attrib, binding, count, instances,
103 &spaceRequired));
104
105 // Align to 16-byte boundary
106 unsigned int alignedSpaceRequired = roundUpPow2(spaceRequired, 16u);
107 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), alignedSpaceRequired >= spaceRequired);
108
109 *spaceInBytesOut = alignedSpaceRequired;
110 return angle::Result::Continue;
111 }
112
discard(const gl::Context * context)113 angle::Result VertexBufferInterface::discard(const gl::Context *context)
114 {
115 ASSERT(mVertexBuffer);
116 return mVertexBuffer->discard(context);
117 }
118
getVertexBuffer() const119 VertexBuffer *VertexBufferInterface::getVertexBuffer() const
120 {
121 ASSERT(mVertexBuffer);
122 return mVertexBuffer;
123 }
124
125 // StreamingVertexBufferInterface Implementation
StreamingVertexBufferInterface(BufferFactoryD3D * factory)126 StreamingVertexBufferInterface::StreamingVertexBufferInterface(BufferFactoryD3D *factory)
127 : VertexBufferInterface(factory, true), mWritePosition(0), mReservedSpace(0)
128 {}
129
initialize(const gl::Context * context,std::size_t initialSize)130 angle::Result StreamingVertexBufferInterface::initialize(const gl::Context *context,
131 std::size_t initialSize)
132 {
133 return setBufferSize(context, static_cast<unsigned int>(initialSize));
134 }
135
reset()136 void StreamingVertexBufferInterface::reset()
137 {
138 if (mVertexBuffer)
139 {
140 mVertexBuffer->release();
141 mVertexBuffer = mFactory->createVertexBuffer();
142 }
143 }
144
~StreamingVertexBufferInterface()145 StreamingVertexBufferInterface::~StreamingVertexBufferInterface() {}
146
reserveSpace(const gl::Context * context,unsigned int size)147 angle::Result StreamingVertexBufferInterface::reserveSpace(const gl::Context *context,
148 unsigned int size)
149 {
150 unsigned int curBufferSize = getBufferSize();
151 if (size > curBufferSize)
152 {
153 ANGLE_TRY(setBufferSize(context, std::max(size, 3 * curBufferSize / 2)));
154 mWritePosition = 0;
155 }
156 else if (mWritePosition + size > curBufferSize)
157 {
158 ANGLE_TRY(discard(context));
159 mWritePosition = 0;
160 }
161
162 mReservedSpace = size;
163 return angle::Result::Continue;
164 }
165
storeDynamicAttribute(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,gl::VertexAttribType currentValueType,GLint start,size_t count,GLsizei instances,unsigned int * outStreamOffset,const uint8_t * sourceData)166 angle::Result StreamingVertexBufferInterface::storeDynamicAttribute(
167 const gl::Context *context,
168 const gl::VertexAttribute &attrib,
169 const gl::VertexBinding &binding,
170 gl::VertexAttribType currentValueType,
171 GLint start,
172 size_t count,
173 GLsizei instances,
174 unsigned int *outStreamOffset,
175 const uint8_t *sourceData)
176 {
177 unsigned int spaceRequired = 0;
178 ANGLE_TRY(getSpaceRequired(context, attrib, binding, count, instances, &spaceRequired));
179
180 // Protect against integer overflow
181 angle::CheckedNumeric<unsigned int> checkedPosition(mWritePosition);
182 checkedPosition += spaceRequired;
183 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), checkedPosition.IsValid());
184
185 mReservedSpace = 0;
186
187 ANGLE_TRY(mVertexBuffer->storeVertexAttributes(context, attrib, binding, currentValueType,
188 start, count, instances, mWritePosition,
189 sourceData));
190
191 if (outStreamOffset)
192 {
193 *outStreamOffset = mWritePosition;
194 }
195
196 mWritePosition += spaceRequired;
197
198 return angle::Result::Continue;
199 }
200
reserveVertexSpace(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,size_t count,GLsizei instances)201 angle::Result StreamingVertexBufferInterface::reserveVertexSpace(const gl::Context *context,
202 const gl::VertexAttribute &attrib,
203 const gl::VertexBinding &binding,
204 size_t count,
205 GLsizei instances)
206 {
207 unsigned int requiredSpace = 0;
208 ANGLE_TRY(mFactory->getVertexSpaceRequired(context, attrib, binding, count, instances,
209 &requiredSpace));
210
211 // Align to 16-byte boundary
212 auto alignedRequiredSpace = rx::CheckedRoundUp(requiredSpace, 16u);
213 alignedRequiredSpace += mReservedSpace;
214
215 // Protect against integer overflow
216 ANGLE_CHECK_GL_ALLOC(GetImplAs<ContextD3D>(context), alignedRequiredSpace.IsValid());
217
218 ANGLE_TRY(reserveSpace(context, alignedRequiredSpace.ValueOrDie()));
219
220 return angle::Result::Continue;
221 }
222
223 // StaticVertexBufferInterface Implementation
AttributeSignature()224 StaticVertexBufferInterface::AttributeSignature::AttributeSignature()
225 : formatID(angle::FormatID::NONE), stride(0), offset(0)
226 {}
227
matchesAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding) const228 bool StaticVertexBufferInterface::AttributeSignature::matchesAttribute(
229 const gl::VertexAttribute &attrib,
230 const gl::VertexBinding &binding) const
231 {
232 size_t attribStride = ComputeVertexAttributeStride(attrib, binding);
233
234 if (formatID != attrib.format->id || static_cast<GLuint>(stride) != attribStride)
235 {
236 return false;
237 }
238
239 size_t attribOffset =
240 (static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) % attribStride);
241 return (offset == attribOffset);
242 }
243
set(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)244 void StaticVertexBufferInterface::AttributeSignature::set(const gl::VertexAttribute &attrib,
245 const gl::VertexBinding &binding)
246 {
247 formatID = attrib.format->id;
248 offset = stride = static_cast<GLuint>(ComputeVertexAttributeStride(attrib, binding));
249 offset = static_cast<size_t>(ComputeVertexAttributeOffset(attrib, binding)) %
250 ComputeVertexAttributeStride(attrib, binding);
251 }
252
StaticVertexBufferInterface(BufferFactoryD3D * factory)253 StaticVertexBufferInterface::StaticVertexBufferInterface(BufferFactoryD3D *factory)
254 : VertexBufferInterface(factory, false)
255 {}
256
~StaticVertexBufferInterface()257 StaticVertexBufferInterface::~StaticVertexBufferInterface() {}
258
matchesAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding) const259 bool StaticVertexBufferInterface::matchesAttribute(const gl::VertexAttribute &attrib,
260 const gl::VertexBinding &binding) const
261 {
262 return mSignature.matchesAttribute(attrib, binding);
263 }
264
setAttribute(const gl::VertexAttribute & attrib,const gl::VertexBinding & binding)265 void StaticVertexBufferInterface::setAttribute(const gl::VertexAttribute &attrib,
266 const gl::VertexBinding &binding)
267 {
268 return mSignature.set(attrib, binding);
269 }
270
storeStaticAttribute(const gl::Context * context,const gl::VertexAttribute & attrib,const gl::VertexBinding & binding,GLint start,GLsizei count,GLsizei instances,const uint8_t * sourceData)271 angle::Result StaticVertexBufferInterface::storeStaticAttribute(const gl::Context *context,
272 const gl::VertexAttribute &attrib,
273 const gl::VertexBinding &binding,
274 GLint start,
275 GLsizei count,
276 GLsizei instances,
277 const uint8_t *sourceData)
278 {
279 unsigned int spaceRequired = 0;
280 ANGLE_TRY(getSpaceRequired(context, attrib, binding, count, instances, &spaceRequired));
281 ANGLE_TRY(setBufferSize(context, spaceRequired));
282
283 ASSERT(attrib.enabled);
284 ANGLE_TRY(mVertexBuffer->storeVertexAttributes(context, attrib, binding,
285 gl::VertexAttribType::InvalidEnum, start, count,
286 instances, 0, sourceData));
287
288 mSignature.set(attrib, binding);
289 mVertexBuffer->hintUnmapResource();
290 return angle::Result::Continue;
291 }
292
293 } // namespace rx
294