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