Bug 1427668 - Add MozFramebuffer. - r=daoshengmu draft
authorJeff Gilbert <jgilbert@mozilla.com>
Mon, 18 Dec 2017 18:19:38 -0800
changeset 716053 44c13b0337ae588db25c34af7bc98174dc9ac634
parent 716014 3acb14b949150529ec761f845f9a3d61ee341dac
child 716054 41b45ac5be765ef2d57f486fe522e7f758fb9e21
push id94316
push userbmo:jgilbert@mozilla.com
push dateFri, 05 Jan 2018 03:14:09 +0000
reviewersdaoshengmu
bugs1427668
milestone59.0a1
Bug 1427668 - Add MozFramebuffer. - r=daoshengmu MozReview-Commit-ID: CX0wxs7Gqvp
gfx/gl/GLContext.h
gfx/gl/MozFramebuffer.cpp
gfx/gl/MozFramebuffer.h
gfx/gl/moz.build
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -3688,24 +3688,52 @@ protected:
     bool mHeavyGLCallsSinceLastFlush;
 
 public:
     void FlushIfHeavyGLCallsSinceLastFlush();
     static bool ShouldSpew();
     static bool ShouldDumpExts();
     bool 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);
     }
+
+    // --
+
+    GLuint CreateFramebuffer() {
+        GLuint x = 0;
+        fGenFramebuffers(1, &x);
+        return x;
+    }
+    GLuint CreateRenderbuffer() {
+        GLuint x = 0;
+        fGenRenderbuffers(1, &x);
+        return x;
+    }
+    GLuint CreateTexture() {
+        GLuint x = 0;
+        fGenTextures(1, &x);
+        return x;
+    }
+
+    void DeleteFramebuffer(const GLuint x) {
+        fDeleteFramebuffers(1, &x);
+    }
+    void DeleteRenderbuffer(const GLuint x) {
+        fDeleteRenderbuffers(1, &x);
+    }
+    void DeleteTexture(const GLuint x) {
+        fDeleteTextures(1, &x);
+    }
 };
 
 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>
