Bug 1170842 - Part 4: Implement FramebufferTextureLayer. r=jgilbert
authorDan Glastonbury <dglastonbury@mozilla.com>
Fri, 03 Jul 2015 11:55:43 +1000
changeset 279089 4a61055fc72db54c77ea8c4d0ea510b09b12ffd1
parent 279088 0310a2141d9565a66fccfd9377685cdd256043d3
child 279091 67083c55d5d8dd09d7e60d907cddbe1a42c13edc
push idunknown
push userunknown
push dateunknown
reviewersjgilbert
bugs1170842
milestone43.0a1
Bug 1170842 - Part 4: Implement FramebufferTextureLayer. r=jgilbert
dom/canvas/WebGL2Context.cpp
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextFramebuffers.cpp
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLFramebuffer.cpp
dom/canvas/WebGLFramebuffer.h
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -74,18 +74,17 @@ static const gl::GLFeature kRequiredFeat
     gl::GLFeature::clear_buffers,
     gl::GLFeature::copy_buffer,
     gl::GLFeature::depth_texture,
     gl::GLFeature::draw_instanced,
     gl::GLFeature::draw_range_elements,
     gl::GLFeature::element_index_uint,
     gl::GLFeature::frag_color_float,
     gl::GLFeature::frag_depth,
-    gl::GLFeature::framebuffer_blit,
-    gl::GLFeature::framebuffer_multisample,
+    gl::GLFeature::framebuffer_object,
     gl::GLFeature::get_integer_indexed,
     gl::GLFeature::get_integer64_indexed,
     gl::GLFeature::gpu_shader4,
     gl::GLFeature::instanced_arrays,
     gl::GLFeature::instanced_non_arrays,
     gl::GLFeature::map_buffer_range,
     gl::GLFeature::occlusion_query2,
     gl::GLFeature::packed_depth_stencil,
@@ -160,16 +159,26 @@ WebGLContext::InitWebGL2()
     }
 
     // we initialise WebGL 2 related stuff.
     gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
                      &mGLMaxTransformFeedbackSeparateAttribs);
     gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
                      &mGLMaxUniformBufferBindings);
 
+    if (MinCapabilityMode()) {
+        mGLMax3DTextureSize = MINVALUE_GL_MAX_3D_TEXTURE_SIZE;
+        mGLMaxArrayTextureLayers = MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS;
+    } else {
+        gl->fGetIntegerv(LOCAL_GL_MAX_3D_TEXTURE_SIZE,
+                         (GLint*) &mGLMax3DTextureSize);
+        gl->fGetIntegerv(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS,
+                         (GLint*) &mGLMaxArrayTextureLayers);
+    }
+
     mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
     mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);
 
     mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
     mBoundTransformFeedback = mDefaultTransformFeedback;
 
     mBypassShaderValidation = true;
 
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -3,16 +3,22 @@
  * 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 WEBGL2CONTEXT_H_
 #define WEBGL2CONTEXT_H_
 
 #include "WebGLContext.h"
 
+/*
+ * Minimum value constants define in 6.2 State Tables of OpenGL ES - 3.0.4
+ */
+#define MINVALUE_GL_MAX_3D_TEXTURE_SIZE             256
+#define MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS        256
+
 namespace mozilla {
 
 class ErrorResult;
 class WebGLSampler;
 class WebGLSync;
 class WebGLTransformFeedback;
 class WebGLVertexArrayObject;
 namespace dom {
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -325,20 +325,102 @@ WebGL2Context::BlitFramebuffer(GLint src
     }
 
     MakeContextCurrent();
     gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
                          dstX0, dstY0, dstX1, dstY1,
                          mask, filter);
 }
 
