Bug 1325333 - Check type of buffer to be cleared by Clear[Buffer]. - r=daoshengmu a=lizzard
authorJeff Gilbert <jgilbert@mozilla.com>
Thu, 22 Dec 2016 02:22:12 -0800
changeset 366064 f1877cf8ba418215cc955b85b56ac674a54230b7
parent 366063 2d2153ad43c9ee058b21eeec125720fd30b54ffe
child 366065 927ea08a16a54e8c4322231249f9562e725465f5
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdaoshengmu, lizzard
bugs1325333
milestone52.0a2
Bug 1325333 - Check type of buffer to be cleared by Clear[Buffer]. - r=daoshengmu a=lizzard MozReview-Commit-ID: 8A37aTeW25t
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextMRTs.cpp
dom/canvas/WebGLContextFramebufferOperations.cpp
dom/canvas/WebGLFramebuffer.cpp
dom/canvas/WebGLFramebuffer.h
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -291,17 +291,17 @@ public:
     // ------------------------------------------------------------------------
     // Multiple Render Targets - WebGL2ContextMRTs.cpp
     /* Implemented in WebGLContext
     void DrawBuffers(const dom::Sequence<GLenum>& buffers);
     */
 
 private:
     bool ValidateClearBuffer(const char* funcName, GLenum buffer, GLint drawBuffer,
-                             size_t availElemCount, GLuint elemOffset);
+                             size_t availElemCount, GLuint elemOffset, GLenum funcType);
 
     void ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32Arr& src,
                        GLuint srcElemOffset);
     void ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32Arr& src,
                        GLuint srcElemOffset);
     void ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32Arr& src,
                         GLuint srcElemOffset);
 
--- a/dom/canvas/WebGL2ContextMRTs.cpp
+++ b/dom/canvas/WebGL2ContextMRTs.cpp
@@ -7,48 +7,46 @@
 
 #include "GLContext.h"
 #include "WebGLFramebuffer.h"
 
 namespace mozilla {
 
 bool
 WebGL2Context::ValidateClearBuffer(const char* funcName, GLenum buffer, GLint drawBuffer,
-                                   size_t availElemCount, GLuint elemOffset)
+                                   size_t availElemCount, GLuint elemOffset,
+                                   GLenum funcType)
 {
-    if (IsContextLost())
-        return false;
-
     if (elemOffset > availElemCount) {
         ErrorInvalidValue("%s: Offset too big for list.", funcName);
         return false;
     }
     availElemCount -= elemOffset;
 
     ////
 
     size_t requiredElements;
     GLint maxDrawBuffer;
     switch (buffer) {
     case LOCAL_GL_COLOR:
-    case LOCAL_GL_FRONT:
-    case LOCAL_GL_BACK:
-    case LOCAL_GL_LEFT:
-    case LOCAL_GL_RIGHT:
-    case LOCAL_GL_FRONT_AND_BACK:
           requiredElements = 4;
           maxDrawBuffer = mGLMaxDrawBuffers - 1;
           break;
 
     case LOCAL_GL_DEPTH:
     case LOCAL_GL_STENCIL:
           requiredElements = 1;
           maxDrawBuffer = 0;
           break;
 
+    case LOCAL_GL_DEPTH_STENCIL:
+          requiredElements = 2;
+          maxDrawBuffer = 0;
+          break;
+
     default:
           ErrorInvalidEnumInfo(funcName, buffer);
           return false;
     }
 
     if (drawBuffer < 0 || drawBuffer > maxDrawBuffer) {
         ErrorInvalidValue("%s: Invalid drawbuffer %d. This buffer only supports"
                           " `drawbuffer` values between 0 and %u.",
@@ -60,79 +58,131 @@ WebGL2Context::ValidateClearBuffer(const
         ErrorInvalidValue("%s: Not enough elements. Require %u. Given %u.",
                           funcName, requiredElements, availElemCount);
         return false;
     }
 
     ////
 
     MakeContextCurrent();
-    if (mBoundDrawFramebuffer) {
-        if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
+
+    const auto& fb = mBoundDrawFramebuffer;
+    if (fb) {
+        if (!fb->ValidateAndInitAttachments(funcName))
+            return false;
+
+        if (!fb->ValidateClearBufferType(funcName, buffer, drawBuffer, funcType))
             return false;
+    } else if (buffer == LOCAL_GL_COLOR) {
+        if (drawBuffer != 0)
+            return true;
+
+        if (mDefaultFB_DrawBuffer0 == LOCAL_GL_NONE)
+            return true;
+
+        if (funcType != LOCAL_GL_FLOAT) {
+            ErrorInvalidOperation("%s: For default framebuffer, COLOR is always of type"
+                                  " FLOAT.",
+                                  funcName);
+            return false;
+        }
     }
 
     return true;
 }
 
 ////
 
 void
 WebGL2Context::ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32Arr& src,
                              GLuint srcElemOffset)
 {
     const char funcName[] = "clearBufferfv";
-    if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
+    if (IsContextLost())
         return;
 
+    if (buffer != LOCAL_GL_COLOR &&
+        buffer != LOCAL_GL_DEPTH)
+    {
+        ErrorInvalidEnum("%s: buffer must be COLOR or DEPTH.", funcName);
+        return;
+    }
+
+    if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset,
+                             LOCAL_GL_FLOAT))
+    {
+        return;
+    }
+
     ScopedDrawCallWrapper wrapper(*this);
-
     const auto ptr = src.elemBytes + srcElemOffset;
     gl->fClearBufferfv(buffer, drawBuffer, ptr);
 }
 
 void
 WebGL2Context::ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32Arr& src,
                              GLuint srcElemOffset)
 {
     const char funcName[] = "clearBufferiv";
-    if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
+    if (IsContextLost())
         return;
 
+    if (buffer != LOCAL_GL_COLOR &&
+        buffer != LOCAL_GL_STENCIL)
+    {
+        ErrorInvalidEnum("%s: buffer must be COLOR or STENCIL.", funcName);
+        return;
+    }
+
+    if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset,
+                             LOCAL_GL_INT))
+    {
+        return;
+    }
+
     ScopedDrawCallWrapper wrapper(*this);
