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.)

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

mercurial