+static bool
+ValidateTextureLayerAttachment(GLenum attachment)
+{
+    if (LOCAL_GL_COLOR_ATTACHMENT0 < attachment &&
+        attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
+    {
+        return true;
+    }
+
+    switch (attachment) {
+    case LOCAL_GL_DEPTH_ATTACHMENT:
+    case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
+    case LOCAL_GL_STENCIL_ATTACHMENT:
+        return true;
+    }
+
+    return false;
+}
+
 void
-WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
+WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
+                                       WebGLTexture* texture, GLint level, GLint layer)
 {
-    GenerateWarning("framebufferTextureLayer: Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!ValidateFramebufferTarget(target, "framebufferTextureLayer"))
+        return;
+
+    if (!ValidateTextureLayerAttachment(attachment))
+        return ErrorInvalidEnumInfo("framebufferTextureLayer: attachment:", attachment);
+
+    if (texture) {
+        if (texture->IsDeleted()) {
+            return ErrorInvalidValue("framebufferTextureLayer: texture must be a valid "
+                                     "texture object.");
+        }
+
+        if (level < 0)
+            return ErrorInvalidValue("framebufferTextureLayer: layer must be >= 0.");
+
+        switch (texture->Target()) {
+        case LOCAL_GL_TEXTURE_3D:
+            if ((GLuint) layer >= mGLMax3DTextureSize) {
+                return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
+                                         "MAX_3D_TEXTURE_SIZE");
+            }
+            break;
+
+        case LOCAL_GL_TEXTURE_2D_ARRAY:
+            if ((GLuint) layer >= mGLMaxArrayTextureLayers) {
+                return ErrorInvalidValue("framebufferTextureLayer: layer must be < "
+                                         "MAX_ARRAY_TEXTURE_LAYERS");
+            }
+            break;
+
+        default:
+            return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
+                                         "existing 3D texture, or a 2D texture array.");
+        }
+    } else {
+        return ErrorInvalidOperation("framebufferTextureLayer: texture must be an "
+                                     "existing 3D texture, or a 2D texture array.");
+    }
+
+    WebGLFramebuffer* fb;
+    switch (target) {
+    case LOCAL_GL_FRAMEBUFFER:
+    case LOCAL_GL_DRAW_FRAMEBUFFER:
+        fb = mBoundDrawFramebuffer;
+        break;
+
+    case LOCAL_GL_READ_FRAMEBUFFER:
+        fb = mBoundReadFramebuffer;
+        break;
+
+    default:
+        MOZ_CRASH("Bad target.");
+    }
+
+    if (!fb) {
+        return ErrorInvalidOperation("framebufferTextureLayer: cannot modify"
+                                     " framebuffer 0.");
+    }
+
+    fb->FramebufferTextureLayer(attachment, texture, level, layer);
 }
 
 // Map attachments intended for the default buffer, to attachments for a non-
 // default buffer.
 static bool
 TranslateDefaultAttachments(const dom::Sequence<GLenum>& in, dom::Sequence<GLenum>* out)
 {
     for (size_t i = 0; i < in.Length(); i++) {
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -267,16 +267,18 @@ WebGLContext::WebGLContext()
     mGLMaxVertexTextureImageUnits = 0;
     mGLMaxVaryingVectors = 0;
     mGLMaxFragmentUniformVectors = 0;
     mGLMaxVertexUniformVectors = 0;
     mGLMaxColorAttachments = 1;
     mGLMaxDrawBuffers = 1;
     mGLMaxTransformFeedbackSeparateAttribs = 0;
     mGLMaxUniformBufferBindings = 0;
+    mGLMax3DTextureSize = 0;
+    mGLMaxArrayTextureLayers = 0;
 
     // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
     mPixelStorePackAlignment = 4;
     mPixelStoreUnpackAlignment = 4;
 
     WebGLMemoryTracker::AddWebGLContext(this);
 
     mAllowContextRestore = true;
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1072,16 +1072,18 @@ protected:
     int32_t mGLMaxVaryingVectors;
     int32_t mGLMaxFragmentUniformVectors;
     int32_t mGLMaxVertexUniformVectors;
     int32_t mGLMaxColorAttachments;
     int32_t mGLMaxDrawBuffers;
     uint32_t  mGLMaxTransformFeedbackSeparateAttribs;
     GLuint  mGLMaxUniformBufferBindings;
     GLsizei mGLMaxSamples;
+    GLuint  mGLMax3DTextureSize;
+    GLuint  mGLMaxArrayTextureLayers;
 
 public:
     GLuint MaxVertexAttribs() const {
         return mGLMaxVertexAttribs;
     }
 
     GLuint GLMaxTextureUnits() const {
         return mGLMaxTextureUnits;
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -116,27 +116,34 @@ UnmarkAttachment(WebGLFBAttachPoint& att
     if (!maybe)
         maybe = attachment.Renderbuffer();
 
     if (maybe)
         maybe->UnmarkAttachment(attachment);
 }
 
 void
-WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target,
-                                          GLint level)
+WebGLFBAttachPoint::SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level)
+{
+    SetTexImageLayer(tex, target, level, 0);
+}
+
+void
+WebGLFBAttachPoint::SetTexImageLayer(WebGLTexture* tex, TexImageTarget target,
+                                     GLint level, GLint layer)
 {
     mFB->InvalidateFramebufferStatus();
 
     UnmarkAttachment(*this);
 
     mTexturePtr = tex;
     mRenderbufferPtr = nullptr;
     mTexImageTarget = target;
     mTexImageLevel = level;
+    mTexImageLayer = layer;
 
     if (tex)
         tex->MarkAttachment(*this);
 }
 
 void
 WebGLFBAttachPoint::SetRenderbuffer(WebGLRenderbuffer* rb)
 {
@@ -373,28 +380,54 @@ WebGLFBAttachPoint::FinalizeAttachment(g
     }
     MOZ_ASSERT(HasImage());
 
     if (Texture()) {
         MOZ_ASSERT(gl == Texture()->Context()->GL());
 
         const GLenum imageTarget = ImageTarget().get();
         const GLint mipLevel = MipLevel();
+        const GLint layer = Layer();
         const GLuint glName = Texture()->mGLName;
 
-        if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
-            gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
-                                      imageTarget, glName, mipLevel);
-            gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
-                                      imageTarget, glName, mipLevel);
-        } else {
-            gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
-                                      imageTarget, glName, mipLevel);
+        switch (imageTarget) {
+        case LOCAL_GL_TEXTURE_2D:
+        case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+        case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+        case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+        case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+        case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+        case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+            if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+                gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
+                                          imageTarget, glName, mipLevel);
+                gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
+                                          imageTarget, glName, mipLevel);
+            } else {
+                gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
+                                          imageTarget, glName, mipLevel);
+            }
+            break;
+
+        case LOCAL_GL_TEXTURE_2D_ARRAY:
+        case LOCAL_GL_TEXTURE_3D:
+            if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
+                gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER,
+                                             LOCAL_GL_DEPTH_ATTACHMENT,
+                                             glName, mipLevel, layer);
+                gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER,
+                                             LOCAL_GL_STENCIL_ATTACHMENT,
+                                             glName, mipLevel, layer);
+            } else {
+                gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
+                                             glName, mipLevel, layer);
+            }
+            break;
         }