-
     const auto ptr = src.elemBytes + srcElemOffset;
     gl->fClearBufferiv(buffer, drawBuffer, ptr);
 }
 
 void
 WebGL2Context::ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32Arr& src,
                               GLuint srcElemOffset)
 {
     const char funcName[] = "clearBufferuiv";
-    if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset))
+    if (IsContextLost())
         return;
 
+    if (buffer != LOCAL_GL_COLOR)
+        return ErrorInvalidEnum("%s: buffer must be COLOR.", funcName);
+
+    if (!ValidateClearBuffer(funcName, buffer, drawBuffer, src.elemCount, srcElemOffset,
+                             LOCAL_GL_UNSIGNED_INT))
+    {
+        return;
+    }
+
     ScopedDrawCallWrapper wrapper(*this);
-
     const auto ptr = src.elemBytes + srcElemOffset;
     gl->fClearBufferuiv(buffer, drawBuffer, ptr);
 }
 
 ////
 
 void
 WebGL2Context::ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth,
                              GLint stencil)
 {
     const char funcName[] = "clearBufferfi";
-    if (!ValidateClearBuffer(funcName, LOCAL_GL_DEPTH, drawBuffer, 1, 0))
+    if (IsContextLost())
         return;
 
     if (buffer != LOCAL_GL_DEPTH_STENCIL)
-        return ErrorInvalidEnumInfo(funcName, buffer);
+        return ErrorInvalidEnum("%s: buffer must be DEPTH_STENCIL.", funcName);
+
+    if (!ValidateClearBuffer(funcName, buffer, drawBuffer, 2, 0, 0))
+        return;
 
     ScopedDrawCallWrapper wrapper(*this);
-
     gl->fClearBufferfi(buffer, drawBuffer, depth, stencil);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLContextFramebufferOperations.cpp
+++ b/dom/canvas/WebGLContextFramebufferOperations.cpp
@@ -27,20 +27,37 @@ WebGLContext::Clear(GLbitfield mask)
         return ErrorInvalidValue("%s: invalid mask bits", funcName);
 
     if (mask == 0) {
         GenerateWarning("Calling gl.clear(0) has no effect.");
     } else if (mRasterizerDiscardEnabled) {
         GenerateWarning("Calling gl.clear() with RASTERIZER_DISCARD enabled has no effects.");
     }
 
-    if (mBoundDrawFramebuffer &&
-        !mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
-    {
-        return;
+    if (mBoundDrawFramebuffer) {
+        if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(funcName))
+            return;
+
+        if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
+            const auto& resolvedData = mBoundDrawFramebuffer->ResolvedCompleteData();
+            for (const auto& cur : resolvedData->colorDrawBuffers) {
+                switch (cur->Format()->format->componentType) {
+                case webgl::ComponentType::Float:
+                case webgl::ComponentType::NormInt:
+                case webgl::ComponentType::NormUInt:
+                    break;
+
+                default:
+                    ErrorInvalidOperation("%s: Color draw buffers must be floating-point"
+                                          " or fixed-point. (normalized (u)ints)",
+                                          funcName);
+                    return;
+                }
+            }
+        }
     }
 
     ScopedDrawCallWrapper wrapper(*this);
     gl->fClear(mask);
 }
 
 static GLfloat
 GLClampFloat(GLfloat val)
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -866,16 +866,54 @@ WebGLFramebuffer::ValidateAndInitAttachm
 
     mContext->ErrorInvalidFramebufferOperation("%s: Framebuffer must be"
                                                " complete.",
                                                funcName);
     return false;
 }
 
 bool