new file mode 100644
--- /dev/null
+++ b/gfx/gl/MozFramebuffer.cpp
@@ -0,0 +1,163 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MozFramebuffer.h"
+
+#include "GLContext.h"
+#include "ScopedGLHelpers.h"
+
+namespace mozilla {
+namespace gl {
+
+static void
+DeleteByTarget(GLContext* const gl, const GLenum target, const GLuint name)
+{
+    if (target == LOCAL_GL_RENDERBUFFER) {
+        gl->DeleteRenderbuffer(name);
+    } else {
+        gl->DeleteTexture(name);
+    }
+}
+
+UniquePtr<MozFramebuffer>
+MozFramebuffer::Create(GLContext* const gl, const gfx::IntSize& size,
+                       const uint32_t samples, const bool depthStencil)
+{
+    if (samples && !gl->IsSupported(GLFeature::framebuffer_multisample))
+        return nullptr;
+
+    gl->MakeCurrent();
+
+    GLContext::LocalErrorScope errorScope(*gl);
+
+    GLenum colorTarget;
+    GLuint colorName;
+    if (samples) {
+        colorTarget = LOCAL_GL_RENDERBUFFER;
+        colorName = gl->CreateRenderbuffer();
+        const ScopedBindRenderbuffer bindRB(gl, colorName);
+        gl->fRenderbufferStorageMultisample(colorTarget, samples, LOCAL_GL_RGBA8,
+                                            size.width, size.height);
+    } else {
+        colorTarget = LOCAL_GL_TEXTURE_2D;
+        colorName = gl->CreateTexture();
+        const ScopedBindTexture bindTex(gl, colorName);
+        gl->TexParams_SetClampNoMips();
+        const ScopedBindPBO bindPBO(gl, LOCAL_GL_PIXEL_UNPACK_BUFFER);
+        gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
+        gl->fTexImage2D(colorTarget, 0, LOCAL_GL_RGBA,
+                        size.width, size.height, 0,
+                        LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr);
+    }
+
+    const auto err = errorScope.GetError();
+    if (err) {
+        MOZ_ASSERT(err == LOCAL_GL_OUT_OF_MEMORY);
+        DeleteByTarget(gl, colorTarget, colorName);
+        return nullptr;
+    }
+
+    return CreateWith(gl, size, samples, depthStencil, colorTarget, colorName);
+}
+
+UniquePtr<MozFramebuffer>
+MozFramebuffer::CreateWith(GLContext* const gl, const gfx::IntSize& size,
+                           const uint32_t samples, const bool depthStencil,
+                           const GLenum colorTarget, const GLuint colorName)
+{
+    UniquePtr<MozFramebuffer> mozFB(new MozFramebuffer(gl, size, samples, depthStencil,
+                                                       colorTarget, colorName));
+
+    const ScopedBindFramebuffer bindFB(gl, mozFB->mFB);
+
+    if (colorTarget == LOCAL_GL_RENDERBUFFER) {
+        gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
+                                     colorTarget, colorName);
+    } else {
+        gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
+                                  colorTarget, colorName, 0);
+    }
+
+    const auto fnAllocRB = [&](GLuint rb, GLenum format) {
+        const ScopedBindRenderbuffer bindRB(gl, rb);
+        if (samples) {
+            gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples, format,
+                                                size.width, size.height);
+        } else {
+            gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, format, size.width,
+                                     size.height);
+        }
+        return rb;
+    };
+
+    if (depthStencil) {
+        GLuint depthRB, stencilRB;
+
+        {
+            GLContext::LocalErrorScope errorScope(*gl);
+
+            if (gl->IsSupported(GLFeature::packed_depth_stencil)) {
+                depthRB = fnAllocRB(mozFB->mDepthRB, LOCAL_GL_DEPTH24_STENCIL8);
+                stencilRB = depthRB; // Ignore unused mStencilRB.
+            } else {
+                depthRB   = fnAllocRB(mozFB->mDepthRB  , LOCAL_GL_DEPTH_COMPONENT24);
+                stencilRB = fnAllocRB(mozFB->mStencilRB, LOCAL_GL_STENCIL_INDEX8);
+            }
+
+            const auto err = errorScope.GetError();
+            if (err) {
+                MOZ_ASSERT(err == LOCAL_GL_OUT_OF_MEMORY);
+                return nullptr;
+            }
+        }
+
+        gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
+                                     LOCAL_GL_RENDERBUFFER, depthRB);
+        gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
+                                     LOCAL_GL_RENDERBUFFER, stencilRB);
+    }
+
+    const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+        MOZ_ASSERT(false);
+        return nullptr;
+    }
+
+    return Move(mozFB);
+}
+
+////////////////////
+
+MozFramebuffer::MozFramebuffer(GLContext* const gl, const gfx::IntSize& size,
+                               const uint32_t samples, const bool depthStencil,
+                               const GLenum colorTarget, const GLuint colorName)
+    : mWeakGL(gl)
+    , mSize(size)
+    , mSamples(samples)
+    , mFB(gl->CreateFramebuffer())
+    , mColorTarget(colorTarget)
+    , mColorName(colorName)
+    , mDepthRB(depthStencil ? gl->CreateRenderbuffer() : 0)
+    , mStencilRB(depthStencil ? gl->CreateRenderbuffer() : 0)
+{
+    MOZ_ASSERT(mColorTarget);
+    MOZ_ASSERT(mColorName);
+}
+
+MozFramebuffer::~MozFramebuffer()
+{
+    GLContext* const gl = mWeakGL;
+    if (!gl || !gl->MakeCurrent())
+        return;
+
+    gl->DeleteFramebuffer(mFB);
+    gl->DeleteRenderbuffer(mDepthRB);
+    gl->DeleteRenderbuffer(mStencilRB);
+
+    DeleteByTarget(gl, mColorTarget, mColorName);
+}
+
+} // namespace gl
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/gl/MozFramebuffer.h
@@ -0,0 +1,54 @@
+/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZ_FRAMEBUFFER_H_
+#define MOZ_FRAMEBUFFER_H_
+
+#include "gfx2DGlue.h"
+#include "GLConsts.h"
+#include "GLContextTypes.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/WeakPtr.h"
+
+namespace mozilla {
+namespace gl {
+
+class MozFramebuffer final
+{
+    const WeakPtr<GLContext> mWeakGL;
+public:
+    const gfx::IntSize mSize;
+    const uint32_t mSamples;
+    const GLuint mFB;
+    const GLenum mColorTarget;
+private:
+    const GLuint mColorName;
+    const GLuint mDepthRB;
+    const GLuint mStencilRB;
+
+public:
+    static UniquePtr<MozFramebuffer> Create(GLContext* gl, const gfx::IntSize& size,
+                                            uint32_t samples, bool depthStencil);
+
+    static UniquePtr<MozFramebuffer> CreateWith(GLContext* gl, const gfx::IntSize& size,
+                                                uint32_t samples, bool depthStencil,
+                                                GLenum colorTarget, GLuint colorName);
+private:
+    MozFramebuffer(GLContext* gl, const gfx::IntSize& size, uint32_t samples,
+                   bool depthStencil, GLenum colorTarget, GLuint colorName);
+public:
+    ~MozFramebuffer();
+
+    GLuint ColorTex() const {
+        if (mColorTarget == LOCAL_GL_RENDERBUFFER)
+            return 0;
+        return mColorName;
+    }
+};
+
+} // namespace gl
+} // namespace mozilla
+
+#endif  // MOZ_FRAMEBUFFER_H_
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -131,16 +131,17 @@ UNIFIED_SOURCES += [
     'GLContextTypes.cpp',
     'GLDebugUtils.cpp',
     'GLLibraryEGL.cpp',
     'GLLibraryLoader.cpp',
     'GLReadTexImageHelper.cpp',
     'GLScreenBuffer.cpp',
     'GLTextureImage.cpp',
     'GLUploadHelpers.cpp',
+    'MozFramebuffer.cpp',
     'ScopedGLHelpers.cpp',
     'SharedSurface.cpp',
     'SharedSurfaceEGL.cpp',
     'SharedSurfaceGL.cpp',
     'SurfaceTypes.cpp',
     'TextureImageEGL.cpp',
 ]