Bug 1305540 - Lazily bind PBO targets. - r=ethlin, a=gchang
authorJeff Gilbert (:jgilbert) <jgilbert@mozilla.com>
Mon, 26 Sep 2016 13:38:56 -0700
changeset 439962 59c498f1a9888ea94fc271ea3da339555028f976
parent 439961 03c71ac83a13e9618b48de8c0f6194df48124b2d
child 439963 c15eb2d2c15d7205835526ef4e71604e3a9be180
push id36143
push userjkingston@mozilla.com
push dateWed, 16 Nov 2016 22:20:38 +0000
reviewersethlin, gchang
bugs1305540
milestone51.0a2
Bug 1305540 - Lazily bind PBO targets. - r=ethlin, a=gchang MozReview-Commit-ID: B9WiCNfNsfY
dom/canvas/TexUnpackBlob.cpp
dom/canvas/WebGL2ContextBuffers.cpp
dom/canvas/WebGLBuffer.cpp
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextBuffers.cpp
dom/canvas/WebGLContextGL.cpp
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -390,25 +390,26 @@ TexUnpackBytes::TexOrSubImage(bool isSub
     }
 
     //////
 
     MOZ_ASSERT(webgl->mBoundPixelUnpackBuffer);
 
     if (!isSubImage) {
         // Alloc first to catch OOMs.
-        gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
+        AssertUintParamCorrect(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
         *out_error = DoTexOrSubImage(false, gl, target, level, dui, xOffset, yOffset,
                                      zOffset, mWidth, mHeight, mDepth, nullptr);
-        gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER,
-                        webgl->mBoundPixelUnpackBuffer->mGLName);
         if (*out_error)
             return false;
     }
 
+    const ScopedLazyBind bindPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER,
+                                 webgl->mBoundPixelUnpackBuffer);
+
     //////
 
     // Make our sometimes-implicit values explicit. Also this keeps them constant when we
     // ask for height=mHeight-1 and such.
     gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, mRowLength);
     gl->fPixelStorei(LOCAL_GL_UNPACK_IMAGE_HEIGHT, mImageHeight);
 
     if (mDepth > 1) {
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -80,16 +80,18 @@ WebGL2Context::CopyBufferSubData(GLenum 
                               (readType == WebGLBuffer::Kind::OtherData) ? "other"
                                                                          : "element",
                               (writeType == WebGLBuffer::Kind::OtherData) ? "other"
                                                                           : "element");
         return;
     }
 
     gl->MakeCurrent();
+    const ScopedLazyBind readBind(gl, readTarget, readBuffer);
+    const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
     gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
 }
 
 void
 WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
                                 const dom::ArrayBufferView& data)
 {
     const char funcName[] = "getBufferSubData";
@@ -138,16 +140,17 @@ WebGL2Context::GetBufferSubData(GLenum t
         ErrorInvalidOperation("%s: Currently bound transform feedback is active.",
                               funcName);
         return;
     }
 
     ////
 
     gl->MakeCurrent();
+    const ScopedLazyBind readBind(gl, target, buffer);
 
     const auto ptr = gl->fMapBufferRange(target, offset, data.LengthAllowShared(),
                                          LOCAL_GL_MAP_READ_BIT);
     // Warning: Possibly shared memory.  See bug 1225033.
     memcpy(data.DataAllowShared(), ptr, data.LengthAllowShared());
     gl->fUnmapBuffer(target);
 }
 
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -109,16 +109,17 @@ WebGLBuffer::BufferData(GLenum target, s
         mContext->ErrorInvalidOperation("%s: Buffer is bound to an active transform"
                                         " feedback object.",
                                         funcName);
         return;
     }
 
     const auto& gl = mContext->gl;
     gl->MakeCurrent();
+    const ScopedLazyBind lazyBind(gl, target, this);
     mContext->InvalidateBufferFetching();
 
 #ifdef XP_MACOSX
     // bug 790879
     if (gl->WorkAroundDriverBugs() &&
         size > INT32_MAX)
     {
         mContext->ErrorOutOfMemory("%s: Allocation size too large.", funcName);
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -2157,16 +2157,49 @@ ScopedFBRebinder::UnwrapImpl()
         mGL->fBindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
         mGL->fBindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, fnName(mWebGL->mBoundReadFramebuffer));
     } else {
         MOZ_ASSERT(mWebGL->mBoundDrawFramebuffer == mWebGL->mBoundReadFramebuffer);
         mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fnName(mWebGL->mBoundDrawFramebuffer));
     }
 }
 
