Bug 1325835 - Support dx_interop on Intel. - r=jrmuizel
authorJeff Gilbert <jgilbert@mozilla.com>
Thu, 29 Dec 2016 15:17:23 -0800
changeset 331950 661cad778f950879e02c62fcd7dc06381243b7ff
parent 331949 097237b12c7af50158d853ff1abdb2e2590aed10
child 331951 2286081f1ce3fa6d38d8d14cc2ecee918b6ab252
push id36738
push usercbook@mozilla.com
push dateWed, 01 Feb 2017 12:27:08 +0000
treeherderautoland@e9f38cda7664 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1325835
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1325835 - Support dx_interop on Intel. - r=jrmuizel MozReview-Commit-ID: 7CFfmDYhYaR
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLContext.h
gfx/gl/ScopedGLHelpers.cpp
gfx/gl/ScopedGLHelpers.h
gfx/gl/SharedSurfaceD3D11Interop.cpp
gfx/gl/SharedSurfaceD3D11Interop.h
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -950,16 +950,17 @@ GLBlitHelper::DrawBlitTextureToFramebuff
         type = BlitTexRect;
         break;
     default:
         MOZ_CRASH("GFX: Fatal Error: Bad `srcTarget`.");
         break;
     }
 
     ScopedGLDrawState autoStates(mGL);
+    const ScopedBindFramebuffer bindFB(mGL);
     if (internalFBs) {
         mGL->Screen()->BindFB_Internal(destFB);
     } else {
         mGL->BindFB(destFB);
     }
 
     // Does destructive things to (only!) what we just saved above.
     bool good = UseTexQuadProgram(type, srcSize);
@@ -968,16 +969,17 @@ GLBlitHelper::DrawBlitTextureToFramebuff
         MOZ_DIAGNOSTIC_ASSERT(false,
                               "Error: Failed to prepare to blit texture->framebuffer.\n");
         mGL->fScissor(0, 0, destSize.width, destSize.height);
         mGL->fColorMask(1, 1, 1, 1);
         mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
         return;
     }
 
+    const ScopedBindTexture bindTex(mGL, srcTex, srcTarget);
     mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
 }
 
 void
 GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
                                        const gfx::IntSize& srcSize,
                                        const gfx::IntSize& destSize,
                                        GLenum destTarget,
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -326,16 +326,20 @@ public:
     GLRenderer Renderer() const {
         return mRenderer;
     }
 
     bool IsContextLost() const {
         return mContextLost;
     }
 
+    bool HasPBOState() const {
+        return (!IsGLES() || Version() >= 300);
+    }
+
     /**
      * If this context is double-buffered, returns TRUE.
      */
     virtual bool IsDoubleBuffered() const {
         return false;
     }
 
     virtual GLContextType GetContextType() const = 0;
@@ -3665,16 +3669,25 @@ public:
 protected:
     bool mHeavyGLCallsSinceLastFlush;
 
 public:
     void FlushIfHeavyGLCallsSinceLastFlush();
     static bool ShouldSpew();
     static bool ShouldDumpExts();
     void Readback(SharedSurface* src, gfx::DataSourceSurface* dest);
+
+    ////
+
+    void TexParams_SetClampNoMips(GLenum target = LOCAL_GL_TEXTURE_2D) {
+        fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+        fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+        fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
+        fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
+    }
 };
 
 bool DoesStringMatch(const char* aString, const char* aWantedString);
 
 void SplitByChar(const nsACString& str, const char delim,
                  std::vector<nsCString>* const out);
 
 template<size_t N>
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -490,30 +490,24 @@ ScopedGLDrawState::~ScopedGLDrawState()
     mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer);
 
     mGL->fUseProgram(boundProgram);
 }
 
 ////////////////////////////////////////////////////////////////////////
 // ScopedPackState
 
