• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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