content/canvas/src/WebGLContextBuffers.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "WebGLContext.h"
michael@0 7 #include "GLContext.h"
michael@0 8 #include "WebGLBuffer.h"
michael@0 9 #include "WebGLVertexArray.h"
michael@0 10
michael@0 11 using namespace mozilla;
michael@0 12 using namespace mozilla::dom;
michael@0 13
michael@0 14 void
michael@0 15 WebGLContext::BindBuffer(GLenum target, WebGLBuffer *buffer)
michael@0 16 {
michael@0 17 if (IsContextLost())
michael@0 18 return;
michael@0 19
michael@0 20 if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
michael@0 21 return;
michael@0 22
michael@0 23 // silently ignore a deleted buffer
michael@0 24 if (buffer && buffer->IsDeleted())
michael@0 25 return;
michael@0 26
michael@0 27 WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
michael@0 28
michael@0 29 if (!bufferSlot) {
michael@0 30 return;
michael@0 31 }
michael@0 32
michael@0 33 if (buffer) {
michael@0 34 if (!buffer->Target()) {
michael@0 35 buffer->SetTarget(target);
michael@0 36 buffer->SetHasEverBeenBound(true);
michael@0 37 } else if (target != buffer->Target()) {
michael@0 38 return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
michael@0 39 }
michael@0 40 }
michael@0 41
michael@0 42 *bufferSlot = buffer;
michael@0 43
michael@0 44 MakeContextCurrent();
michael@0 45
michael@0 46 gl->fBindBuffer(target, buffer ? buffer->GLName() : 0);
michael@0 47 }
michael@0 48
michael@0 49 void
michael@0 50 WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
michael@0 51 {
michael@0 52 if (IsContextLost())
michael@0 53 return;
michael@0 54
michael@0 55 if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
michael@0 56 return;
michael@0 57
michael@0 58 // silently ignore a deleted buffer
michael@0 59 if (buffer && buffer->IsDeleted()) {
michael@0 60 return;
michael@0 61 }
michael@0 62
michael@0 63 WebGLRefPtr<WebGLBuffer>* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
michael@0 64
michael@0 65 if (!indexedBufferSlot) {
michael@0 66 return;
michael@0 67 }
michael@0 68
michael@0 69 if (buffer) {
michael@0 70 if (!buffer->Target()) {
michael@0 71 buffer->SetTarget(target);
michael@0 72 buffer->SetHasEverBeenBound(true);
michael@0 73 } else if (target != buffer->Target()) {
michael@0 74 return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
michael@0 75 }
michael@0 76 }
michael@0 77
michael@0 78 WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
michael@0 79
michael@0 80 MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
michael@0 81
michael@0 82 *indexedBufferSlot = buffer;
michael@0 83 *bufferSlot = buffer;
michael@0 84
michael@0 85 MakeContextCurrent();
michael@0 86
michael@0 87 gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0);
michael@0 88 }
michael@0 89
michael@0 90 void
michael@0 91 WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
michael@0 92 WebGLintptr offset, WebGLsizeiptr size)
michael@0 93 {
michael@0 94 if (IsContextLost())
michael@0 95 return;
michael@0 96
michael@0 97 if (!ValidateObjectAllowDeletedOrNull("bindBufferRange", buffer))
michael@0 98 return;
michael@0 99
michael@0 100 // silently ignore a deleted buffer
michael@0 101 if (buffer && buffer->IsDeleted())
michael@0 102 return;
michael@0 103
michael@0 104 WebGLRefPtr<WebGLBuffer>* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
michael@0 105
michael@0 106 if (!indexedBufferSlot) {
michael@0 107 return;
michael@0 108 }
michael@0 109
michael@0 110 if (buffer) {
michael@0 111 if (!buffer->Target()) {
michael@0 112 buffer->SetTarget(target);
michael@0 113 buffer->SetHasEverBeenBound(true);
michael@0 114 } else if (target != buffer->Target()) {
michael@0 115 return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
michael@0 116 }
michael@0 117 CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + size;
michael@0 118 if (!checked_neededByteLength.isValid() ||
michael@0 119 checked_neededByteLength.value() > buffer->ByteLength())
michael@0 120 {
michael@0 121 return ErrorInvalidValue("bindBufferRange: invalid range");
michael@0 122 }
michael@0 123 }
michael@0 124
michael@0 125 WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
michael@0 126
michael@0 127 MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
michael@0 128
michael@0 129 *indexedBufferSlot = buffer;
michael@0 130 *bufferSlot = buffer;
michael@0 131
michael@0 132 MakeContextCurrent();
michael@0 133
michael@0 134 gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 0, offset, size);
michael@0 135 }
michael@0 136
michael@0 137 void
michael@0 138 WebGLContext::BufferData(GLenum target, WebGLsizeiptr size,
michael@0 139 GLenum usage)
michael@0 140 {
michael@0 141 if (IsContextLost())
michael@0 142 return;
michael@0 143
michael@0 144 WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferData");
michael@0 145
michael@0 146 if (!bufferSlot) {
michael@0 147 return;
michael@0 148 }
michael@0 149
michael@0 150 if (size < 0)
michael@0 151 return ErrorInvalidValue("bufferData: negative size");
michael@0 152
michael@0 153 if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
michael@0 154 return;
michael@0 155
michael@0 156 // careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t.
michael@0 157 if (!CheckedInt<GLsizeiptr>(size).isValid())
michael@0 158 return ErrorOutOfMemory("bufferData: bad size");
michael@0 159
michael@0 160 WebGLBuffer* boundBuffer = bufferSlot->get();
michael@0 161
michael@0 162 if (!boundBuffer)
michael@0 163 return ErrorInvalidOperation("bufferData: no buffer bound!");
michael@0 164
michael@0 165 void* zeroBuffer = calloc(size, 1);
michael@0 166 if (!zeroBuffer)
michael@0 167 return ErrorOutOfMemory("bufferData: out of memory");
michael@0 168
michael@0 169 MakeContextCurrent();
michael@0 170 InvalidateBufferFetching();
michael@0 171
michael@0 172 GLenum error = CheckedBufferData(target, size, zeroBuffer, usage);
michael@0 173 free(zeroBuffer);
michael@0 174
michael@0 175 if (error) {
michael@0 176 GenerateWarning("bufferData generated error %s", ErrorName(error));
michael@0 177 return;
michael@0 178 }
michael@0 179
michael@0 180 boundBuffer->SetByteLength(size);
michael@0 181 if (!boundBuffer->ElementArrayCacheBufferData(nullptr, size)) {
michael@0 182 return ErrorOutOfMemory("bufferData: out of memory");
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 void
michael@0 187 WebGLContext::BufferData(GLenum target,
michael@0 188 const Nullable<ArrayBuffer> &maybeData,
michael@0 189 GLenum usage)
michael@0 190 {
michael@0 191 if (IsContextLost())
michael@0 192 return;
michael@0 193
michael@0 194 if (maybeData.IsNull()) {
michael@0 195 // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
michael@0 196 return ErrorInvalidValue("bufferData: null object passed");
michael@0 197 }
michael@0 198
michael@0 199 WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferData");
michael@0 200
michael@0 201 if (!bufferSlot) {
michael@0 202 return;
michael@0 203 }
michael@0 204
michael@0 205 const ArrayBuffer& data = maybeData.Value();
michael@0 206 data.ComputeLengthAndData();
michael@0 207
michael@0 208 // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
michael@0 209 // is like intptr_t.
michael@0 210 if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
michael@0 211 return ErrorOutOfMemory("bufferData: bad size");
michael@0 212
michael@0 213 if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
michael@0 214 return;
michael@0 215
michael@0 216 WebGLBuffer* boundBuffer = bufferSlot->get();
michael@0 217
michael@0 218 if (!boundBuffer)
michael@0 219 return ErrorInvalidOperation("bufferData: no buffer bound!");
michael@0 220
michael@0 221 MakeContextCurrent();
michael@0 222 InvalidateBufferFetching();
michael@0 223
michael@0 224 GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
michael@0 225
michael@0 226 if (error) {
michael@0 227 GenerateWarning("bufferData generated error %s", ErrorName(error));
michael@0 228 return;
michael@0 229 }
michael@0 230
michael@0 231 boundBuffer->SetByteLength(data.Length());
michael@0 232 if (!boundBuffer->ElementArrayCacheBufferData(data.Data(), data.Length())) {
michael@0 233 return ErrorOutOfMemory("bufferData: out of memory");
michael@0 234 }
michael@0 235 }
michael@0 236
michael@0 237 void
michael@0 238 WebGLContext::BufferData(GLenum target, const ArrayBufferView& data,
michael@0 239 GLenum usage)
michael@0 240 {
michael@0 241 if (IsContextLost())
michael@0 242 return;
michael@0 243
michael@0 244 WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
michael@0 245
michael@0 246 if (!bufferSlot) {
michael@0 247 return;
michael@0 248 }
michael@0 249
michael@0 250 if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
michael@0 251 return;
michael@0 252
michael@0 253 WebGLBuffer* boundBuffer = bufferSlot->get();
michael@0 254
michael@0 255 if (!boundBuffer)
michael@0 256 return ErrorInvalidOperation("bufferData: no buffer bound!");
michael@0 257
michael@0 258 data.ComputeLengthAndData();
michael@0 259
michael@0 260 // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
michael@0 261 // is like intptr_t.
michael@0 262 if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
michael@0 263 return ErrorOutOfMemory("bufferData: bad size");
michael@0 264
michael@0 265 InvalidateBufferFetching();
michael@0 266 MakeContextCurrent();
michael@0 267
michael@0 268 GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
michael@0 269 if (error) {
michael@0 270 GenerateWarning("bufferData generated error %s", ErrorName(error));
michael@0 271 return;
michael@0 272 }
michael@0 273
michael@0 274 boundBuffer->SetByteLength(data.Length());
michael@0 275 if (!boundBuffer->ElementArrayCacheBufferData(data.Data(), data.Length())) {
michael@0 276 return ErrorOutOfMemory("bufferData: out of memory");
michael@0 277 }
michael@0 278 }
michael@0 279
michael@0 280 void
michael@0 281 WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
michael@0 282 const Nullable<ArrayBuffer> &maybeData)
michael@0 283 {
michael@0 284 if (IsContextLost())
michael@0 285 return;
michael@0 286
michael@0 287 if (maybeData.IsNull()) {
michael@0 288 // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
michael@0 289 return;
michael@0 290 }
michael@0 291
michael@0 292 WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
michael@0 293
michael@0 294 if (!bufferSlot) {
michael@0 295 return;
michael@0 296 }
michael@0 297
michael@0 298 if (byteOffset < 0)
michael@0 299 return ErrorInvalidValue("bufferSubData: negative offset");
michael@0 300
michael@0 301 WebGLBuffer* boundBuffer = bufferSlot->get();
michael@0 302
michael@0 303 if (!boundBuffer)
michael@0 304 return ErrorInvalidOperation("bufferData: no buffer bound!");
michael@0 305
michael@0 306 const ArrayBuffer& data = maybeData.Value();
michael@0 307 data.ComputeLengthAndData();
michael@0 308
michael@0 309 CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
michael@0 310 if (!checked_neededByteLength.isValid())
michael@0 311 return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
michael@0 312
michael@0 313 if (checked_neededByteLength.value() > boundBuffer->ByteLength())
michael@0 314 return ErrorInvalidValue("bufferSubData: not enough data - operation requires %d bytes, but buffer only has %d bytes",
michael@0 315 checked_neededByteLength.value(), boundBuffer->ByteLength());
michael@0 316
michael@0 317 MakeContextCurrent();
michael@0 318
michael@0 319 boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.Data(), data.Length());
michael@0 320
michael@0 321 gl->fBufferSubData(target, byteOffset, data.Length(), data.Data());
michael@0 322 }
michael@0 323
michael@0 324 void
michael@0 325 WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
michael@0 326 const ArrayBufferView& data)
michael@0 327 {
michael@0 328 if (IsContextLost())
michael@0 329 return;
michael@0 330
michael@0 331 WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
michael@0 332
michael@0 333 if (!bufferSlot) {
michael@0 334 return;
michael@0 335 }
michael@0 336
michael@0 337 if (byteOffset < 0)
michael@0 338 return ErrorInvalidValue("bufferSubData: negative offset");
michael@0 339
michael@0 340 WebGLBuffer* boundBuffer = bufferSlot->get();
michael@0 341
michael@0 342 if (!boundBuffer)
michael@0 343 return ErrorInvalidOperation("bufferSubData: no buffer bound!");
michael@0 344
michael@0 345 data.ComputeLengthAndData();
michael@0 346
michael@0 347 CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
michael@0 348 if (!checked_neededByteLength.isValid())
michael@0 349 return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
michael@0 350
michael@0 351 if (checked_neededByteLength.value() > boundBuffer->ByteLength())
michael@0 352 return ErrorInvalidValue("bufferSubData: not enough data -- operation requires %d bytes, but buffer only has %d bytes",
michael@0 353 checked_neededByteLength.value(), boundBuffer->ByteLength());
michael@0 354
michael@0 355 boundBuffer->ElementArrayCacheBufferSubData(byteOffset, data.Data(), data.Length());
michael@0 356
michael@0 357 MakeContextCurrent();
michael@0 358 gl->fBufferSubData(target, byteOffset, data.Length(), data.Data());
michael@0 359 }
michael@0 360
michael@0 361 already_AddRefed<WebGLBuffer>
michael@0 362 WebGLContext::CreateBuffer()
michael@0 363 {
michael@0 364 if (IsContextLost())
michael@0 365 return nullptr;
michael@0 366
michael@0 367 nsRefPtr<WebGLBuffer> globj = new WebGLBuffer(this);
michael@0 368 return globj.forget();
michael@0 369 }
michael@0 370
michael@0 371 void
michael@0 372 WebGLContext::DeleteBuffer(WebGLBuffer *buffer)
michael@0 373 {
michael@0 374 if (IsContextLost())
michael@0 375 return;
michael@0 376
michael@0 377 if (!ValidateObjectAllowDeletedOrNull("deleteBuffer", buffer))
michael@0 378 return;
michael@0 379
michael@0 380 if (!buffer || buffer->IsDeleted())
michael@0 381 return;
michael@0 382
michael@0 383 if (mBoundArrayBuffer == buffer) {
michael@0 384 BindBuffer(LOCAL_GL_ARRAY_BUFFER,
michael@0 385 static_cast<WebGLBuffer*>(nullptr));
michael@0 386 }
michael@0 387
michael@0 388 if (mBoundVertexArray->mBoundElementArrayBuffer == buffer) {
michael@0 389 BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER,
michael@0 390 static_cast<WebGLBuffer*>(nullptr));
michael@0 391 }
michael@0 392
michael@0 393 for (int32_t i = 0; i < mGLMaxVertexAttribs; i++) {
michael@0 394 if (mBoundVertexArray->HasAttrib(i) && mBoundVertexArray->mAttribs[i].buf == buffer)
michael@0 395 mBoundVertexArray->mAttribs[i].buf = nullptr;
michael@0 396 }
michael@0 397
michael@0 398 buffer->RequestDelete();
michael@0 399 }
michael@0 400
michael@0 401 bool
michael@0 402 WebGLContext::IsBuffer(WebGLBuffer *buffer)
michael@0 403 {
michael@0 404 if (IsContextLost())
michael@0 405 return false;
michael@0 406
michael@0 407 return ValidateObjectAllowDeleted("isBuffer", buffer) &&
michael@0 408 !buffer->IsDeleted() &&
michael@0 409 buffer->HasEverBeenBound();
michael@0 410 }
michael@0 411
michael@0 412 bool
michael@0 413 WebGLContext::ValidateBufferUsageEnum(GLenum target, const char *infos)
michael@0 414 {
michael@0 415 switch (target) {
michael@0 416 case LOCAL_GL_STREAM_DRAW:
michael@0 417 case LOCAL_GL_STATIC_DRAW:
michael@0 418 case LOCAL_GL_DYNAMIC_DRAW:
michael@0 419 return true;
michael@0 420 default:
michael@0 421 break;
michael@0 422 }
michael@0 423
michael@0 424 ErrorInvalidEnumInfo(infos, target);
michael@0 425 return false;
michael@0 426 }
michael@0 427
michael@0 428 WebGLRefPtr<WebGLBuffer>*
michael@0 429 WebGLContext::GetBufferSlotByTarget(GLenum target, const char* infos)
michael@0 430 {
michael@0 431 switch (target) {
michael@0 432 case LOCAL_GL_ARRAY_BUFFER:
michael@0 433 return &mBoundArrayBuffer;
michael@0 434
michael@0 435 case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
michael@0 436 return &mBoundVertexArray->mBoundElementArrayBuffer;
michael@0 437
michael@0 438 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
michael@0 439 if (!IsWebGL2()) {
michael@0 440 break;
michael@0 441 }
michael@0 442 return &mBoundTransformFeedbackBuffer;
michael@0 443
michael@0 444 default:
michael@0 445 break;
michael@0 446 }
michael@0 447
michael@0 448 ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
michael@0 449 return nullptr;
michael@0 450 }
michael@0 451
michael@0 452 WebGLRefPtr<WebGLBuffer>*
michael@0 453 WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index, const char* infos)
michael@0 454 {
michael@0 455 switch (target) {
michael@0 456 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
michael@0 457 if (index >= mGLMaxTransformFeedbackSeparateAttribs) {
michael@0 458 ErrorInvalidValue("%s: index should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", infos, index);
michael@0 459 return nullptr;
michael@0 460 }
michael@0 461 return nullptr; // See bug 903594
michael@0 462
michael@0 463 default:
michael@0 464 break;
michael@0 465 }
michael@0 466
michael@0 467 ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
michael@0 468 return nullptr;
michael@0 469 }
michael@0 470
michael@0 471 GLenum
michael@0 472 WebGLContext::CheckedBufferData(GLenum target,
michael@0 473 GLsizeiptr size,
michael@0 474 const GLvoid *data,
michael@0 475 GLenum usage)
michael@0 476 {
michael@0 477 #ifdef XP_MACOSX
michael@0 478 // bug 790879
michael@0 479 if (gl->WorkAroundDriverBugs() &&
michael@0 480 int64_t(size) > INT32_MAX) // the cast avoids a potential always-true warning on 32bit
michael@0 481 {
michael@0 482 GenerateWarning("Rejecting valid bufferData call with size %lu to avoid a Mac bug", size);
michael@0 483 return LOCAL_GL_INVALID_VALUE;
michael@0 484 }
michael@0 485 #endif
michael@0 486 WebGLBuffer *boundBuffer = nullptr;
michael@0 487 if (target == LOCAL_GL_ARRAY_BUFFER) {
michael@0 488 boundBuffer = mBoundArrayBuffer;
michael@0 489 } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
michael@0 490 boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
michael@0 491 }
michael@0 492 MOZ_ASSERT(boundBuffer != nullptr, "no buffer bound for this target");
michael@0 493
michael@0 494 bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
michael@0 495 if (sizeChanges) {
michael@0 496 GetAndFlushUnderlyingGLErrors();
michael@0 497 gl->fBufferData(target, size, data, usage);
michael@0 498 GLenum error = GetAndFlushUnderlyingGLErrors();
michael@0 499 return error;
michael@0 500 } else {
michael@0 501 gl->fBufferData(target, size, data, usage);
michael@0 502 return LOCAL_GL_NO_ERROR;
michael@0 503 }
michael@0 504 }

mercurial