-static bool
-HasPBOState(const GLContext* gl)
-{
-    return (!gl->IsGLES() || gl->Version() >= 300);
-}
-
 ScopedPackState::ScopedPackState(GLContext* gl)
     : ScopedGLWrapper<ScopedPackState>(gl)
 {
     mGL->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, &mAlignment);
 
     if (mAlignment != 4) mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
 
-    if (!HasPBOState(mGL))
+    if (!mGL->HasPBOState())
         return;
 
     mGL->fGetIntegerv(LOCAL_GL_PIXEL_PACK_BUFFER_BINDING, (GLint*)&mPixelBuffer);
     mGL->fGetIntegerv(LOCAL_GL_PACK_ROW_LENGTH, &mRowLength);
     mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_PIXELS, &mSkipPixels);
     mGL->fGetIntegerv(LOCAL_GL_PACK_SKIP_ROWS, &mSkipRows);
 
     if (mPixelBuffer != 0) mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, 0);
@@ -522,19 +516,61 @@ ScopedPackState::ScopedPackState(GLConte
     if (mSkipRows != 0)    mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
 }
 
 void
 ScopedPackState::UnwrapImpl()
 {
     mGL->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mAlignment);
 
-    if (!HasPBOState(mGL))
+    if (!mGL->HasPBOState())
         return;
 
     mGL->fBindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, mPixelBuffer);
     mGL->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mRowLength);
     mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mSkipPixels);
     mGL->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mSkipRows);
 }
 
+////////////////////////////////////////////////////////////////////////
+// ScopedBindPBO
+
+static GLuint
+GetPBOBinding(GLContext* gl, GLenum target)
+{
+    if (!gl->HasPBOState())
+        return 0;
+
+    GLenum targetBinding;
+    switch (target) {
+    case LOCAL_GL_PIXEL_PACK_BUFFER:
+        targetBinding = LOCAL_GL_PIXEL_PACK_BUFFER_BINDING;
+        break;
+
+    case LOCAL_GL_PIXEL_UNPACK_BUFFER:
+        targetBinding = LOCAL_GL_PIXEL_UNPACK_BUFFER_BINDING;
+        break;
+
+    default:
+        MOZ_CRASH();
+    }
+
+    return gl->GetIntAs<GLuint>(targetBinding);
+
+}
+
+ScopedBindPBO::ScopedBindPBO(GLContext* gl, GLenum target)
+    : ScopedGLWrapper<ScopedPackState>(gl)
+    , mTarget(target)
+    , mPBO(GetPBOBinding(mGL, mTarget))
+{ }
+
+void
+ScopedBindPBO::UnwrapImpl()
+{
+    if (!mGL->HasPBOState())
+        return;
+
+    mGL->fBindBuffer(mTarget, mPBO);
+}
+
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/ScopedGLHelpers.h
+++ b/gfx/gl/ScopedGLHelpers.h
@@ -357,12 +357,28 @@ protected:
 
 public:
     explicit ScopedPackState(GLContext* gl);
 
 protected:
     void UnwrapImpl();
 };
 
+struct ScopedBindPBO final
+    : public ScopedGLWrapper<ScopedPackState>
+{
+    friend struct ScopedGLWrapper<ScopedPackState>;
+
+protected:
+    const GLenum mTarget;
+    const GLuint mPBO;
+
+public:
+    ScopedBindPBO(GLContext* gl, GLenum target);
+
+protected:
+    void UnwrapImpl();
+};
+
 } /* namespace gl */
 } /* namespace mozilla */
 
 #endif /* SCOPEDGLHELPERS_H_ */
