Bug 1313541 - Buffer[Sub]Data impl. - r=ethlin, a=gchang
authorJeff Gilbert (:jgilbert) <jgilbert@mozilla.com>
Tue, 11 Oct 2016 15:40:34 -0700
changeset 356578 9ee2e73a7312b52ff928569441d1b67d6d12bff0
parent 356577 4031945696c24b704d132cddf96990ccd1eb8b15
child 356579 f83d9fa111a18732b271b772575bc810b7d5d751
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersethlin, gchang
bugs1313541
milestone51.0a2
Bug 1313541 - Buffer[Sub]Data impl. - r=ethlin, a=gchang MozReview-Commit-ID: 4cmfDQuegxm
dom/canvas/WebGLBuffer.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextBuffers.cpp
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -98,16 +98,21 @@ ValidateBufferUsageEnum(WebGLContext* we
     return false;
 }
 
 void
 WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usage)
 {
     const char funcName[] = "bufferData";
 
+    // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
+    // is like intptr_t.
+    if (!CheckedInt<GLsizeiptr>(size).isValid())
+        return ErrorOutOfMemory("%s: bad size", funcName);
+
     if (!ValidateBufferUsageEnum(mContext, funcName, usage))
         return;
 
     if (mNumActiveTFOs) {
         mContext->ErrorInvalidOperation("%s: Buffer is bound to an active transform"
                                         " feedback object.",
                                         funcName);
         return;
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -749,40 +749,39 @@ public:
 // -----------------------------------------------------------------------------
 // Buffer Objects (WebGLContextBuffers.cpp)
     void BindBuffer(GLenum target, WebGLBuffer* buffer);
     void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buf);
     void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buf,
                          WebGLintptr offset, WebGLsizeiptr size);
 
 private:
-    template<typename BufferT>
-    void BufferDataT(GLenum target, const BufferT& data, GLenum usage);
+    void BufferDataImpl(GLenum target, size_t dataLen, const uint8_t* data, GLenum usage);
 
 public:
     void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage);
-    void BufferData(GLenum target, const dom::ArrayBufferView& data,
-                    GLenum usage);
+    void BufferData(GLenum target, const dom::ArrayBufferView& srcData, GLenum usage,
+                    GLuint srcElemOffset = 0, GLuint srcElemCountOverride = 0);
     void BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeData,
                     GLenum usage);
-    void BufferData(GLenum target, const dom::SharedArrayBuffer& data,
-                    GLenum usage);
+    void BufferData(GLenum target, const dom::SharedArrayBuffer& data, GLenum usage);
 
 private:
-    template<typename BufferT>
-    void BufferSubDataT(GLenum target, WebGLsizeiptr byteOffset,
-                        const BufferT& data);
+    void BufferSubDataImpl(GLenum target, WebGLsizeiptr dstByteOffset,
+                           size_t srcDataLen, const uint8_t* srcData);
 
 public:
-    void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
-                       const dom::ArrayBufferView& data);
-    void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
-                       const dom::Nullable<dom::ArrayBuffer>& maybeData);
-    void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
-                       const dom::SharedArrayBuffer& data);
+    void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
+                       const dom::ArrayBufferView& src, GLuint srcElemOffset = 0,
+                       GLuint srcElemCountOverride = 0);
+    void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
+                       const dom::Nullable<dom::ArrayBuffer>& maybeSrc);
+    void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
+                       const dom::SharedArrayBuffer& src);
+
     already_AddRefed<WebGLBuffer> CreateBuffer();
     void DeleteBuffer(WebGLBuffer* buf);
     bool IsBuffer(WebGLBuffer* buf);
 
 protected:
     // bound buffer state
     WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
     WebGLRefPtr<WebGLBuffer> mBoundCopyReadBuffer;
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -299,182 +299,182 @@ WebGLContext::BindBufferRange(GLenum tar
     if (buffer) {
         buffer->SetContentAfterBind(target);
     }
 }
 
 ////////////////////////////////////////
 
 void