+WebGLFramebuffer::ValidateClearBufferType(const char* funcName, GLenum buffer,
+                                          uint32_t drawBuffer, GLenum funcType) const
+{
+    if (buffer != LOCAL_GL_COLOR)
+        return true;
+
+    const auto& attach = mColorAttachments[drawBuffer];
+    if (!count(mResolvedCompleteData->colorDrawBuffers.begin(),
+               mResolvedCompleteData->colorDrawBuffers.end(),
+               &attach))
+    {
+        return true; // DRAW_BUFFERi set to NONE.
+    }
+
+    GLenum attachType;
+    switch (attach.Format()->format->componentType) {
+    case webgl::ComponentType::Int:
+        attachType = LOCAL_GL_INT;
+        break;
+    case webgl::ComponentType::UInt:
+        attachType = LOCAL_GL_UNSIGNED_INT;
+        break;
+    default:
+        attachType = LOCAL_GL_FLOAT;
+        break;
+    }
+
+    if (attachType != funcType) {
+        mContext->ErrorInvalidOperation("%s: This attachment is of type 0x%04x, but"
+                                        " this function is of type 0x%04x.",
+                                        funcName, attachType, funcType);
+        return false;
+    }
+
+    return true;
+}
+
+bool
 WebGLFramebuffer::ValidateForRead(const char* funcName,
                                   const webgl::FormatUsageInfo** const out_format,
                                   uint32_t* const out_width, uint32_t* const out_height)
 {
     if (!ValidateAndInitAttachments(funcName))
         return false;
 
     if (!mColorReadBuffer) {
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -233,16 +233,18 @@ protected:
     void RefreshDrawBuffers() const;
     void RefreshReadBuffer() const;
     bool ResolveAttachmentData(const char* funcName) const;
 
 public:
     void DetachTexture(const WebGLTexture* tex);
     void DetachRenderbuffer(const WebGLRenderbuffer* rb);
     bool ValidateAndInitAttachments(const char* funcName);
+    bool ValidateClearBufferType(const char* funcName, GLenum buffer, uint32_t drawBuffer,
+                                 GLenum funcType) const;
 
     bool ValidateForRead(const char* info,
                          const webgl::FormatUsageInfo** const out_format,
                          uint32_t* const out_width, uint32_t* const out_height);
 
     ////////////////
     // Getters