--- a/gfx/gl/SharedSurfaceD3D11Interop.cpp
+++ b/gfx/gl/SharedSurfaceD3D11Interop.cpp
@@ -290,68 +290,113 @@ SharedSurface_D3D11Interop::Create(DXInt
 
     ////
 
     if (!gl->MakeCurrent()) {
         NS_WARNING("MakeCurrent failed.");
         return nullptr;
     }
 
-    GLuint rbGL = 0;
-    gl->fGenRenderbuffers(1, &rbGL);
-    const auto lockHandle = interop->RegisterObject(texD3D, rbGL, LOCAL_GL_RENDERBUFFER,
+    GLuint interopRB = 0;
+    gl->fGenRenderbuffers(1, &interopRB);
+    const auto lockHandle = interop->RegisterObject(texD3D, interopRB,
+                                                    LOCAL_GL_RENDERBUFFER,
                                                     LOCAL_WGL_ACCESS_WRITE_DISCARD_NV);
     if (!lockHandle) {
         NS_WARNING("Failed to register D3D object with WGL.");
-        gl->fDeleteRenderbuffers(1, &rbGL);
+        gl->fDeleteRenderbuffers(1, &interopRB);
         return nullptr;
     }
 
     ////
 
+    GLuint prodTex = 0;
+    GLuint interopFB = 0;
+    {
+        GLint samples = 0;
+        {
+            const ScopedBindRenderbuffer bindRB(gl, interopRB);
+            gl->fGetRenderbufferParameteriv(LOCAL_GL_RENDERBUFFER,
+                                            LOCAL_GL_RENDERBUFFER_SAMPLES, &samples);
+        }
+        if (samples > 0) { // Intel
+            // Intel's dx_interop GL-side textures have SAMPLES=1, likely because that's
+            // what the D3DTextures technically have. However, SAMPLES=1 is very different
+            // from SAMPLES=0 in GL.
+            // For more, see https://bugzilla.mozilla.org/show_bug.cgi?id=1325835
+
+            // Our ShSurf tex or rb must be single-sampled.
+            gl->fGenTextures(1, &prodTex);
+            const ScopedBindTexture bindTex(gl, prodTex);
+            gl->TexParams_SetClampNoMips();
+
+            const GLenum format = (hasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB);
+            const ScopedBindPBO nullPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER);
+            gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, format, size.width, size.height, 0,
+                            format, LOCAL_GL_UNSIGNED_BYTE, nullptr);
+
+            gl->fGenFramebuffers(1, &interopFB);
+            ScopedBindFramebuffer bindFB(gl, interopFB);
+            gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
+                                         LOCAL_GL_RENDERBUFFER, interopRB);
+            MOZ_ASSERT(gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) ==
+                       LOCAL_GL_FRAMEBUFFER_COMPLETE);
+        }
+    }
+
+    ////
+
     typedef SharedSurface_D3D11Interop ptrT;
-    UniquePtr<ptrT> ret ( new ptrT(gl, size, hasAlpha, rbGL, interop, lockHandle,
-                                   texD3D, dxgiHandle) );
+    UniquePtr<ptrT> ret ( new ptrT(gl, size, hasAlpha, prodTex, interopFB, interopRB,
+                                   interop, lockHandle, texD3D, dxgiHandle) );
     return Move(ret);
 }
 
 SharedSurface_D3D11Interop::SharedSurface_D3D11Interop(GLContext* gl,
                                                        const gfx::IntSize& size,
-                                                       bool hasAlpha, GLuint rbGL,
+                                                       bool hasAlpha, GLuint prodTex,
+                                                       GLuint interopFB, GLuint interopRB,
                                                        DXInterop2Device* interop,
                                                        HANDLE lockHandle,
                                                        ID3D11Texture2D* texD3D,
                                                        HANDLE dxgiHandle)
     : SharedSurface(SharedSurfaceType::DXGLInterop2,
-                    AttachmentType::GLRenderbuffer,
+                    prodTex ? AttachmentType::GLTexture
+                            : AttachmentType::GLRenderbuffer,
                     gl,
                     size,
                     hasAlpha,
                     true)
-    , mProdRB(rbGL)
+    , mProdTex(prodTex)
+    , mInteropFB(interopFB)
+    , mInteropRB(interopRB)
     , mInterop(interop)
     , mLockHandle(lockHandle)
     , mTexD3D(texD3D)
     , mDXGIHandle(dxgiHandle)
     , mNeedsFinish(gfxPrefs::WebGLDXGLNeedsFinish())
     , mLockedForGL(false)