+WebGLContext::BufferDataImpl(GLenum target, size_t dataLen, const uint8_t* data,
+                             GLenum usage)
+{
+    const char funcName[] = "bufferData";
+
+    const auto& buffer = ValidateBufferSelection(funcName, target);
+    if (!buffer)
+        return;
+
+    buffer->BufferData(target, dataLen, data, usage);
+}
+
+////
+
+void
 WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
 {
     const char funcName[] = "bufferData";
     if (IsContextLost())
         return;
 
     if (!ValidateNonNegative(funcName, "size", size))
         return;
 
-    // careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t.
-    if (!CheckedInt<GLsizeiptr>(size).isValid())
-        return ErrorOutOfMemory("%s: bad size", funcName);
-
-    const auto& buffer = ValidateBufferSelection(funcName, target);
-    if (!buffer)
-        return;
-
     ////
 
-    UniquePtr<uint8_t> zeroBuffer((uint8_t*)calloc(size, 1));
+    const UniqueBuffer zeroBuffer(calloc(size, 1));
     if (!zeroBuffer)
         return ErrorOutOfMemory("%s: Failed to allocate zeros.", funcName);
 
-    buffer->BufferData(target, size_t(size), zeroBuffer.get(), usage);
+    BufferDataImpl(target, size_t(size), zeroBuffer.get(), usage);
+}
+
+void
+WebGLContext::BufferData(GLenum target, const dom::SharedArrayBuffer& src, GLenum usage)
+{
+    if (IsContextLost())
+        return;
+
+    src.ComputeLengthAndData();
+    BufferDataImpl(target, src.LengthAllowShared(), src.DataAllowShared(), usage);
 }
 
-// BufferT may be one of
-// const dom::ArrayBuffer&
-// const dom::SharedArrayBuffer&
-// const dom::ArrayBufferView&
-template<typename BufferT>
 void
-WebGLContext::BufferDataT(GLenum target,
-                          const BufferT& data,
-                          GLenum usage)
+WebGLContext::BufferData(GLenum target, const dom::Nullable<dom::ArrayBuffer>& maybeSrc,
+                         GLenum usage)
+{
+    if (IsContextLost())
+        return;
+
+    if (maybeSrc.IsNull())
+        return ErrorInvalidValue("bufferData: null object passed");
+    auto& src = maybeSrc.Value();
+
+    src.ComputeLengthAndData();
+    BufferDataImpl(target, src.LengthAllowShared(), src.DataAllowShared(), usage);
+}
+
+void
+WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& src, GLenum usage,
+                         GLuint srcElemOffset, GLuint srcElemCountOverride)
 {
     const char funcName[] = "bufferData";
     if (IsContextLost())
         return;
 
-    data.ComputeLengthAndData();
-
-    // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
-    // is like intptr_t.
-    if (!CheckedInt<GLsizeiptr>(data.LengthAllowShared()).isValid())
-        return ErrorOutOfMemory("bufferData: bad size");
-
-    const auto& buffer = ValidateBufferSelection(funcName, target);
-    if (!buffer)
+    uint8_t* bytes;
+    size_t byteLen;
+    if (!ValidateArrayBufferView(funcName, src, srcElemOffset, srcElemCountOverride,
+                                 &bytes, &byteLen))
+    {
         return;
-
-    // Warning: Possibly shared memory.  See bug 1225033.
-    buffer->BufferData(target, data.LengthAllowShared(), data.DataAllowShared(), usage);
-}
+    }
 
-void
-WebGLContext::BufferData(GLenum target,
-                         const dom::SharedArrayBuffer& data,
-                         GLenum usage)
-{
-    BufferDataT(target, data, usage);
-}
-
-void
-WebGLContext::BufferData(GLenum target,
-                         const dom::Nullable<dom::ArrayBuffer>& maybeData,
-                         GLenum usage)
-{
-    if (maybeData.IsNull()) {
-        // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
-        return ErrorInvalidValue("bufferData: null object passed");
-    }
-    BufferDataT(target, maybeData.Value(), usage);
-}
-
-void
-WebGLContext::BufferData(GLenum target, const dom::ArrayBufferView& data,
-                         GLenum usage)
-{
-    BufferDataT(target, data, usage);
+    BufferDataImpl(target, byteLen, bytes, usage);
 }
 
 ////////////////////////////////////////
 
-// BufferT may be one of
-// const dom::ArrayBuffer&
-// const dom::SharedArrayBuffer&
-// const dom::ArrayBufferView&
-template<typename BufferT>
 void
