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 we are using robust resource init, make sure the buffer starts cleared.
80 // Note: the Context is checked for nullptr because of some testing code.
81 // TODO(jmadill): Investigate lazier clearing.
82 if (context && context->getState().isRobustResourceInitEnabled() && !data && size > 0)
83 {
84 angle::MemoryBuffer *scratchBuffer = nullptr;
85 ANGLE_CHECK_GL_ALLOC(
86 context, context->getZeroFilledBuffer(static_cast<size_t>(size), &scratchBuffer));
87 dataForImpl = scratchBuffer->data();
88 }
89
90 ANGLE_TRY(mImpl->setData(context, target, dataForImpl, size, usage));
91
92 mIndexRangeCache.clear();
93 mState.mUsage = usage;
94 mState.mSize = size;
95
96 // Notify when storage changes.
97 onStateChange(angle::SubjectMessage::SubjectChanged);
98
99 return angle::Result::Continue;
100 }
101
bufferSubData(const Context * context,BufferBinding target,const void * data,GLsizeiptr size,GLintptr offset)102 angle::Result Buffer::bufferSubData(const Context *context,
103 BufferBinding target,
104 const void *data,
105 GLsizeiptr size,
106 GLintptr offset)
107 {
108 ANGLE_TRY(mImpl->setSubData(context, target, data, size, offset));
109
110 mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
111 static_cast<unsigned int>(size));
112
113 // Notify when data changes.
114 onStateChange(angle::SubjectMessage::ContentsChanged);
115
116 return angle::Result::Continue;
117 }
118
copyBufferSubData(const Context * context,Buffer * source,GLintptr sourceOffset,GLintptr destOffset,GLsizeiptr size)119 angle::Result Buffer::copyBufferSubData(const Context *context,
120 Buffer *source,
121 GLintptr sourceOffset,
122 GLintptr destOffset,
123 GLsizeiptr size)
124 {
125 ANGLE_TRY(
126 mImpl->copySubData(context, source->getImplementation(), sourceOffset, destOffset, size));
127
128 mIndexRangeCache.invalidateRange(static_cast<unsigned int>(destOffset),
129 static_cast<unsigned int>(size));
130
131 // Notify when data changes.
132 onStateChange(angle::SubjectMessage::ContentsChanged);
133
134 return angle::Result::Continue;
135 }
136
map(const Context * context,GLenum access)137 angle::Result Buffer::map(const Context *context, GLenum access)
138 {
139 ASSERT(!mState.mMapped);
140
141 mState.mMapPointer = nullptr;
142 ANGLE_TRY(mImpl->map(context, access, &mState.mMapPointer));
143
144 ASSERT(access == GL_WRITE_ONLY_OES);
145
146 mState.mMapped = GL_TRUE;
147 mState.mMapOffset = 0;
148 mState.mMapLength = mState.mSize;
149 mState.mAccess = access;
150 mState.mAccessFlags = GL_MAP_WRITE_BIT;
151 mIndexRangeCache.clear();
152
153 // Notify when state changes.
154 onStateChange(angle::SubjectMessage::SubjectMapped);
155
156 return angle::Result::Continue;
157 }
158
mapRange(const Context * context,GLintptr offset,GLsizeiptr length,GLbitfield access)159 angle::Result Buffer::mapRange(const Context *context,
160 GLintptr offset,
161 GLsizeiptr length,
162 GLbitfield access)
163 {
164 ASSERT(!mState.mMapped);
165 ASSERT(offset + length <= mState.mSize);
166
167 mState.mMapPointer = nullptr;
168 ANGLE_TRY(mImpl->mapRange(context, offset, length, access, &mState.mMapPointer));
169
170 mState.mMapped = GL_TRUE;
171 mState.mMapOffset = static_cast<GLint64>(offset);
172 mState.mMapLength = static_cast<GLint64>(length);
173 mState.mAccess = GL_WRITE_ONLY_OES;
174 mState.mAccessFlags = access;
175
176 // The OES_mapbuffer extension states that GL_WRITE_ONLY_OES is the only valid
177 // value for GL_BUFFER_ACCESS_OES because it was written against ES2. Since there is
178 // no update for ES3 and the GL_READ_ONLY and GL_READ_WRITE enums don't exist for ES,
179 // we cannot properly set GL_BUFFER_ACCESS_OES when glMapBufferRange is called.
180
181 if ((access & GL_MAP_WRITE_BIT) > 0)
182 {
183 mIndexRangeCache.invalidateRange(static_cast<unsigned int>(offset),
184 static_cast<unsigned int>(length));
185 }
186
187 // Notify when state changes.
188 onStateChange(angle::SubjectMessage::SubjectMapped);
189
190 return angle::Result::Continue;
191 }
192
unmap(const Context * context,GLboolean * result)193 angle::Result Buffer::unmap(const Context *context, GLboolean *result)
194 {
195 ASSERT(mState.mMapped);
196
197 *result = GL_FALSE;
198 ANGLE_TRY(mImpl->unmap(context, result));
199
200 mState.mMapped = GL_FALSE;
201 mState.mMapPointer = nullptr;
202 mState.mMapOffset = 0;
203 mState.mMapLength = 0;
204 mState.mAccess = GL_WRITE_ONLY_OES;
205 mState.mAccessFlags = 0;
206
207 // Notify when data changes.
208 onStateChange(angle::SubjectMessage::SubjectUnmapped);
209
210 return angle::Result::Continue;
211 }
212
onDataChanged()213 void Buffer::onDataChanged()
214 {
215 mIndexRangeCache.clear();
216
217 // Notify when data changes.
218 onStateChange(angle::SubjectMessage::ContentsChanged);
219
220 mImpl->onDataChanged();
221 }
222
getIndexRange(const gl::Context * context,DrawElementsType type,size_t offset,size_t count,bool primitiveRestartEnabled,IndexRange * outRange) const223 angle::Result Buffer::getIndexRange(const gl::Context *context,
224 DrawElementsType type,
225 size_t offset,
226 size_t count,
227 bool primitiveRestartEnabled,
228 IndexRange *outRange) const
229 {
230 if (mIndexRangeCache.findRange(type, offset, count, primitiveRestartEnabled, outRange))
231 {
232 return angle::Result::Continue;
233 }
234
235 ANGLE_TRY(
236 mImpl->getIndexRange(context, type, offset, count, primitiveRestartEnabled, outRange));
237
238 mIndexRangeCache.addRange(type, offset, count, primitiveRestartEnabled, *outRange);
239
240 return angle::Result::Continue;
241 }
242
getMemorySize() const243 GLint64 Buffer::getMemorySize() const
244 {
245 GLint64 implSize = mImpl->getMemorySize();
246 return implSize > 0 ? implSize : mState.mSize;
247 }
248
isDoubleBoundForTransformFeedback() const249 bool Buffer::isDoubleBoundForTransformFeedback() const
250 {
251 return mState.mTransformFeedbackIndexedBindingCount > 1;
252 }
253
onTFBindingChanged(const Context * context,bool bound,bool indexed)254 void Buffer::onTFBindingChanged(const Context *context, bool bound, bool indexed)
255 {
256 ASSERT(bound || mState.mBindingCount > 0);
257 mState.mBindingCount += bound ? 1 : -1;
258 if (indexed)
259 {
260 ASSERT(bound || mState.mTransformFeedbackIndexedBindingCount > 0);
261 mState.mTransformFeedbackIndexedBindingCount += bound ? 1 : -1;
262
263 onStateChange(angle::SubjectMessage::BindingChanged);
264 }
265 else
266 {
267 mState.mTransformFeedbackGenericBindingCount += bound ? 1 : -1;
268 }
269 }
270
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)271 void Buffer::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
272 {
273 // Pass it along!
274 ASSERT(index == kImplementationSubjectIndex);
275 ASSERT(message == angle::SubjectMessage::SubjectChanged);
276 onStateChange(angle::SubjectMessage::SubjectChanged);
277 }
278 } // namespace gl
279