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