-WebGLContext::BufferSubDataT(GLenum target,
-                             WebGLsizeiptr byteOffset,
-                             const BufferT& data)
+WebGLContext::BufferSubDataImpl(GLenum target, WebGLsizeiptr dstByteOffset,
+                                size_t dataLen, const uint8_t* data)
 {
     const char funcName[] = "bufferSubData";
-    if (IsContextLost())
-        return;
 
-    if (!ValidateNonNegative(funcName, "byteOffset", byteOffset))
+    if (!ValidateNonNegative(funcName, "byteOffset", dstByteOffset))
         return;
 
     const auto& buffer = ValidateBufferSelection(funcName, target);
     if (!buffer)
         return;
 
     if (buffer->mNumActiveTFOs) {
         ErrorInvalidOperation("%s: Buffer is bound to an active transform feedback"
                               " object.",
                               "bufferSubData");
         return;
     }
 
-    data.ComputeLengthAndData();
+    if (!buffer->ValidateRange(funcName, dstByteOffset, dataLen))
+        return;
 
-    const auto checked_neededByteLength =
-        CheckedInt<size_t>(byteOffset) + data.LengthAllowShared();
-
-    if (!checked_neededByteLength.isValid()) {
-        ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
-                          " byte length.");
+    if (!CheckedInt<GLintptr>(dataLen).isValid()) {
+        ErrorOutOfMemory("%s: Size too large.", funcName);
         return;
     }
+    const GLintptr glDataLen(dataLen);
 
-    if (checked_neededByteLength.value() > buffer->ByteLength()) {
-        ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
-                          " %d bytes, but buffer only has %d bytes.",
-                          checked_neededByteLength.value(),
-                          buffer->ByteLength());
-        return;
-    }
+    ////
 
     MakeContextCurrent();
     const ScopedLazyBind lazyBind(gl, target, buffer);
 
     // Warning: Possibly shared memory.  See bug 1225033.
-    gl->fBufferSubData(target, byteOffset, data.LengthAllowShared(),
-                       data.DataAllowShared());
+    gl->fBufferSubData(target, dstByteOffset, glDataLen, data);
 
     // Warning: Possibly shared memory.  See bug 1225033.
-    buffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
-                                           data.LengthAllowShared());
+    buffer->ElementArrayCacheBufferSubData(dstByteOffset, data, size_t(glDataLen));
+}
+
+void
+WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
+                            const dom::Nullable<dom::ArrayBuffer>& maybeSrc)
+{
+    if (IsContextLost())
+        return;
+
+    if (maybeSrc.IsNull())
+        return ErrorInvalidValue("BufferSubData: returnedData is null.");
+    auto& src = maybeSrc.Value();
+
+    src.ComputeLengthAndData();
+    BufferSubDataImpl(target, dstByteOffset, src.LengthAllowShared(),
+                      src.DataAllowShared());
 }
 
 void
-WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
-                            const dom::Nullable<dom::ArrayBuffer>& maybeData)
+WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
+                            const dom::SharedArrayBuffer& src)
 {
-    if (maybeData.IsNull()) {
-        ErrorInvalidValue("BufferSubData: returnedData is null.");
+    if (IsContextLost())
         return;
-    }
-    BufferSubDataT(target, byteOffset, maybeData.Value());
+
+    src.ComputeLengthAndData();
+    BufferSubDataImpl(target, dstByteOffset, src.LengthAllowShared(),
+                      src.DataAllowShared());
 }
 
 void
-WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
-                            const dom::SharedArrayBuffer& data)
+WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
+                            const dom::ArrayBufferView& src, GLuint srcElemOffset,
+                            GLuint srcElemCountOverride)
 {
-    BufferSubDataT(target, byteOffset, data);
-}
+    const char funcName[] = "bufferSubData";
+    if (IsContextLost())
+        return;
 
-void
-WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
-                            const dom::ArrayBufferView& data)
-{
-    BufferSubDataT(target, byteOffset, data);
+    uint8_t* bytes;
+    size_t byteLen;
+    if (!ValidateArrayBufferView(funcName, src, srcElemOffset, srcElemCountOverride,
+                                 &bytes, &byteLen))
+    {
+        return;
+    }
+
+    BufferSubDataImpl(target, dstByteOffset, byteLen, bytes);
 }
 
 ////////////////////////////////////////
 
 already_AddRefed<WebGLBuffer>
 WebGLContext::CreateBuffer()
 {
     if (IsContextLost())