-{ }
+{
+    MOZ_ASSERT(bool(mProdTex) == bool(mInteropFB));
+}
 
 SharedSurface_D3D11Interop::~SharedSurface_D3D11Interop()
 {
     MOZ_ASSERT(!IsProducerAcquired());
 
     if (!mGL || !mGL->MakeCurrent())
         return;
 
     if (!mInterop->UnregisterObject(mLockHandle)) {
         NS_WARNING("Failed to release mLockHandle, possibly leaking it.");
     }
 
-    mGL->fDeleteRenderbuffers(1, &mProdRB);
+    mGL->fDeleteTextures(1, &mProdTex);
+    mGL->fDeleteFramebuffers(1, &mInteropFB);
+    mGL->fDeleteRenderbuffers(1, &mInteropRB);
 }
 
 void
 SharedSurface_D3D11Interop::ProducerAcquireImpl()
 {
     MOZ_ASSERT(!mLockedForGL);
 
     // Now we have the mutex, we can lock for GL.
@@ -360,16 +405,21 @@ SharedSurface_D3D11Interop::ProducerAcqu
     mLockedForGL = true;
 }
 
 void
 SharedSurface_D3D11Interop::ProducerReleaseImpl()
 {
     MOZ_ASSERT(mLockedForGL);
 
+    if (mProdTex) {
+        mGL->BlitHelper()->DrawBlitTextureToFramebuffer(mProdTex, mInteropFB, mSize,
+                                                        mSize);
+    }
+
     if (mNeedsFinish) {
         mGL->fFinish();
     } else {
         // We probably don't even need this.
         mGL->fFlush();
     }
     MOZ_ALWAYS_TRUE( mInterop->UnlockObject(mLockHandle) );
 
--- a/gfx/gl/SharedSurfaceD3D11Interop.h
+++ b/gfx/gl/SharedSurfaceD3D11Interop.h
@@ -15,17 +15,19 @@ namespace gl {
 class DXInterop2Device;
 class GLContext;
 class WGLLibrary;
 
 class SharedSurface_D3D11Interop
     : public SharedSurface
 {
 public:
-    const GLuint mProdRB;
+    const GLuint mProdTex;
+    const GLuint mInteropFB;
+    const GLuint mInteropRB;
     const RefPtr<DXInterop2Device> mInterop;
     const HANDLE mLockHandle;
     const RefPtr<ID3D11Texture2D> mTexD3D;
     const HANDLE mDXGIHandle;
     const bool mNeedsFinish;
 
 protected:
     bool mLockedForGL;
@@ -40,33 +42,41 @@ public:
         MOZ_ASSERT(surf->mType == SharedSurfaceType::DXGLInterop2);
         return (SharedSurface_D3D11Interop*)surf;
     }
 
 protected:
     SharedSurface_D3D11Interop(GLContext* gl,
                                const gfx::IntSize& size,
                                bool hasAlpha,
-                               GLuint renderbufferGL,
+                               GLuint prodTex,
+                               GLuint interopFB,
+                               GLuint interopRB,
                                DXInterop2Device* interop,
                                HANDLE lockHandle,
                                ID3D11Texture2D* texD3D,
                                HANDLE dxgiHandle);
 
 public:
     virtual ~SharedSurface_D3D11Interop() override;
 
     virtual void LockProdImpl() override { }
     virtual void UnlockProdImpl() override { }
 
     virtual void ProducerAcquireImpl() override;
     virtual void ProducerReleaseImpl() override;
 
     virtual GLuint ProdRenderbuffer() override {
-        return mProdRB;
+        MOZ_ASSERT(!mProdTex);
+        return mInteropRB;
+    }
+
+    virtual GLuint ProdTexture() override {
+        MOZ_ASSERT(mProdTex);
+        return mProdTex;
     }
 
     virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
 };
 
 class SurfaceFactory_D3D11Interop
     : public SurfaceFactory
 {