Implemented glClearBuffer*

TRAC #23475

Author: Geoff Lang
Signed-off-by: Jamie Madill
Signed-off-by: Shannon Woods
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index eff73bb..4fc40d3 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -2425,37 +2425,7 @@
     return programBinary->applyUniformBuffers(boundBuffers);
 }
 
-void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
-                         GLenum format, GLenum type, GLsizei *bufSize, void* pixels)
-{
-    Framebuffer *framebuffer = getReadFramebuffer();
 
-    if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
-    {
-        return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
-    }
-
-    if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
-    {
-        return gl::error(GL_INVALID_OPERATION);
-    }
-
-    GLint sizedInternalFormat = IsSizedInternalFormat(format, mClientVersion) ? format
-                                                                              : GetSizedInternalFormat(format, type, mClientVersion);
-
-    GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, mClientVersion, width, getPackAlignment());
-    // sized query sanity check
-    if (bufSize)
-    {
-        int requiredSize = outputPitch * height;
-        if (requiredSize > *bufSize)
-        {
-            return gl::error(GL_INVALID_OPERATION);
-        }
-    }
-
-    mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, getPackReverseRowOrder(), getPackAlignment(), pixels);
-}
 
 void Context::clear(GLbitfield mask)
 {
@@ -2525,6 +2495,211 @@
     mRenderer->clear(clearParams, framebufferObject);
 }
 