+////////////////////
+
+static GLenum
+TargetIfLazy(GLenum target)
+{
+    switch (target) {
+    case LOCAL_GL_PIXEL_PACK_BUFFER:
+    case LOCAL_GL_PIXEL_UNPACK_BUFFER:
+        return target;
+
+    default:
+        return 0;
+    }
+}
+
+ScopedLazyBind::ScopedLazyBind(gl::GLContext* gl, GLenum target, const WebGLBuffer* buf)
+    : ScopedGLWrapper<ScopedLazyBind>(gl)
+    , mTarget(buf ? TargetIfLazy(target) : 0)
+    , mBuf(buf)
+{
+    if (mTarget) {
+        mGL->fBindBuffer(mTarget, mBuf->mGLName);
+    }
+}
+
+void
+ScopedLazyBind::UnwrapImpl()
+{
+    if (mTarget) {
+        mGL->fBindBuffer(mTarget, 0);
+    }
+}
+
 ////////////////////////////////////////
 
 void
 Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
           uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
           uint32_t* const out_intSize)
 {
     // Only >0 if dstStartInSrc is >0:
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1831,16 +1831,31 @@ public:
         : ScopedGLWrapper<ScopedFBRebinder>(webgl->gl)
         , mWebGL(webgl)
     { }
 
 private:
     void UnwrapImpl();
 };
 
+class ScopedLazyBind final
+    : public gl::ScopedGLWrapper<ScopedLazyBind>
+{
+    friend struct gl::ScopedGLWrapper<ScopedLazyBind>;
+
+    const GLenum mTarget;
+    const WebGLBuffer* const mBuf;
+
+public:
+    ScopedLazyBind(gl::GLContext* gl, GLenum target, const WebGLBuffer* buf);
+
+private:
+    void UnwrapImpl();
+};
+
 void
 ComputeLengthAndData(const dom::ArrayBufferViewOrSharedArrayBufferView& view,
                      void** const out_data, size_t* const out_length,
                      js::Scalar::Type* const out_type);
 
 void
 Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
           uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -132,16 +132,23 @@ WebGLContext::BindBuffer(GLenum target, 
 
     gl->MakeCurrent();
     gl->fBindBuffer(target, buffer ? buffer->mGLName : 0);
 
     *slot = buffer;
     if (buffer) {
         buffer->SetContentAfterBind(target);
     }
+
+    switch (target) {
+    case LOCAL_GL_PIXEL_PACK_BUFFER:
+    case LOCAL_GL_PIXEL_UNPACK_BUFFER:
+        gl->fBindBuffer(target, 0);
+        break;
+    }
 }
 
 ////////////////////////////////////////
 
 bool
 WebGLContext::ValidateIndexedBufferBinding(const char* funcName, GLenum target,
                                            GLuint index,
                                            WebGLRefPtr<WebGLBuffer>** const out_genericBinding,
@@ -424,16 +431,18 @@ WebGLContext::BufferSubDataT(GLenum targ
         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());
 
     // Warning: Possibly shared memory.  See bug 1225033.
     buffer->ElementArrayCacheBufferSubData(byteOffset, data.DataAllowShared(),
                                            data.LengthAllowShared());
 }
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1523,16 +1523,19 @@ WebGL2Context::ReadPixels(GLint x, GLint
     const auto bytesAvailable = mBoundPixelPackBuffer->ByteLength();
     const auto checkedBytesAfterOffset = CheckedUint32(bytesAvailable) - offset;
 
     uint32_t bytesAfterOffset = 0;
     if (checkedBytesAfterOffset.isValid()) {
         bytesAfterOffset = checkedBytesAfterOffset.value();
     }
 
+    gl->MakeCurrent();
+    const ScopedLazyBind lazyBind(gl, LOCAL_GL_PIXEL_PACK_BUFFER, mBoundPixelPackBuffer);
+
     ReadPixelsImpl(x, y, width, height, format, type, (void*)offset, bytesAfterOffset);
 }
 
 static bool
 ValidateReadPixelsFormatAndType(const webgl::FormatInfo* srcFormat,
                                 const webgl::PackingInfo& pi, gl::GLContext* gl,
                                 WebGLContext* webgl)
 {