-        return;
+        return ;
     }
 
     if (Renderbuffer()) {
         Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
         return;
     }
 
     MOZ_CRASH();
@@ -482,16 +515,31 @@ WebGLFramebuffer::FramebufferTexture2D(F
     }
 
     WebGLFBAttachPoint& attachPoint = GetAttachPoint(attachPointEnum);
     attachPoint.SetTexImage(tex, texImageTarget, level);
 
     InvalidateFramebufferStatus();
 }
 
+void
+WebGLFramebuffer::FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex,
+                                          GLint level, GLint layer)
+{
+    MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
+               mContext->mBoundReadFramebuffer == this);
+    MOZ_ASSERT(tex);
+
+    WebGLFBAttachPoint& attachPoint = GetAttachPoint(attachment);
+    TexImageTarget texImageTarget = tex->Target();
+    attachPoint.SetTexImageLayer(tex, texImageTarget, level, layer);
+
+    InvalidateFramebufferStatus();
+}
+
 WebGLFBAttachPoint&
 WebGLFramebuffer::GetAttachPoint(FBAttachment attachPoint)
 {
     switch (attachPoint.get()) {
     case LOCAL_GL_COLOR_ATTACHMENT0:
         return mColorAttachment0;
 
     case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -29,16 +29,17 @@ class WebGLFBAttachPoint
 {
 public:
     WebGLFramebuffer* const mFB;
 private:
     WebGLRefPtr<WebGLTexture> mTexturePtr;
     WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
     FBAttachment mAttachmentPoint;
     TexImageTarget mTexImageTarget;
+    GLint mTexImageLayer;
     GLint mTexImageLevel;
 
 public:
     WebGLFBAttachPoint(WebGLFramebuffer* fb, FBAttachment attachmentPoint);
     ~WebGLFBAttachPoint();
 
     void Unlink() {
         mRenderbufferPtr = nullptr;
@@ -53,33 +54,38 @@ public:
     bool HasAlpha() const;
     bool IsReadableFloat() const;
 
     void Clear() {
         SetRenderbuffer(nullptr);
     }
 
     void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
+    void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level,
+                          GLint layer);
     void SetRenderbuffer(WebGLRenderbuffer* rb);
-
+    
     const WebGLTexture* Texture() const {
         return mTexturePtr;
     }
     WebGLTexture* Texture() {
         return mTexturePtr;
     }
     const WebGLRenderbuffer* Renderbuffer() const {
         return mRenderbufferPtr;
     }
     WebGLRenderbuffer* Renderbuffer() {
         return mRenderbufferPtr;
     }
     TexImageTarget ImageTarget() const {
         return mTexImageTarget;
     }
+    GLint Layer() const {
+        return mTexImageLayer;
+    }
     GLint MipLevel() const {
         return mTexImageLevel;
     }
 
     bool HasUninitializedImageData() const;
     void SetImageDataStatus(WebGLImageDataStatus x);
 
     const WebGLRectangleObject& RectangleObject() const;
@@ -141,16 +147,19 @@ public:
 
     void FramebufferRenderbuffer(FBAttachment attachment, RBTarget rbtarget,
                                  WebGLRenderbuffer* rb);
 
     void FramebufferTexture2D(FBAttachment attachment,
                               TexImageTarget texImageTarget, WebGLTexture* tex,
                               GLint level);
 
+    void FramebufferTextureLayer(FBAttachment attachment, WebGLTexture* tex, GLint level,
+                                 GLint layer);
+
     bool HasDefinedAttachments() const;
     bool HasIncompleteAttachments() const;
     bool AllImageRectsMatch() const;
     FBStatus PrecheckFramebufferStatus() const;
     FBStatus CheckFramebufferStatus() const;
 
     GLenum
     GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const;