+void Context::clearBufferfv(GLenum buffer, int drawbuffer, const float *values)
+{
+    // glClearBufferfv can be called to clear the color buffer or depth buffer
+
+    ClearParameters clearParams = { 0 };
+
+    if (buffer == GL_COLOR)
+    {
+        for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
+        {
+            clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
+        }
+        clearParams.colorFClearValue = ColorF(values[0], values[1], values[2], values[3]);
+        clearParams.colorClearType = GL_FLOAT;
+    }
+    else
+    {
+        for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
+        {
+            clearParams.clearColor[i] = false;
+        }
+        clearParams.colorFClearValue = mState.colorClearValue;
+        clearParams.colorClearType = GL_FLOAT;
+    }
+
+    clearParams.colorMaskRed = mState.blend.colorMaskRed;
+    clearParams.colorMaskGreen = mState.blend.colorMaskGreen;
+    clearParams.colorMaskBlue = mState.blend.colorMaskBlue;
+    clearParams.colorMaskAlpha = mState.blend.colorMaskAlpha;
+
+    if (buffer == GL_DEPTH)
+    {
+        clearParams.clearDepth = true;
+        clearParams.depthClearValue = values[0];
+    }
+    else
+    {
+        clearParams.clearDepth = false;
+        clearParams.depthClearValue = mState.depthClearValue;
+    }
+
+    clearParams.clearStencil = false;
+    clearParams.stencilClearValue = mState.stencilClearValue;
+    clearParams.stencilWriteMask = mState.depthStencil.stencilWritemask;
+    clearParams.scissorEnabled = mState.scissorTest;
+    clearParams.scissor = mState.scissor;
+
+    if (!applyRenderTarget(GL_TRIANGLES, true))   // Clips the clear to the scissor rectangle but not the viewport
+    {
+        return;
+    }
+
+    mRenderer->clear(clearParams, getDrawFramebuffer());
+}
+
+void Context::clearBufferuiv(GLenum buffer, int drawbuffer, const unsigned int *values)
+{
+    // glClearBufferuv can only be called to clear a color buffer
+
+    ClearParameters clearParams = { 0 };
+    for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
+    {
+        clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
+    }
+    clearParams.colorUIClearValue = ColorUI(values[0], values[1], values[2], values[3]);
+    clearParams.colorClearType = GL_UNSIGNED_INT;
+    clearParams.colorMaskRed = mState.blend.colorMaskRed;
+    clearParams.colorMaskGreen = mState.blend.colorMaskGreen;
+    clearParams.colorMaskBlue = mState.blend.colorMaskBlue;
+    clearParams.colorMaskAlpha = mState.blend.colorMaskAlpha;
+    clearParams.clearDepth = false;
+    clearParams.depthClearValue = mState.depthClearValue;
+    clearParams.clearStencil = false;
+    clearParams.stencilClearValue = mState.stencilClearValue;
+    clearParams.stencilWriteMask = mState.depthStencil.stencilWritemask;
+    clearParams.scissorEnabled = mState.scissorTest;
+    clearParams.scissor = mState.scissor;
+
+    if (!applyRenderTarget(GL_TRIANGLES, true))   // Clips the clear to the scissor rectangle but not the viewport
+    {
+        return;
+    }
+
+    mRenderer->clear(clearParams, getDrawFramebuffer());
+}
+
+void Context::clearBufferiv(GLenum buffer, int drawbuffer, const int *values)
+{
+    // glClearBufferfv can be called to clear the color buffer or stencil buffer
+
+    ClearParameters clearParams = { 0 };
+
+    if (buffer == GL_COLOR)
+    {
+        for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
+        {
+            clearParams.clearColor[i] = (drawbuffer == static_cast<int>(i));
+        }
+        clearParams.colorIClearValue = ColorI(values[0], values[1], values[2], values[3]);
+        clearParams.colorClearType = GL_INT;
+    }
+    else
+    {
+        for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
+        {
+            clearParams.clearColor[i] = false;
+        }
+        clearParams.colorFClearValue = mState.colorClearValue;
+        clearParams.colorClearType = GL_FLOAT;
+    }
+
+    clearParams.colorMaskRed = mState.blend.colorMaskRed;
+    clearParams.colorMaskGreen = mState.blend.colorMaskGreen;
+    clearParams.colorMaskBlue = mState.blend.colorMaskBlue;
+    clearParams.colorMaskAlpha = mState.blend.colorMaskAlpha;
+
+    clearParams.clearDepth = false;
+    clearParams.depthClearValue = mState.depthClearValue;
+
+    if (buffer == GL_STENCIL)
+    {
+        clearParams.clearStencil = true;
+        clearParams.stencilClearValue = values[1];
+    }
+    else
+    {
+        clearParams.clearStencil = false;
+        clearParams.stencilClearValue = mState.stencilClearValue;
+    }
+    clearParams.stencilWriteMask = mState.depthStencil.stencilWritemask;
+
+    clearParams.scissorEnabled = mState.scissorTest;
+    clearParams.scissor = mState.scissor;
+
+    if (!applyRenderTarget(GL_TRIANGLES, true))   // Clips the clear to the scissor rectangle but not the viewport
+    {
+        return;
+    }
+
+    mRenderer->clear(clearParams, getDrawFramebuffer());
+}
+
+void Context::clearBufferfi(GLenum buffer, int drawbuffer, float depth, int stencil)
+{
+    // glClearBufferfi can only be called to clear a depth stencil buffer
+
+    ClearParameters clearParams = { 0 };
+    for (unsigned int i = 0; i < ArraySize(clearParams.clearColor); i++)
+    {
+        clearParams.clearColor[i] = false;
+    }
+    clearParams.colorFClearValue = mState.colorClearValue;
+    clearParams.colorClearType = GL_FLOAT;
+    clearParams.colorMaskRed = mState.blend.colorMaskRed;
+    clearParams.colorMaskGreen = mState.blend.colorMaskGreen;
+    clearParams.colorMaskBlue = mState.blend.colorMaskBlue;
+    clearParams.colorMaskAlpha = mState.blend.colorMaskAlpha;
+    clearParams.clearDepth = true;
+    clearParams.depthClearValue = depth;
+    clearParams.clearStencil = true;
+    clearParams.stencilClearValue = stencil;
+    clearParams.stencilWriteMask = mState.depthStencil.stencilWritemask;
+    clearParams.scissorEnabled = mState.scissorTest;
+    clearParams.scissor = mState.scissor;
+
+    if (!applyRenderTarget(GL_TRIANGLES, true))   // Clips the clear to the scissor rectangle but not the viewport
+    {
+        return;
+    }
+
+    mRenderer->clear(clearParams, getDrawFramebuffer());
+}
+
+void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+                         GLenum format, GLenum type, GLsizei *bufSize, void* pixels)
+{
+    Framebuffer *framebuffer = getReadFramebuffer();
+
+    if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+    {
+        return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
+    }
+
+    if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
+    {
+        return gl::error(GL_INVALID_OPERATION);
+    }
+
+    GLint sizedInternalFormat = IsSizedInternalFormat(format, mClientVersion) ? format
+        : GetSizedInternalFormat(format, type, mClientVersion);
+
+    GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, mClientVersion, width, getPackAlignment());
+    // sized query sanity check
+    if (bufSize)
+    {
+        int requiredSize = outputPitch * height;
+        if (requiredSize > *bufSize)
+        {
+            return gl::error(GL_INVALID_OPERATION);
+        }
+    }
+
+    mRenderer->readPixels(framebuffer, x, y, width, height, format, type, outputPitch, getPackReverseRowOrder(), getPackAlignment(), pixels);
+}
+
 void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
 {
     if (!mState.currentProgram)
diff --git a/src/libGLESv2/Context.h b/src/libGLESv2/Context.h
index eb97a5e..808fc4a 100644
--- a/src/libGLESv2/Context.h
+++ b/src/libGLESv2/Context.h
@@ -363,8 +363,13 @@
     bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams);
     bool getIndexedQueryParameterInfo(GLenum target, GLenum *type, unsigned int *numParams);
 
