+
+
+/** Returned by make_color_buffer_mask() for errors */
+#define INVALID_MASK ~0x0
+
+
+/**
+ * Convert the glClearBuffer 'drawbuffer' parameter into a bitmask of
+ * BUFFER_BIT_x values.
+ * Return INVALID_MASK if the drawbuffer value is invalid.
+ */
+static GLbitfield
+make_color_buffer_mask(struct gl_context *ctx, GLint drawbuffer)
+{
+ const struct gl_renderbuffer_attachment *att = ctx->DrawBuffer->Attachment;
+ GLbitfield mask = 0x0;
+
+ /* From the GL 4.0 specification:
+ * If buffer is COLOR, a particular draw buffer DRAW_BUFFERi is
+ * specified by passing i as the parameter drawbuffer, and value
+ * points to a four-element vector specifying the R, G, B, and A
+ * color to clear that draw buffer to. If the draw buffer is one
+ * of FRONT, BACK, LEFT, RIGHT, or FRONT_AND_BACK, identifying
+ * multiple buffers, each selected buffer is cleared to the same
+ * value.
+ *
+ * Note that "drawbuffer" and "draw buffer" have different meaning.
+ * "drawbuffer" specifies DRAW_BUFFERi, while "draw buffer" is what's
+ * assigned to DRAW_BUFFERi. It could be COLOR_ATTACHMENT0, FRONT, BACK,
+ * etc.
+ */
+ if (drawbuffer < 0 || drawbuffer >= (GLint)ctx->Const.MaxDrawBuffers) {
+ return INVALID_MASK;
+ }
+
+ switch (ctx->DrawBuffer->ColorDrawBuffer[drawbuffer]) {
+ case GL_FRONT:
+ if (att[BUFFER_FRONT_LEFT].Renderbuffer)
+ mask |= BUFFER_BIT_FRONT_LEFT;
+ if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
+ mask |= BUFFER_BIT_FRONT_RIGHT;
+ break;
+ case GL_BACK:
+ if (att[BUFFER_BACK_LEFT].Renderbuffer)
+ mask |= BUFFER_BIT_BACK_LEFT;
+ if (att[BUFFER_BACK_RIGHT].Renderbuffer)
+ mask |= BUFFER_BIT_BACK_RIGHT;
+ break;
+ case GL_LEFT:
+ if (att[BUFFER_FRONT_LEFT].Renderbuffer)
+ mask |= BUFFER_BIT_FRONT_LEFT;
+ if (att[BUFFER_BACK_LEFT].Renderbuffer)
+ mask |= BUFFER_BIT_BACK_LEFT;
+ break;
+ case GL_RIGHT:
+ if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
+ mask |= BUFFER_BIT_FRONT_RIGHT;
+ if (att[BUFFER_BACK_RIGHT].Renderbuffer)
+ mask |= BUFFER_BIT_BACK_RIGHT;
+ break;
+ case GL_FRONT_AND_BACK:
+ if (att[BUFFER_FRONT_LEFT].Renderbuffer)
+ mask |= BUFFER_BIT_FRONT_LEFT;
+ if (att[BUFFER_BACK_LEFT].Renderbuffer)
+ mask |= BUFFER_BIT_BACK_LEFT;
+ if (att[BUFFER_FRONT_RIGHT].Renderbuffer)
+ mask |= BUFFER_BIT_FRONT_RIGHT;
+ if (att[BUFFER_BACK_RIGHT].Renderbuffer)
+ mask |= BUFFER_BIT_BACK_RIGHT;
+ break;
+ default:
+ {
+ GLint buf = ctx->DrawBuffer->_ColorDrawBufferIndexes[drawbuffer];
+
+ if (buf >= 0 && att[buf].Renderbuffer) {
+ mask |= 1 << buf;
+ }
+ }
+ }
+
+ return mask;
+}
+
+
+
+/**
+ * New in GL 3.0
+ * Clear signed integer color buffer or stencil buffer (not depth).
+ */
+void GLAPIENTRY
+_mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FLUSH_VERTICES(ctx, 0);
+
+ FLUSH_CURRENT(ctx, 0);
+
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+ }
+
+ switch (buffer) {
+ case GL_STENCIL:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "ClearBuffer generates an INVALID VALUE error if buffer is
+ * COLOR and drawbuffer is less than zero, or greater than the
+ * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
+ * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ else if (ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer && !ctx->RasterDiscard) {
+ /* Save current stencil clear value, set to 'value', do the
+ * stencil clear and restore the clear value.
+ * XXX in the future we may have a new ctx->Driver.ClearBuffer()
+ * hook instead.
+ */
+ const GLuint clearSave = ctx->Stencil.Clear;
+ ctx->Stencil.Clear = *value;
+ ctx->Driver.Clear(ctx, BUFFER_BIT_STENCIL);
+ ctx->Stencil.Clear = clearSave;
+ }
+ break;
+ case GL_COLOR:
+ {
+ const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
+ if (mask == INVALID_MASK) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ else if (mask && !ctx->RasterDiscard) {
+ union gl_color_union clearSave;
+
+ /* save color */
+ clearSave = ctx->Color.ClearColor;
+ /* set color */
+ COPY_4V(ctx->Color.ClearColor.i, value);
+ /* clear buffer(s) */
+ ctx->Driver.Clear(ctx, mask);
+ /* restore color */
+ ctx->Color.ClearColor = clearSave;
+ }
+ }
+ break;
+ case GL_DEPTH:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "The result of ClearBuffer is undefined if no conversion between
+ * the type of the specified value and the type of the buffer being
+ * cleared is defined (for example, if ClearBufferiv is called for a
+ * fixed- or floating-point buffer, or if ClearBufferfv is called
+ * for a signed or unsigned integer buffer). This is not an error."
+ *
+ * In this case we take "undefined" and "not an error" to mean "ignore."
+ * Note that we still need to generate an error for the invalid
+ * drawbuffer case (see the GL_STENCIL case above).
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferiv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferiv(buffer=%s)",
+ _mesa_lookup_enum_by_nr(buffer));
+ return;
+ }
+}
+
+
+/**
+ * New in GL 3.0
+ * Clear unsigned integer color buffer (not depth, not stencil).
+ */
+void GLAPIENTRY
+_mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ FLUSH_VERTICES(ctx, 0);
+ FLUSH_CURRENT(ctx, 0);
+
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+ }
+
+ switch (buffer) {
+ case GL_COLOR:
+ {
+ const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
+ if (mask == INVALID_MASK) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ else if (mask && !ctx->RasterDiscard) {
+ union gl_color_union clearSave;
+
+ /* save color */
+ clearSave = ctx->Color.ClearColor;
+ /* set color */
+ COPY_4V(ctx->Color.ClearColor.ui, value);
+ /* clear buffer(s) */
+ ctx->Driver.Clear(ctx, mask);
+ /* restore color */
+ ctx->Color.ClearColor = clearSave;
+ }
+ }
+ break;
+ case GL_DEPTH:
+ case GL_STENCIL:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "The result of ClearBuffer is undefined if no conversion between
+ * the type of the specified value and the type of the buffer being
+ * cleared is defined (for example, if ClearBufferiv is called for a
+ * fixed- or floating-point buffer, or if ClearBufferfv is called
+ * for a signed or unsigned integer buffer). This is not an error."
+ *
+ * In this case we take "undefined" and "not an error" to mean "ignore."
+ * Even though we could do something sensible for GL_STENCIL, page 263
+ * (page 279 of the PDF) says:
+ *
+ * "Only ClearBufferiv should be used to clear stencil buffers."
+ *
+ * Note that we still need to generate an error for the invalid
+ * drawbuffer case (see the GL_STENCIL case in _mesa_ClearBufferiv).
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferuiv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferuiv(buffer=%s)",
+ _mesa_lookup_enum_by_nr(buffer));
+ return;
+ }
+}
+
+
+/**
+ * New in GL 3.0
+ * Clear fixed-pt or float color buffer or depth buffer (not stencil).
+ */
+void GLAPIENTRY
+_mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ FLUSH_VERTICES(ctx, 0);
+ FLUSH_CURRENT(ctx, 0);
+
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+ }
+
+ switch (buffer) {
+ case GL_DEPTH:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "ClearBuffer generates an INVALID VALUE error if buffer is
+ * COLOR and drawbuffer is less than zero, or greater than the
+ * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
+ * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ else if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer && !ctx->RasterDiscard) {
+ /* Save current depth clear value, set to 'value', do the
+ * depth clear and restore the clear value.
+ * XXX in the future we may have a new ctx->Driver.ClearBuffer()
+ * hook instead.
+ */
+ const GLclampd clearSave = ctx->Depth.Clear;
+ ctx->Depth.Clear = *value;
+ ctx->Driver.Clear(ctx, BUFFER_BIT_DEPTH);
+ ctx->Depth.Clear = clearSave;
+ }
+ /* clear depth buffer to value */
+ break;
+ case GL_COLOR:
+ {
+ const GLbitfield mask = make_color_buffer_mask(ctx, drawbuffer);
+ if (mask == INVALID_MASK) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ else if (mask && !ctx->RasterDiscard) {
+ union gl_color_union clearSave;
+
+ /* save color */
+ clearSave = ctx->Color.ClearColor;
+ /* set color */
+ COPY_4V(ctx->Color.ClearColor.f, value);
+ /* clear buffer(s) */
+ ctx->Driver.Clear(ctx, mask);
+ /* restore color */
+ ctx->Color.ClearColor = clearSave;
+ }
+ }
+ break;
+ case GL_STENCIL:
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "The result of ClearBuffer is undefined if no conversion between
+ * the type of the specified value and the type of the buffer being
+ * cleared is defined (for example, if ClearBufferiv is called for a
+ * fixed- or floating-point buffer, or if ClearBufferfv is called
+ * for a signed or unsigned integer buffer). This is not an error."
+ *
+ * In this case we take "undefined" and "not an error" to mean "ignore."
+ * Note that we still need to generate an error for the invalid
+ * drawbuffer case (see the GL_DEPTH case above).
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfv(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfv(buffer=%s)",
+ _mesa_lookup_enum_by_nr(buffer));
+ return;
+ }
+}
+
+
+/**
+ * New in GL 3.0
+ * Clear depth/stencil buffer only.
+ */
+void GLAPIENTRY
+_mesa_ClearBufferfi(GLenum buffer, GLint drawbuffer,
+ GLfloat depth, GLint stencil)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLbitfield mask = 0;
+
+ FLUSH_VERTICES(ctx, 0);
+ FLUSH_CURRENT(ctx, 0);
+
+ if (buffer != GL_DEPTH_STENCIL) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glClearBufferfi(buffer=%s)",
+ _mesa_lookup_enum_by_nr(buffer));
+ return;
+ }
+
+ /* Page 264 (page 280 of the PDF) of the OpenGL 3.0 spec says:
+ *
+ * "ClearBuffer generates an INVALID VALUE error if buffer is
+ * COLOR and drawbuffer is less than zero, or greater than the
+ * value of MAX DRAW BUFFERS minus one; or if buffer is DEPTH,
+ * STENCIL, or DEPTH STENCIL and drawbuffer is not zero."
+ */
+ if (drawbuffer != 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glClearBufferfi(drawbuffer=%d)",
+ drawbuffer);
+ return;
+ }
+
+ if (ctx->RasterDiscard)
+ return;
+
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+ }
+
+ if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer)
+ mask |= BUFFER_BIT_DEPTH;
+ if (ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer)
+ mask |= BUFFER_BIT_STENCIL;
+
+ if (mask) {
+ /* save current clear values */
+ const GLclampd clearDepthSave = ctx->Depth.Clear;
+ const GLuint clearStencilSave = ctx->Stencil.Clear;
+
+ /* set new clear values */
+ ctx->Depth.Clear = depth;
+ ctx->Stencil.Clear = stencil;
+
+ /* clear buffers */
+ ctx->Driver.Clear(ctx, mask);
+
+ /* restore */
+ ctx->Depth.Clear = clearDepthSave;
+ ctx->Stencil.Clear = clearStencilSave;
+ }
+}