• 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       mWebGLType(WebGLBufferType::Undefined)
42 {}
43 
~BufferState()44 BufferState::~BufferState() {}
45 
Buffer(rx::GLImplFactory * factory,BufferID id)46 Buffer::Buffer(rx::GLImplFactory *factory, BufferID id)
47     : RefCountObject(factory->generateSerial(), id),
48       mImpl(factory->createBuffer(mState)),
49       mImplObserver(this, kImplementationSubjectIndex)
50 {
51     mImplObserver.bind(mImpl);
52 }
53 
~Buffer()54 Buffer::~Buffer()
55 {
56     SafeDelete(mImpl);
57 }
58 
onDestroy(const Context * context)59 void Buffer::onDestroy(const Context *context)
60 {
61     mContentsObservers.clear();
62 
63     // In tests, mImpl might be null.
64     if (mImpl)
65         mImpl->destroy(context);
66 }
67 
onBind(const Context * context,BufferBinding target)68 void Buffer::onBind(const Context *context, BufferBinding target)
69 {
70     // Note: this function is called from glBindBuffer, which does not hold the share group lock.
71     // However, it only affects webgl contexts, where browsers already guarantees thread safety.
72     if (!context->isWebGL())
73     {
74         return;
75     }
76 
77     if (mState.mWebGLType == WebGLBufferType::Undefined)
78     {
79         if (target == BufferBinding::ElementArray)
80         {
81             mState.mWebGLType = WebGLBufferType::ElementArray;
82         }
83         else
84         {
85             mState.mWebGLType = WebGLBufferType::OtherData;
86         }
87     }
88 }
89 
setLabel(const Context * context,const std::string & label)90 angle::Result Buffer::setLabel(const Context *context, const std::string &label)
91 {
92     mState.mLabel = label;
93     if (mImpl)
94     {
95         return mImpl->onLabelUpdate(context);
96     }
97     return angle::Result::Continue;
98 }
99 
getLabel() const100 const std::string &Buffer::getLabel() const
101 {
102     return mState.mLabel;
103 }
104 
bufferStorageExternal(Context * context,BufferBinding target,GLsizeiptr size,GLeglClientBufferEXT clientBuffer,GLbitfield flags)105 angle::Result Buffer::bufferStorageExternal(Context *context,
106                                             BufferBinding target,
107                                             GLsizeiptr size,
108                                             GLeglClientBufferEXT clientBuffer,
109                                             GLbitfield flags)
110 {
111     return bufferExternalDataImpl(context, target, clientBuffer, size, flags);
112 }
113 
bufferStorage(Context * context,BufferBinding target,GLsizeiptr size,const void * data,GLbitfield flags)114 angle::Result Buffer::bufferStorage(Context *context,
115                                     BufferBinding target,
116                                     GLsizeiptr size,
117                                     const void *data,
118                                     GLbitfield flags)
119 {
120     return bufferDataImpl(context, target, data, size, BufferUsage::DynamicDraw, flags,
121                           BufferStorage::Immutable);
122 }
123 
bufferData(Context * context,BufferBinding target,const void * data,GLsizeiptr size,BufferUsage usage)124 angle::Result Buffer::bufferData(Context *context,
125                                  BufferBinding target,
126                                  const void *data,
127                                  GLsizeiptr size,
128                                  BufferUsage usage)
129 {
130     GLbitfield flags = (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT_EXT);
131     return bufferDataImpl(context, target, data, size, usage, flags, BufferStorage::Mutable);
132 }
133 
bufferDataImpl(Context * context,BufferBinding target,const void * data,GLsizeiptr size,BufferUsage usage,GLbitfield flags,BufferStorage bufferStorage)134 angle::Result Buffer::bufferDataImpl(Context *context,
135                                      BufferBinding target,
136                                      const void *data,
137                                      GLsizeiptr size,
138                                      BufferUsage usage,
139                                      GLbitfield flags,
140                                      BufferStorage bufferStorage)
141 {
142     const void *dataForImpl = data;
143 
144     if (mState.isMapped())
145     {
146         // Per the OpenGL ES 3.0 spec, buffers are implicity unmapped when a call to
147         // BufferData happens on a mapped buffer:
148         //
149         //     If any portion of the buffer object is mapped in the current context or any context
150         //     current to another thread, it is as though UnmapBuffer (see section 2.10.3) is
151         //     executed in each such context prior to deleting the existing data store.
152         //
153         GLboolean dontCare = GL_FALSE;
154         ANGLE_TRY(unmap(context, &dontCare));
155     }
156 
157     // If we are using robust resource init, make sure the buffer starts cleared.
158     // Note: the Context is checked for nullptr because of some testing code.
159     // TODO(jmadill): Investigate lazier clearing.
160     if (context && context->isRobustResourceInitEnabled() && !data && size > 0)
161     {
162         angle::MemoryBuffer *scratchBuffer = nullptr;
163         ANGLE_CHECK_GL_ALLOC(
164             context, context->getZeroFilledBuffer(static_cast<size_t>(size), &scratchBuffer));
165         dataForImpl = scratchBuffer->data();
166     }
167 
168     if (mImpl->setDataWithUsageFlags(context, target, nullptr, dataForImpl, size, usage, flags,
169                                      bufferStorage) == angle::Result::Stop)
170     {
171         // If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
172         mIndexRangeCache.clear();
173         mState.mSize = 0;
174 
175         // Notify when storage changes.
176         onStateChange(angle::SubjectMessage::SubjectChanged);
177 
178         return angle::Result::Stop;
179     }
180 
181     bool wholeBuffer = size == mState.mSize;
182 
183     mIndexRangeCache.clear();
184     mState.mUsage                = usage;
185     mState.mSize                 = size;
186     mState.mImmutable            = (bufferStorage == BufferStorage::Immutable);
187     mState.mStorageExtUsageFlags = flags;
188 
189     // Notify when storage changes.
190     if (wholeBuffer)
191     {
192         onContentsChange();
193     }
194     else
195     {
196         onStateChange(angle::SubjectMessage::SubjectChanged);
197     }
198 
199     return angle::Result::Continue;
200 }
201 
bufferExternalDataImpl(Context * context,BufferBinding target,GLeglClientBufferEXT clientBuffer,GLsizeiptr size,GLbitfield flags)202 angle::Result Buffer::bufferExternalDataImpl(Context *context,
203                                              BufferBinding target,
204                                              GLeglClientBufferEXT clientBuffer,
205                                              GLsizeiptr size,
206                                              GLbitfield flags)
207 {
208     if (mState.isMapped())
209     {
210         // Per the OpenGL ES 3.0 spec, buffers are implicitly unmapped when a call to
211         // BufferData happens on a mapped buffer:
212         //
213         //     If any portion of the buffer object is mapped in the current context or any context
214         //     current to another thread, it is as though UnmapBuffer (see section 2.10.3) is
215         //     executed in each such context prior to deleting the existing data store.
216         //
217         GLboolean dontCare = GL_FALSE;
218         ANGLE_TRY(unmap(context, &dontCare));
219     }
220 
221     if (mImpl->setDataWithUsageFlags(context, target, clientBuffer, nullptr, size,
222                                      BufferUsage::InvalidEnum, flags,
223                                      BufferStorage::Immutable) == angle::Result::Stop)
224     {
225         // If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
226         mIndexRangeCache.clear();
227         mState.mSize = 0;
228 
229         // Notify when storage changes.
230         onStateChange(angle::SubjectMessage::SubjectChanged);
231 
232         return angle::Result::Stop;
233     }
234 
235     mIndexRangeCache.clear();
236     mState.mUsage                = BufferUsage::InvalidEnum;
237     mState.mSize                 = size;
238     mState.mImmutable            = GL_TRUE;
239     mState.mStorageExtUsageFlags = flags;
240     mState.mExternal             = GL_TRUE;
241 
242     // Notify when storage changes.
243     onStateChange(angle::SubjectMessage::SubjectChanged);
244 
245     return angle::Result::Continue;
246 }
247 
bufferSubData(const Context * context,BufferBinding target,const void * data,GLsizeiptr size,GLintptr offset)248 angle::Result Buffer::bufferSubData(const Context *context,
249                                     BufferBinding target,
250                                     const void *data,
251                                     GLsizeiptr size,
252                                     GLintptr offset)
253 {
254     ANGLE_TRY(mImpl->setSubData(context, target, data, size, offset));
255 
256     mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
257                                      static_cast<unsigned int>(size));
258 
259     // Notify when data changes.
260     onContentsChange();
261 
262     return angle::Result::Continue;
263 }
264 
copyBufferSubData(const Context * context,Buffer * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)265 angle::Result Buffer::copyBufferSubData(const Context *context,
266                                         Buffer *source,
267                                         GLintptr sourceOffset,
268                                         GLintptr destOffset,
269                                         GLsizeiptr size)
270 {
271     ANGLE_TRY(
272         mImpl->copySubData(context, source->getImplementation(), sourceOffset, destOffset, size));
273 
274     mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset),
275                                      static_cast<unsigned int>(size));
276 
277     // Notify when data changes.
278     onContentsChange();
279 
280     return angle::Result::Continue;
281 }
282 
map(const Context * context,GLenum access)283 angle::Result Buffer::map(const Context *context, GLenum access)
284 {
285     ASSERT(!mState.mMapped);
286 
287     mState.mMapPointer = nullptr;
288     ANGLE_TRY(mImpl->map(context, access, &mState.mMapPointer));
289 
290     ASSERT(access == GL_WRITE_ONLY_OES);
291 
292     mState.mMapped      = GL_TRUE;
293     mState.mMapOffset   = 0;
294     mState.mMapLength   = mState.mSize;
295     mState.mAccess      = access;
296     mState.mAccessFlags = GL_MAP_WRITE_BIT;
297     mIndexRangeCache.clear();
298 
299     // Notify when state changes.
300     onStateChange(angle::SubjectMessage::SubjectMapped);
301 
302     return angle::Result::Continue;
303 }
304 
mapRange(const Context * context,GLintptr offset,GLsizeiptr length,GLbitfield access)305 angle::Result Buffer::mapRange(const Context *context,
306                                GLintptr offset,
307                                GLsizeiptr length,
308                                GLbitfield access)
309 {
310     ASSERT(!mState.mMapped);
311     ASSERT(offset + length <= mState.mSize);
312 
313     mState.mMapPointer = nullptr;
314     ANGLE_TRY(mImpl->mapRange(context, offset, length, access, &mState.mMapPointer));
315 
316     mState.mMapped      = GL_TRUE;
317     mState.mMapOffset   = static_cast<GLint64>(offset);
318     mState.mMapLength   = static_cast<GLint64>(length);
319     mState.mAccess      = GL_WRITE_ONLY_OES;
320     mState.mAccessFlags = access;
321 
322     // The OES_mapbuffer extension states that GL_WRITE_ONLY_OES is the only valid
323     // value for GL_BUFFER_ACCESS_OES because it was written against ES2.  Since there is
324     // no update for ES3 and the GL_READ_ONLY and GL_READ_WRITE enums don't exist for ES,
325     // we cannot properly set GL_BUFFER_ACCESS_OES when glMapBufferRange is called.
326 
327     if ((access & GL_MAP_WRITE_BIT) > 0)
328     {
329         mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
330                                          static_cast<unsigned int>(length));
331     }
332 
333     // Notify when state changes.
334     onStateChange(angle::SubjectMessage::SubjectMapped);
335 
336     return angle::Result::Continue;
337 }
338 
unmap(const Context * context,GLboolean * result)339 angle::Result Buffer::unmap(const Context *context, GLboolean *result)
340 {
341     ASSERT(mState.mMapped);
342 
343     *result = GL_FALSE;
344     ANGLE_TRY(mImpl->unmap(context, result));
345 
346     mState.mMapped      = GL_FALSE;
347     mState.mMapPointer  = nullptr;
348     mState.mMapOffset   = 0;
349     mState.mMapLength   = 0;
350     mState.mAccess      = GL_WRITE_ONLY_OES;
351     mState.mAccessFlags = 0;
352 
353     // Notify when data changes.
354     onStateChange(angle::SubjectMessage::SubjectUnmapped);
355 
356     return angle::Result::Continue;
357 }
358 
onDataChanged()359 void Buffer::onDataChanged()
360 {
361     mIndexRangeCache.clear();
362 
363     // Notify when data changes.
364     onContentsChange();
365 
366     mImpl->onDataChanged();
367 }
368 
getIndexRange(const gl::Context * context,DrawElementsType type,size_t offset,size_t count,bool primitiveRestartEnabled,IndexRange * outRange) const369 angle::Result Buffer::getIndexRange(const gl::Context *context,
370                                     DrawElementsType type,
371                                     size_t offset,
372                                     size_t count,
373                                     bool primitiveRestartEnabled,
374                                     IndexRange *outRange) const
375 {
376     if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
377     {
378         return angle::Result::Continue;
379     }
380 
381     ANGLE_TRY(
382         mImpl->getIndexRange(context, type, offset, count, primitiveRestartEnabled, outRange));
383 
384     mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
385 
386     return angle::Result::Continue;
387 }
388 
getMemorySize() const389 GLint64 Buffer::getMemorySize() const
390 {
391     GLint64 implSize = mImpl->getMemorySize();
392     return implSize > 0 ? implSize : mState.mSize;
393 }
394 
isDoubleBoundForTransformFeedback() const395 bool Buffer::isDoubleBoundForTransformFeedback() const
396 {
397     return mState.mTransformFeedbackIndexedBindingCount > 1;
398 }
399 
onTFBindingChanged(const Context * context,bool bound,bool indexed)400 void Buffer::onTFBindingChanged(const Context *context, bool bound, bool indexed)
401 {
402     ASSERT(bound || mState.mBindingCount > 0);
403     mState.mBindingCount += bound ? 1 : -1;
404     if (indexed)
405     {
406         ASSERT(bound || mState.mTransformFeedbackIndexedBindingCount > 0);
407         mState.mTransformFeedbackIndexedBindingCount += bound ? 1 : -1;
408 
409         onStateChange(angle::SubjectMessage::BindingChanged);
410     }
411     else
412     {
413         mState.mTransformFeedbackGenericBindingCount += bound ? 1 : -1;
414     }
415 }
416 
getSubData(const gl::Context * context,GLintptr offset,GLsizeiptr size,void * outData)417 angle::Result Buffer::getSubData(const gl::Context *context,
418                                  GLintptr offset,
419                                  GLsizeiptr size,
420                                  void *outData)
421 {
422     return mImpl->getSubData(context, offset, size, outData);
423 }
424 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)425 void Buffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
426 {
427     // Pass it along!
428     ASSERT(index == kImplementationSubjectIndex);
429     ASSERT(message == angle::SubjectMessage::SubjectChanged ||
430            message == angle::SubjectMessage::InternalMemoryAllocationChanged);
431     onStateChange(message);
432 }
433 
getContentsObserverIndex(void * observer,uint32_t bufferIndex) const434 size_t Buffer::getContentsObserverIndex(void *observer, uint32_t bufferIndex) const
435 {
436     ContentsObserver contentsObserver{bufferIndex, observer};
437     for (size_t observerIndex = 0; observerIndex < mContentsObservers.size(); ++observerIndex)
438     {
439         if (mContentsObservers[observerIndex] == contentsObserver)
440         {
441             return observerIndex;
442         }
443     }
444 
445     return kInvalidContentsObserverIndex;
446 }
447 
addContentsObserver(VertexArray * vertexArray,uint32_t bufferIndex)448 void Buffer::addContentsObserver(VertexArray *vertexArray, uint32_t bufferIndex)
449 {
450     ASSERT(bufferIndex != ContentsObserver::kBufferTextureIndex);
451     if (getContentsObserverIndex(vertexArray, bufferIndex) == kInvalidContentsObserverIndex)
452     {
453         mContentsObservers.push_back({bufferIndex, vertexArray});
454     }
455 }
456 
removeContentsObserverImpl(void * observer,uint32_t bufferIndex)457 void Buffer::removeContentsObserverImpl(void *observer, uint32_t bufferIndex)
458 {
459     size_t foundObserver = getContentsObserverIndex(observer, bufferIndex);
460     if (foundObserver != kInvalidContentsObserverIndex)
461     {
462         size_t lastObserverIndex = mContentsObservers.size() - 1;
463         if (foundObserver != lastObserverIndex)
464         {
465             mContentsObservers[foundObserver] = mContentsObservers[lastObserverIndex];
466         }
467         mContentsObservers.pop_back();
468     }
469 }
470 
removeContentsObserver(VertexArray * vertexArray,uint32_t bufferIndex)471 void Buffer::removeContentsObserver(VertexArray *vertexArray, uint32_t bufferIndex)
472 {
473     removeContentsObserverImpl(vertexArray, bufferIndex);
474 }
475 
addContentsObserver(Texture * texture)476 void Buffer::addContentsObserver(Texture *texture)
477 {
478     if (!hasContentsObserver(texture))
479     {
480         mContentsObservers.push_back({ContentsObserver::kBufferTextureIndex, texture});
481     }
482 }
483 
removeContentsObserver(Texture * texture)484 void Buffer::removeContentsObserver(Texture *texture)
485 {
486     removeContentsObserverImpl(texture, ContentsObserver::kBufferTextureIndex);
487 }
488 
hasContentsObserver(Texture * texture) const489 bool Buffer::hasContentsObserver(Texture *texture) const
490 {
491     return getContentsObserverIndex(texture, ContentsObserver::kBufferTextureIndex) !=
492            kInvalidContentsObserverIndex;
493 }
494 
onContentsChange()495 void Buffer::onContentsChange()
496 {
497     for (const ContentsObserver &contentsObserver : mContentsObservers)
498     {
499         if (contentsObserver.bufferIndex != ContentsObserver::kBufferTextureIndex)
500         {
501             static_cast<VertexArray *>(contentsObserver.observer)
502                 ->onBufferContentsChange(contentsObserver.bufferIndex);
503         }
504         else
505         {
506             static_cast<Texture *>(contentsObserver.observer)->onBufferContentsChange();
507         }
508     }
509 }
510 }  // namespace gl
511