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