xref: /aosp_15_r20/external/angle/src/libANGLE/Buffer.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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::InvalidEnum, flags);
121 }
122 
bufferData(Context * context,BufferBinding target,const void * data,GLsizeiptr size,BufferUsage usage)123 angle::Result Buffer::bufferData(Context *context,
124                                  BufferBinding target,
125                                  const void *data,
126                                  GLsizeiptr size,
127                                  BufferUsage usage)
128 {
129     GLbitfield flags = (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_DYNAMIC_STORAGE_BIT_EXT);
130     return bufferDataImpl(context, target, data, size, usage, flags);
131 }
132 
bufferDataImpl(Context * context,BufferBinding target,const void * data,GLsizeiptr size,BufferUsage usage,GLbitfield flags)133 angle::Result Buffer::bufferDataImpl(Context *context,
134                                      BufferBinding target,
135                                      const void *data,
136                                      GLsizeiptr size,
137                                      BufferUsage usage,
138                                      GLbitfield flags)
139 {
140     const void *dataForImpl = data;
141 
142     if (mState.isMapped())
143     {
144         // Per the OpenGL ES 3.0 spec, buffers are implicity unmapped when a call to
145         // BufferData happens on a mapped buffer:
146         //
147         //     If any portion of the buffer object is mapped in the current context or any context
148         //     current to another thread, it is as though UnmapBuffer (see section 2.10.3) is
149         //     executed in each such context prior to deleting the existing data store.
150         //
151         GLboolean dontCare = GL_FALSE;
152         ANGLE_TRY(unmap(context, &dontCare));
153     }
154 
155     // If we are using robust resource init, make sure the buffer starts cleared.
156     // Note: the Context is checked for nullptr because of some testing code.
157     // TODO(jmadill): Investigate lazier clearing.
158     if (context && context->isRobustResourceInitEnabled() && !data && size > 0)
159     {
160         angle::MemoryBuffer *scratchBuffer = nullptr;
161         ANGLE_CHECK_GL_ALLOC(
162             context, context->getZeroFilledBuffer(static_cast<size_t>(size), &scratchBuffer));
163         dataForImpl = scratchBuffer->data();
164     }
165 
166     if (mImpl->setDataWithUsageFlags(context, target, nullptr, dataForImpl, size, usage, flags) ==
167         angle::Result::Stop)
168     {
169         // If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
170         mIndexRangeCache.clear();
171         mState.mSize = 0;
172 
173         // Notify when storage changes.
174         onStateChange(angle::SubjectMessage::SubjectChanged);
175 
176         return angle::Result::Stop;
177     }
178 
179     bool wholeBuffer = size == mState.mSize;
180 
181     mIndexRangeCache.clear();
182     mState.mUsage                = usage;
183     mState.mSize                 = size;
184     mState.mImmutable            = (usage == BufferUsage::InvalidEnum);
185     mState.mStorageExtUsageFlags = flags;
186 
187     // Notify when storage changes.
188     if (wholeBuffer)
189     {
190         onContentsChange();
191     }
192     else
193     {
194         onStateChange(angle::SubjectMessage::SubjectChanged);
195     }
196 
197     return angle::Result::Continue;
198 }
199 
bufferExternalDataImpl(Context * context,BufferBinding target,GLeglClientBufferEXT clientBuffer,GLsizeiptr size,GLbitfield flags)200 angle::Result Buffer::bufferExternalDataImpl(Context *context,
201                                              BufferBinding target,
202                                              GLeglClientBufferEXT clientBuffer,
203                                              GLsizeiptr size,
204                                              GLbitfield flags)
205 {
206     if (mState.isMapped())
207     {
208         // Per the OpenGL ES 3.0 spec, buffers are implicitly unmapped when a call to
209         // BufferData happens on a mapped buffer:
210         //
211         //     If any portion of the buffer object is mapped in the current context or any context
212         //     current to another thread, it is as though UnmapBuffer (see section 2.10.3) is
213         //     executed in each such context prior to deleting the existing data store.
214         //
215         GLboolean dontCare = GL_FALSE;
216         ANGLE_TRY(unmap(context, &dontCare));
217     }
218 
219     if (mImpl->setDataWithUsageFlags(context, target, clientBuffer, nullptr, size,
220                                      BufferUsage::InvalidEnum, flags) == angle::Result::Stop)
221     {
222         // If setData fails, the buffer contents are undefined. Set a zero size to indicate that.
223         mIndexRangeCache.clear();
224         mState.mSize = 0;
225 
226         // Notify when storage changes.
227         onStateChange(angle::SubjectMessage::SubjectChanged);
228 
229         return angle::Result::Stop;
230     }
231 
232     mIndexRangeCache.clear();
233     mState.mUsage                = BufferUsage::InvalidEnum;
234     mState.mSize                 = size;
235     mState.mImmutable            = GL_TRUE;
236     mState.mStorageExtUsageFlags = flags;
237     mState.mExternal             = GL_TRUE;
238 
239     // Notify when storage changes.
240     onStateChange(angle::SubjectMessage::SubjectChanged);
241 
242     return angle::Result::Continue;
243 }
244 
bufferSubData(const Context * context,BufferBinding target,const void * data,GLsizeiptr size,GLintptr offset)245 angle::Result Buffer::bufferSubData(const Context *context,
246                                     BufferBinding target,
247                                     const void *data,
248                                     GLsizeiptr size,
249                                     GLintptr offset)
250 {
251     ANGLE_TRY(mImpl->setSubData(context, target, data, size, offset));
252 
253     mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
254                                      static_cast<unsigned int>(size));
255 
256     // Notify when data changes.
257     onContentsChange();
258 
259     return angle::Result::Continue;
260 }
261 
copyBufferSubData(const Context * context,Buffer * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)262 angle::Result Buffer::copyBufferSubData(const Context *context,
263                                         Buffer *source,
264                                         GLintptr sourceOffset,
265                                         GLintptr destOffset,
266                                         GLsizeiptr size)
267 {
268     ANGLE_TRY(
269         mImpl->copySubData(context, source->getImplementation(), sourceOffset, destOffset, size));
270 
271     mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset),
272                                      static_cast<unsigned int>(size));
273 
274     // Notify when data changes.
275     onContentsChange();
276 
277     return angle::Result::Continue;
278 }
279 
map(const Context * context,GLenum access)280 angle::Result Buffer::map(const Context *context, GLenum access)
281 {
282     ASSERT(!mState.mMapped);
283 
284     mState.mMapPointer = nullptr;
285     ANGLE_TRY(mImpl->map(context, access, &mState.mMapPointer));
286 
287     ASSERT(access == GL_WRITE_ONLY_OES);
288 
289     mState.mMapped      = GL_TRUE;
290     mState.mMapOffset   = 0;
291     mState.mMapLength   = mState.mSize;
292     mState.mAccess      = access;
293     mState.mAccessFlags = GL_MAP_WRITE_BIT;
294     mIndexRangeCache.clear();
295 
296     // Notify when state changes.
297     onStateChange(angle::SubjectMessage::SubjectMapped);
298 
299     return angle::Result::Continue;
300 }
301 
mapRange(const Context * context,GLintptr offset,GLsizeiptr length,GLbitfield access)302 angle::Result Buffer::mapRange(const Context *context,
303                                GLintptr offset,
304                                GLsizeiptr length,
305                                GLbitfield access)
306 {
307     ASSERT(!mState.mMapped);
308     ASSERT(offset + length <= mState.mSize);
309 
310     mState.mMapPointer = nullptr;
311     ANGLE_TRY(mImpl->mapRange(context, offset, length, access, &mState.mMapPointer));
312 
313     mState.mMapped      = GL_TRUE;
314     mState.mMapOffset   = static_cast<GLint64>(offset);
315     mState.mMapLength   = static_cast<GLint64>(length);
316     mState.mAccess      = GL_WRITE_ONLY_OES;
317     mState.mAccessFlags = access;
318 
319     // The OES_mapbuffer extension states that GL_WRITE_ONLY_OES is the only valid
320     // value for GL_BUFFER_ACCESS_OES because it was written against ES2.  Since there is
321     // no update for ES3 and the GL_READ_ONLY and GL_READ_WRITE enums don't exist for ES,
322     // we cannot properly set GL_BUFFER_ACCESS_OES when glMapBufferRange is called.
323 
324     if ((access & GL_MAP_WRITE_BIT) > 0)
325     {
326         mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
327                                          static_cast<unsigned int>(length));
328     }
329 
330     // Notify when state changes.
331     onStateChange(angle::SubjectMessage::SubjectMapped);
332 
333     return angle::Result::Continue;
334 }
335 
unmap(const Context * context,GLboolean * result)336 angle::Result Buffer::unmap(const Context *context, GLboolean *result)
337 {
338     ASSERT(mState.mMapped);
339 
340     *result = GL_FALSE;
341     ANGLE_TRY(mImpl->unmap(context, result));
342 
343     mState.mMapped      = GL_FALSE;
344     mState.mMapPointer  = nullptr;
345     mState.mMapOffset   = 0;
346     mState.mMapLength   = 0;
347     mState.mAccess      = GL_WRITE_ONLY_OES;
348     mState.mAccessFlags = 0;
349 
350     // Notify when data changes.
351     onStateChange(angle::SubjectMessage::SubjectUnmapped);
352 
353     return angle::Result::Continue;
354 }
355 
onDataChanged()356 void Buffer::onDataChanged()
357 {
358     mIndexRangeCache.clear();
359 
360     // Notify when data changes.
361     onContentsChange();
362 
363     mImpl->onDataChanged();
364 }
365 
getIndexRange(const gl::Context * context,DrawElementsType type,size_t offset,size_t count,bool primitiveRestartEnabled,IndexRange * outRange) const366 angle::Result Buffer::getIndexRange(const gl::Context *context,
367                                     DrawElementsType type,
368                                     size_t offset,
369                                     size_t count,
370                                     bool primitiveRestartEnabled,
371                                     IndexRange *outRange) const
372 {
373     if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
374     {
375         return angle::Result::Continue;
376     }
377 
378     ANGLE_TRY(
379         mImpl->getIndexRange(context, type, offset, count, primitiveRestartEnabled, outRange));
380 
381     mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
382 
383     return angle::Result::Continue;
384 }
385 
getMemorySize() const386 GLint64 Buffer::getMemorySize() const
387 {
388     GLint64 implSize = mImpl->getMemorySize();
389     return implSize > 0 ? implSize : mState.mSize;
390 }
391 
isDoubleBoundForTransformFeedback() const392 bool Buffer::isDoubleBoundForTransformFeedback() const
393 {
394     return mState.mTransformFeedbackIndexedBindingCount > 1;
395 }
396 
onTFBindingChanged(const Context * context,bool bound,bool indexed)397 void Buffer::onTFBindingChanged(const Context *context, bool bound, bool indexed)
398 {
399     ASSERT(bound || mState.mBindingCount > 0);
400     mState.mBindingCount += bound ? 1 : -1;
401     if (indexed)
402     {
403         ASSERT(bound || mState.mTransformFeedbackIndexedBindingCount > 0);
404         mState.mTransformFeedbackIndexedBindingCount += bound ? 1 : -1;
405 
406         onStateChange(angle::SubjectMessage::BindingChanged);
407     }
408     else
409     {
410         mState.mTransformFeedbackGenericBindingCount += bound ? 1 : -1;
411     }
412 }
413 
getSubData(const gl::Context * context,GLintptr offset,GLsizeiptr size,void * outData)414 angle::Result Buffer::getSubData(const gl::Context *context,
415                                  GLintptr offset,
416                                  GLsizeiptr size,
417                                  void *outData)
418 {
419     return mImpl->getSubData(context, offset, size, outData);
420 }
421 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)422 void Buffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
423 {
424     // Pass it along!
425     ASSERT(index == kImplementationSubjectIndex);
426     ASSERT(message == angle::SubjectMessage::SubjectChanged ||
427            message == angle::SubjectMessage::InternalMemoryAllocationChanged);
428     onStateChange(message);
429 }
430 
getContentsObserverIndex(void * observer,uint32_t bufferIndex) const431 size_t Buffer::getContentsObserverIndex(void *observer, uint32_t bufferIndex) const
432 {
433     ContentsObserver contentsObserver{bufferIndex, observer};
434     for (size_t observerIndex = 0; observerIndex < mContentsObservers.size(); ++observerIndex)
435     {
436         if (mContentsObservers[observerIndex] == contentsObserver)
437         {
438             return observerIndex;
439         }
440     }
441 
442     return kInvalidContentsObserverIndex;
443 }
444 
addContentsObserver(VertexArray * vertexArray,uint32_t bufferIndex)445 void Buffer::addContentsObserver(VertexArray *vertexArray, uint32_t bufferIndex)
446 {
447     ASSERT(bufferIndex != ContentsObserver::kBufferTextureIndex);
448     if (getContentsObserverIndex(vertexArray, bufferIndex) == kInvalidContentsObserverIndex)
449     {
450         mContentsObservers.push_back({bufferIndex, vertexArray});
451     }
452 }
453 
removeContentsObserverImpl(void * observer,uint32_t bufferIndex)454 void Buffer::removeContentsObserverImpl(void *observer, uint32_t bufferIndex)
455 {
456     size_t foundObserver = getContentsObserverIndex(observer, bufferIndex);
457     if (foundObserver != kInvalidContentsObserverIndex)
458     {
459         size_t lastObserverIndex = mContentsObservers.size() - 1;
460         if (foundObserver != lastObserverIndex)
461         {
462             mContentsObservers[foundObserver] = mContentsObservers[lastObserverIndex];
463         }
464         mContentsObservers.pop_back();
465     }
466 }
467 
removeContentsObserver(VertexArray * vertexArray,uint32_t bufferIndex)468 void Buffer::removeContentsObserver(VertexArray *vertexArray, uint32_t bufferIndex)
469 {
470     removeContentsObserverImpl(vertexArray, bufferIndex);
471 }
472 
addContentsObserver(Texture * texture)473 void Buffer::addContentsObserver(Texture *texture)
474 {
475     if (!hasContentsObserver(texture))
476     {
477         mContentsObservers.push_back({ContentsObserver::kBufferTextureIndex, texture});
478     }
479 }
480 
removeContentsObserver(Texture * texture)481 void Buffer::removeContentsObserver(Texture *texture)
482 {
483     removeContentsObserverImpl(texture, ContentsObserver::kBufferTextureIndex);
484 }
485 
hasContentsObserver(Texture * texture) const486 bool Buffer::hasContentsObserver(Texture *texture) const
487 {
488     return getContentsObserverIndex(texture, ContentsObserver::kBufferTextureIndex) !=
489            kInvalidContentsObserverIndex;
490 }
491 
onContentsChange()492 void Buffer::onContentsChange()
493 {
494     for (const ContentsObserver &contentsObserver : mContentsObservers)
495     {
496         if (contentsObserver.bufferIndex != ContentsObserver::kBufferTextureIndex)
497         {
498             static_cast<VertexArray *>(contentsObserver.observer)
499                 ->onBufferContentsChange(contentsObserver.bufferIndex);
500         }
501         else
502         {
503             static_cast<Texture *>(contentsObserver.observer)->onBufferContentsChange();
504         }
505     }
506 }
507 }  // namespace gl
508