mesa: Rework crazy error code rules in glDrawBuffers().
authorKenneth Graunke <kenneth@whitecape.org>
Fri, 16 Nov 2012 22:52:01 +0000 (14:52 -0800)
committerIan Romanick <ian.d.romanick@intel.com>
Tue, 15 Jan 2013 21:34:00 +0000 (13:34 -0800)
Perhaps most importantly, this patch adds comments quoting the relevant
spec paragraphs above each error condition.

It also makes three changes:
- For FBOs, GL_COLOR_ATTACHMENTm where m >= MaxDrawBuffers is supposed
  to generate INVALID_OPERATION (not INVALID_ENUM).
- Constants that refer to multiple buffers (such as FRONT, BACK, LEFT,
  RIGHT, and FRONT_AND_BACK) are supposed to generate INVALID_OPERATION,
  not INVALID_ENUM.
- In ES 3.0, for FBOs, buffers[i] must be NONE or GL_COLOR_ATTACHMENTi
  or else INVALID_OPERATION occurs.  (This is a new restriction.)

Fixes es3conform's draw-buffers-api test.

v2: The error path was missing a "return" like all the other error
paths.  Also, we may as well call it glDrawBuffers in the error message
since the ARB suffix doesn't exist in ES 3.

Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
src/mesa/main/buffers.c

index d10a573..3dcd46f 100644 (file)
@@ -290,6 +290,10 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers)
 
    /* Turns out n==0 is a valid input that should not produce an error.
     * The remaining code below correctly handles the n==0 case.
+    *
+    * From the OpenGL 3.0 specification, page 258:
+    * "An INVALID_VALUE error is generated if n is greater than
+    *  MAX_DRAW_BUFFERS."
     */
    if (n < 0 || n > (GLsizei) ctx->Const.MaxDrawBuffers) {
       _mesa_error(ctx, GL_INVALID_VALUE, "glDrawBuffersARB(n)");
@@ -305,20 +309,76 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers)
          destMask[output] = 0x0;
       }
       else {
+         /* From the OpenGL 3.0 specification, page 258:
+          * "If the GL is bound to a framebuffer object and DrawBuffers is
+          *  supplied with [...] COLOR_ATTACHMENTm where m is greater than or
+          *  equal to the value of MAX_COLOR_ATTACHMENTS, then the error
+          *  INVALID_OPERATION results."
+          */
+         if (_mesa_is_user_fbo(ctx->DrawBuffer) && buffers[output] >=
+             GL_COLOR_ATTACHMENT0 + ctx->Const.MaxDrawBuffers) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffersARB(buffer)");
+            return;
+         }
+
          destMask[output] = draw_buffer_enum_to_bitmask(buffers[output]);
-         if (destMask[output] == BAD_MASK
-             || _mesa_bitcount(destMask[output]) > 1) {
+
+         /* From the OpenGL 3.0 specification, page 258:
+          * "Each buffer listed in bufs must be one of the values from tables
+          *  4.5 or 4.6.  Otherwise, an INVALID_ENUM error is generated.
+          */
+         if (destMask[output] == BAD_MASK) {
             _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffersARB(buffer)");
             return;
          }         
+
+         /* From the OpenGL 3.0 specification, page 259:
+          * "For both the default framebuffer and framebuffer objects, the
+          *  constants FRONT, BACK, LEFT, RIGHT, and FRONT_AND_BACK are not
+          *  valid in the bufs array passed to DrawBuffers, and will result in
+          *  the error INVALID_OPERATION.  This restriction is because these
+          *  constants may themselves refer to multiple buffers, as shown in
+          *  table 4.4."
+          */
+         if (_mesa_bitcount(destMask[output]) > 1) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffersARB(buffer)");
+            return;
+         }
+
+         /* From the OpenGL 3.0 specification, page 259:
+          * "If the GL is bound to the default framebuffer and DrawBuffers is
+          *  supplied with a constant (other than NONE) that does not indicate
+          *  any of the color buffers allocated to the GL context by the window
+          *  system, the error INVALID_OPERATION will be generated.
+          *
+          *  If the GL is bound to a framebuffer object and DrawBuffers is
+          *  supplied with a constant from table 4.6 [...] then the error
+          *  INVALID_OPERATION results."
+          */
          destMask[output] &= supportedMask;
          if (destMask[output] == 0) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
                         "glDrawBuffersARB(unsupported buffer)");
             return;
          }
+
+         /* ES 3.0 is even more restrictive.  From the ES 3.0 spec, page 180:
+          * "If the GL is bound to a framebuffer object, the ith buffer listed
+          *  in bufs must be COLOR_ATTACHMENTi or NONE. [...] INVALID_OPERATION."
+          */
+         if (_mesa_is_gles3(ctx) && _mesa_is_user_fbo(ctx->DrawBuffer) &&
+             buffers[output] != GL_NONE &&
+             buffers[output] != GL_COLOR_ATTACHMENT0 + output) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffers(buffer)");
+            return;
+         }
+
+         /* From the OpenGL 3.0 specification, page 258:
+          * "Except for NONE, a buffer may not appear more than once in the
+          *  array pointed to by bufs.  Specifying a buffer more then once will
+          *  result in the error INVALID_OPERATION."
+          */
          if (destMask[output] & usedBufferMask) {
-            /* can't specify a dest buffer more than once! */
             _mesa_error(ctx, GL_INVALID_OPERATION,
                         "glDrawBuffersARB(duplicated buffer)");
             return;