-    void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels);
     void clear(GLbitfield mask);
+    void clearBufferfv(GLenum buffer, int drawbuffer, const float *values);
+    void clearBufferuiv(GLenum buffer, int drawbuffer, const unsigned int *values);
+    void clearBufferiv(GLenum buffer, int drawbuffer, const int *values);
+    void clearBufferfi(GLenum buffer, int drawbuffer, float depth, int stencil);
+
+    void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei *bufSize, void* pixels);
     void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances);
     void drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances);
     void sync(bool block);   // flush/finish
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 35580b3..34dc3a1 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -8374,8 +8374,24 @@
                 return gl::error(GL_INVALID_OPERATION);
             }
 
-            // glClearBufferiv
-            UNIMPLEMENTED();
+            switch (buffer)
+            {
+              case GL_COLOR:
+                if (drawbuffer < 0 || drawbuffer >= static_cast<GLint>(context->getMaximumRenderTargets()))
+                {
+                    return gl::error(GL_INVALID_VALUE);
+                }
+                break;
+              case GL_STENCIL:
+                if (drawbuffer != 0)
+                {
+                    return gl::error(GL_INVALID_VALUE);
+                }
+              default:
+                return gl::error(GL_INVALID_ENUM);
+            }
+
+            context->clearBufferiv(buffer, drawbuffer, value);
         }
     }
     catch(std::bad_alloc&)
@@ -8400,8 +8416,19 @@
                 return gl::error(GL_INVALID_OPERATION);
             }
 
-            // glClearBufferuiv
-            UNIMPLEMENTED();
+            switch (buffer)
+            {
+              case GL_COLOR:
+                if (drawbuffer < 0 || drawbuffer >= static_cast<GLint>(context->getMaximumRenderTargets()))
+                {
+                    return gl::error(GL_INVALID_VALUE);
+                }
+                break;
+              default:
+                return gl::error(GL_INVALID_ENUM);
+            }
+
+            context->clearBufferuiv(buffer, drawbuffer, value);
         }
     }
     catch(std::bad_alloc&)
@@ -8426,8 +8453,25 @@
                 return gl::error(GL_INVALID_OPERATION);
             }
 
-            // glClearBufferfv
-            UNIMPLEMENTED();
+            switch (buffer)
+            {
+              case GL_COLOR:
+                if (drawbuffer < 0 || drawbuffer >= static_cast<GLint>(context->getMaximumRenderTargets()))
+                {
+                    return gl::error(GL_INVALID_VALUE);
+                }
+                break;
+              case GL_DEPTH:
+                if (drawbuffer != 0)
+                {
+                    return gl::error(GL_INVALID_VALUE);
+                }
+                break;
+              default:
+                return gl::error(GL_INVALID_ENUM);
+            }
+
+            context->clearBufferfv(buffer, drawbuffer, value);
         }
     }
     catch(std::bad_alloc&)
@@ -8452,8 +8496,19 @@
                 return gl::error(GL_INVALID_OPERATION);
             }
 
-            // glClearBufferfi
-            UNIMPLEMENTED();
+            switch (buffer)
+            {
+              case GL_DEPTH_STENCIL:
+                if (drawbuffer != 0)
+                {
+                    return gl::error(GL_INVALID_VALUE);
+                }
+                break;
+              default:
+                return gl::error(GL_INVALID_ENUM);
+            }
+
+            context->clearBufferfi(buffer, drawbuffer, depth, stencil);
         }
     }
     catch(std::bad_alloc&)