• 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 // Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or
8 // index data. Implements GL buffer objects and related functionality.
9 // [OpenGL ES 2.0.24] section 2.9 page 21.
10 
11 #include "libANGLE/Buffer.h"
12 
13 #include "libANGLE/Context.h"
14 #include "libANGLE/renderer/BufferImpl.h"
15 #include "libANGLE/renderer/GLImplFactory.h"
16 
17 namespace gl
18 {
19 namespace
20 {
21 constexpr angle::SubjectIndex kImplementationSubjectIndex = 0;
22 constexpr size_t kInvalidContentsObserverIndex            = std::numeric_limits<size_t>::max();
23 }  // anonymous namespace
24 
BufferState()25 BufferState::BufferState()
26     : mLabel(),
27       mUsage(BufferUsage::StaticDraw),
28       mSize(0),
29       mAccessFlags(0),
30       mAccess(GL_WRITE_ONLY_OES),
31       mMapped(GL_FALSE),
32       mMapPointer(nullptr),
33       mMapOffset(0),
34       mMapLength(0),
35       mBindingCount(0),
36       mTransformFeedbackIndexedBindingCount(0),
37       mTransformFeedbackGenericBindingCount(0),
38       mImmutable(GL_FALSE),
39       mStorageExtUsageFlags(0),
40       mExternal(GL_FALSE)
41 {}
42 
~BufferState()43 BufferState::~BufferState() {}
44 
Buffer(rx::GLImplFactory * factory,BufferID id)45 Buffer::Buffer(rx::GLImplFactory *factory, BufferID id)
46     : RefCountObject(factory->generateSerial(), id),
47       mImpl(factory->createBuffer(mState)),
48       mImplObserver(this, kImplementationSubjectIndex)
49 {
50     mImplObserver.bind(mImpl);
51 }
52 
~Buffer()53 Buffer::~Buffer()
54 {
55     SafeDelete(mImpl);
56 }
57 
onDestroy(const Context * context)58 void Buffer::onDestroy(const Context *context)
59 {
60     // In tests, mImpl might be null.
61     if (mImpl)
62         mImpl->destroy(context);
63 }
64 
setLabel(const Context * context,const std::string & label)65 void Buffer::setLabel(const Context *context, const std::string &label)
66 {
67     mState.mLabel = label;
68 }
69 
getLabel() const70 const std::string &Buffer::getLabel() const
71 {
72     return mState.mLabel;
73 }
74 
bufferStorageExternal(Context * context,BufferBinding target,GLsizeiptr size,GLeglClientBufferEXT clientBuffer,GLbitfield flags)75 angle::Result Buffer::bufferStorageExternal(Context *context,
76                                             BufferBinding target,
77                                             GLsizeiptr size,
78                                             GLeglClientBufferEXT clientBuffer,
79                                             GLbitfield flags)
80 {
81     return bufferExternalDataImpl(context, target, clientBuffer, size, flags);
82 }
83 
bufferStorage(Context * context,BufferBinding target,GLsizeiptr size,const void * data,GLbitfield flags)84 angle::Result Buffer::bufferStorage(Context *context,
85                                     BufferBinding target,
86                                     GLsizeiptr size,
87                                     const void *data,
88                                     GLbitfield flags)
89 {
90     return bufferDataImpl(context, target, data, size, BufferUsage::InvalidEnum, flags);
91 }
92 
bufferData(Context * context,BufferBinding target,const void * data,GLsizeiptr size,BufferUsage usage)93 angle::Result Buffer::bufferData(Context *context,
94                                  BufferBinding target,
95                                  const void *data,
96                                  GLsizeiptr size,
97                                  BufferUsage usage)
98 {
99     GLbitfield flags = (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT_EXT);
100     return bufferDataImpl(context, target, data, size, usage, flags);
101 }
102 
bufferDataImpl(Context * context,BufferBinding target,const void * data,GLsizeiptr size,BufferUsage usage,GLbitfield flags)103 angle::Result Buffer::bufferDataImpl(Context *context,
104                                      BufferBinding target,
105                                      const void *data,
106                                      GLsizeiptr size,
107                                      BufferUsage usage,
108                                      GLbitfield flags)
109 {
110     const void *dataForImpl = data;
111 
112     if (mState.isMapped())
113     {
114         // Per the OpenGL ES 3.0 spec, buffers are implicity unmapped when a call to
115         // BufferData happens on a mapped buffer:
116         //
117         //     If any portion of the buffer object is mapped in the current context or any context
118         //     current to another thread, it is as though UnmapBuffer (see section 2.10.3) is
119         //     executed in each such context prior to deleting the existing data store.
120         //
121         GLboolean dontCare = GL_FALSE;
122         ANGLE_TRY(unmap(context, &dontCare));
123     }
124 
125     // If we are using robust resource init, make sure the buffer starts cleared.
126     // Note: the Context is checked for nullptr because of some testing code.
127     // TODO(jmadill): Investigate lazier clearing.
128     if (context && context->getState().isRobustResourceInitEnabled() && !data && size > 0)
129     {
130         angle::MemoryBuffer *scratchBuffer = nullptr;
131         ANGLE_CHECK_GL_ALLOC(
132             context, context->getZeroFilledBuffer(static_cast<size_t>(size), &scratchBuffer));
133         dataForImpl = scratchBuffer->data();
134     }
135 
136     if (mImpl->setDataWithUsageFlags(context, target, nullptr, dataForImpl, size, usage, flags) ==
137         angle::Result::Stop)
138     {
139         // If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
140         mIndexRangeCache.clear();
141         mState.mSize = 0;
142 
143         // Notify when storage changes.
144         onStateChange(angle::SubjectMessage::SubjectChanged);
145 
146         return angle::Result::Stop;
147     }
148 
149     bool wholeBuffer = size == mState.mSize;
150 
151     mIndexRangeCache.clear();
152     mState.mUsage                = usage;
153     mState.mSize                 = size;
154     mState.mImmutable            = (usage == BufferUsage::InvalidEnum);
155     mState.mStorageExtUsageFlags = flags;
156 
157     // Notify when storage changes.
158     if (wholeBuffer)
159     {
160         onContentsChange();
161     }
162     else
163     {
164         onStateChange(angle::SubjectMessage::SubjectChanged);
165     }
166 
167     return angle::Result::Continue;
168 }
169 
bufferExternalDataImpl(Context * context,BufferBinding target,GLeglClientBufferEXT clientBuffer,GLsizeiptr size,GLbitfield flags)170 angle::Result Buffer::bufferExternalDataImpl(Context *context,
171                                              BufferBinding target,
172                                              GLeglClientBufferEXT clientBuffer,
173                                              GLsizeiptr size,
174                                              GLbitfield flags)
175 {
176     if (mState.isMapped())
177     {
178         // Per the OpenGL ES 3.0 spec, buffers are implicitly unmapped when a call to
179         // BufferData happens on a mapped buffer:
180         //
181         //     If any portion of the buffer object is mapped in the current context or any context
182         //     current to another thread, it is as though UnmapBuffer (see section 2.10.3) is
183         //     executed in each such context prior to deleting the existing data store.
184         //
185         GLboolean dontCare = GL_FALSE;
186         ANGLE_TRY(unmap(context, &dontCare));
187     }
188 
189     if (mImpl->setDataWithUsageFlags(context, target, clientBuffer, nullptr, size,
190                                      BufferUsage::InvalidEnum, flags) == angle::Result::Stop)
191     {
192         // If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
193         mIndexRangeCache.clear();
194         mState.mSize = 0;
195 
196         // Notify when storage changes.
197         onStateChange(angle::SubjectMessage::SubjectChanged);
198 
199         return angle::Result::Stop;
200     }
201 
202     mIndexRangeCache.clear();
203     mState.mUsage                = BufferUsage::InvalidEnum;
204     mState.mSize                 = size;
205     mState.mImmutable            = GL_TRUE;
206     mState.mStorageExtUsageFlags = flags;
207     mState.mExternal             = GL_TRUE;
208 
209     // Notify when storage changes.
210     onStateChange(angle::SubjectMessage::SubjectChanged);
211 
212     return angle::Result::Continue;
213 }
214 
bufferSubData(const Context * context,BufferBinding target,const void * data,GLsizeiptr size,GLintptr offset)215 angle::Result Buffer::bufferSubData(const Context *context,
216                                     BufferBinding target,
217                                     const void *data,
218                                     GLsizeiptr size,
219                                     GLintptr offset)
220 {
221     ANGLE_TRY(mImpl->setSubData(context, target, data, size, offset));
222 
223     mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
224                                      static_cast<unsigned int>(size));
225 
226     // Notify when data changes.
227     onContentsChange();
228 
229     return angle::Result::Continue;
230 }
231 
copyBufferSubData(const Context * context,Buffer * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)232 angle::Result Buffer::copyBufferSubData(const Context *context,
233                                         Buffer *source,
234                                         GLintptr sourceOffset,
235                                         GLintptr destOffset,
236                                         GLsizeiptr size)
237 {
238     ANGLE_TRY(
239         mImpl->copySubData(context, source->getImplementation(), sourceOffset, destOffset, size));
240 
241     mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset),
242                                      static_cast<unsigned int>(size));
243 
244     // Notify when data changes.
245     onContentsChange();
246 
247     return angle::Result::Continue;
248 }
249 
map(const Context * context,GLenum access)250 angle::Result Buffer::map(const Context *context, GLenum access)
251 {
252     ASSERT(!mState.mMapped);
253 
254     mState.mMapPointer = nullptr;
255     ANGLE_TRY(mImpl->map(context, access, &mState.mMapPointer));
256 
257     ASSERT(access == GL_WRITE_ONLY_OES);
258 
259     mState.mMapped      = GL_TRUE;
260     mState.mMapOffset   = 0;
261     mState.mMapLength   = mState.mSize;
262     mState.mAccess      = access;
263     mState.mAccessFlags = GL_MAP_WRITE_BIT;
264     mIndexRangeCache.clear();
265 
266     // Notify when state changes.
267     onStateChange(angle::SubjectMessage::SubjectMapped);
268 
269     return angle::Result::Continue;
270 }
271 
mapRange(const Context * context,GLintptr offset,GLsizeiptr length,GLbitfield access)272 angle::Result Buffer::mapRange(const Context *context,
273                                GLintptr offset,
274                                GLsizeiptr length,
275                                GLbitfield access)
276 {
277     ASSERT(!mState.mMapped);
278     ASSERT(offset + length <= mState.mSize);
279 
280     mState.mMapPointer = nullptr;
281     ANGLE_TRY(mImpl->mapRange(context, offset, length, access, &mState.mMapPointer));
282 
283     mState.mMapped      = GL_TRUE;
284     mState.mMapOffset   = static_cast<GLint64>(offset);
285     mState.mMapLength   = static_cast<GLint64>(length);
286     mState.mAccess      = GL_WRITE_ONLY_OES;
287     mState.mAccessFlags = access;
288 
289     // The OES_mapbuffer extension states that GL_WRITE_ONLY_OES is the only valid
290     // value for GL_BUFFER_ACCESS_OES because it was written against ES2.  Since there is
291     // no update for ES3 and the GL_READ_ONLY and GL_READ_WRITE enums don't exist for ES,
292     // we cannot properly set GL_BUFFER_ACCESS_OES when glMapBufferRange is called.
293 
294     if ((access & GL_MAP_WRITE_BIT) > 0)
295     {
296         mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
297                                          static_cast<unsigned int>(length));
298     }
299 
300     // Notify when state changes.
301     onStateChange(angle::SubjectMessage::SubjectMapped);
302 
303     return angle::Result::Continue;
304 }
305 
unmap(const Context * context,GLboolean * result)306 angle::Result Buffer::unmap(const Context *context, GLboolean *result)
307 {
308     ASSERT(mState.mMapped);
309 
310     *result = GL_FALSE;
311     ANGLE_TRY(mImpl->unmap(context, result));
312 
313     mState.mMapped      = GL_FALSE;
314     mState.mMapPointer  = nullptr;
315     mState.mMapOffset   = 0;
316     mState.mMapLength   = 0;
317     mState.mAccess      = GL_WRITE_ONLY_OES;
318     mState.mAccessFlags = 0;
319 
320     // Notify when data changes.
321     onStateChange(angle::SubjectMessage::SubjectUnmapped);
322 
323     return angle::Result::Continue;
324 }
325 
onDataChanged()326 void Buffer::onDataChanged()
327 {
328     mIndexRangeCache.clear();
329 
330     // Notify when data changes.
331     onContentsChange();
332 
333     mImpl->onDataChanged();
334 }
335 
getIndexRange(const gl::Context * context,DrawElementsType type,size_t offset,size_t count,bool primitiveRestartEnabled,IndexRange * outRange) const336 angle::Result Buffer::getIndexRange(const gl::Context *context,
337                                     DrawElementsType type,
338                                     size_t offset,
339                                     size_t count,
340                                     bool primitiveRestartEnabled,
341                                     IndexRange *outRange) const
342 {
343     if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
344     {
345         return angle::Result::Continue;
346     }
347 
348     ANGLE_TRY(
349         mImpl->getIndexRange(context, type, offset, count, primitiveRestartEnabled, outRange));
350 
351     mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
352 
353     return angle::Result::Continue;
354 }
355 
getMemorySize() const356 GLint64 Buffer::getMemorySize() const
357 {
358     GLint64 implSize = mImpl->getMemorySize();
359     return implSize > 0 ? implSize : mState.mSize;
360 }
361 
isDoubleBoundForTransformFeedback() const362 bool Buffer::isDoubleBoundForTransformFeedback() const
363 {
364     return mState.mTransformFeedbackIndexedBindingCount > 1;
365 }
366 
onTFBindingChanged(const Context * context,bool bound,bool indexed)367 void Buffer::onTFBindingChanged(const Context *context, bool bound, bool indexed)
368 {
369     ASSERT(bound || mState.mBindingCount > 0);
370     mState.mBindingCount += bound ? 1 : -1;
371     if (indexed)
372     {
373         ASSERT(bound || mState.mTransformFeedbackIndexedBindingCount > 0);
374         mState.mTransformFeedbackIndexedBindingCount += bound ? 1 : -1;
375 
376         onStateChange(angle::SubjectMessage::BindingChanged);
377     }
378     else
379     {
380         mState.mTransformFeedbackGenericBindingCount += bound ? 1 : -1;
381     }
382 }
383 
getSubData(const gl::Context * context,GLintptr offset,GLsizeiptr size,void * outData)384 angle::Result Buffer::getSubData(const gl::Context *context,
385                                  GLintptr offset,
386                                  GLsizeiptr size,
387                                  void *outData)
388 {
389     return mImpl->getSubData(context, offset, size, outData);
390 }
391 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)392 void Buffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
393 {
394     // Pass it along!
395     ASSERT(index == kImplementationSubjectIndex);
396     ASSERT(message == angle::SubjectMessage::SubjectChanged ||
397            message == angle::SubjectMessage::InternalMemoryAllocationChanged);
398     onStateChange(message);
399 }
400 
getContentsObserverIndex(VertexArray * vertexArray,uint32_t bufferIndex) const401 size_t Buffer::getContentsObserverIndex(VertexArray *vertexArray, uint32_t bufferIndex) const
402 {
403     for (size_t observerIndex = 0; observerIndex < mContentsObservers.size(); ++observerIndex)
404     {
405         const ContentsObserver &observer = mContentsObservers[observerIndex];
406         if (observer.vertexArray == vertexArray && observer.bufferIndex == bufferIndex)
407         {
408             return observerIndex;
409         }
410     }
411 
412     return kInvalidContentsObserverIndex;
413 }
414 
addContentsObserver(VertexArray * vertexArray,uint32_t bufferIndex)415 void Buffer::addContentsObserver(VertexArray *vertexArray, uint32_t bufferIndex)
416 {
417     if (getContentsObserverIndex(vertexArray, bufferIndex) == kInvalidContentsObserverIndex)
418     {
419         mContentsObservers.push_back({vertexArray, bufferIndex});
420     }
421 }
422 
removeContentsObserver(VertexArray * vertexArray,uint32_t bufferIndex)423 void Buffer::removeContentsObserver(VertexArray *vertexArray, uint32_t bufferIndex)
424 {
425     size_t foundObserver = getContentsObserverIndex(vertexArray, bufferIndex);
426     if (foundObserver != kInvalidContentsObserverIndex)
427     {
428         size_t lastObserverIndex = mContentsObservers.size() - 1;
429         if (foundObserver != lastObserverIndex)
430         {
431             mContentsObservers[foundObserver] = mContentsObservers[lastObserverIndex];
432         }
433         mContentsObservers.pop_back();
434     }
435 }
436 
onContentsChange()437 void Buffer::onContentsChange()
438 {
439     for (const ContentsObserver &observer : mContentsObservers)
440     {
441         observer.vertexArray->onBufferContentsChange(observer.bufferIndex);
442     }
443 }
444 }  // namespace gl
445