mesa: move glBlitFramebuffer code into new blit.c file
authorBrian Paul <brianp@vmware.com>
Sat, 1 Feb 2014 15:58:43 +0000 (08:58 -0700)
committerBrian Paul <brianp@vmware.com>
Sun, 2 Feb 2014 13:52:37 +0000 (06:52 -0700)
Just for better organization.
v2: update gl_genexec.py too (not api_exec.c)

Acked-by: Kenneth Graunke <kenneth@whitecape.org>
src/mapi/glapi/gen/gl_genexec.py
src/mesa/Makefile.sources
src/mesa/SConscript
src/mesa/main/blit.c [new file with mode: 0644]
src/mesa/main/blit.h [new file with mode: 0644]
src/mesa/main/fbobject.c
src/mesa/main/fbobject.h

index b7ac16b061ac700bd98cf29922c4c6e60bf7da43..6be3f84cf4df27cd810bd9f4f7a61d7a63951d3d 100644 (file)
@@ -51,6 +51,7 @@ header = """/**
 #include "main/atifragshader.h"
 #include "main/attrib.h"
 #include "main/blend.h"
+#include "main/blit.h"
 #include "main/bufferobj.h"
 #include "main/arrayobj.h"
 #include "main/buffers.h"
index d14823db9e18f88dcf802205ff62e4072da8b803..6a8a045fb095e2758e305c2716d8157cc1d63f71 100644 (file)
@@ -18,6 +18,7 @@ MAIN_FILES = \
        $(SRCDIR)main/attrib.c \
        $(SRCDIR)main/arrayobj.c \
        $(SRCDIR)main/blend.c \
+       $(SRCDIR)main/blit.c \
        $(SRCDIR)main/bufferobj.c \
        $(SRCDIR)main/buffers.c \
        $(SRCDIR)main/clear.c \
index 77e2aaa7ee1cdb1dfa8633fd0c8c999089449b82..4bc4de4f41a4525fb505febcf9f87eaf6c4a535c 100644 (file)
@@ -46,6 +46,7 @@ main_sources = [
     'main/attrib.c',
     'main/arrayobj.c',
     'main/blend.c',
+    'main/blit.c',
     'main/bufferobj.c',
     'main/buffers.c',
     'main/clear.c',
diff --git a/src/mesa/main/blit.c b/src/mesa/main/blit.c
new file mode 100644 (file)
index 0000000..0b70a3d
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2013  VMware, Inc.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * glBlitFramebuffer functions.
+ */
+
+#include <stdbool.h>
+
+#include "context.h"
+#include "enums.h"
+#include "blit.h"
+#include "fbobject.h"
+#include "glformats.h"
+#include "mtypes.h"
+#include "state.h"
+
+
+/** Set this to 1 to debug/log glBlitFramebuffer() calls */
+#define DEBUG_BLIT 0
+
+
+
+static const struct gl_renderbuffer_attachment *
+find_attachment(const struct gl_framebuffer *fb,
+                const struct gl_renderbuffer *rb)
+{
+   GLuint i;
+   for (i = 0; i < Elements(fb->Attachment); i++) {
+      if (fb->Attachment[i].Renderbuffer == rb)
+         return &fb->Attachment[i];
+   }
+   return NULL;
+}
+
+
+/**
+ * Helper function for checking if the datatypes of color buffers are
+ * compatible for glBlitFramebuffer.  From the 3.1 spec, page 198:
+ *
+ * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
+ *  and any of the following conditions hold:
+ *   - The read buffer contains fixed-point or floating-point values and any
+ *     draw buffer contains neither fixed-point nor floating-point values.
+ *   - The read buffer contains unsigned integer values and any draw buffer
+ *     does not contain unsigned integer values.
+ *   - The read buffer contains signed integer values and any draw buffer
+ *     does not contain signed integer values."
+ */
+static GLboolean
+compatible_color_datatypes(mesa_format srcFormat, mesa_format dstFormat)
+{
+   GLenum srcType = _mesa_get_format_datatype(srcFormat);
+   GLenum dstType = _mesa_get_format_datatype(dstFormat);
+
+   if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
+      assert(srcType == GL_UNSIGNED_NORMALIZED ||
+             srcType == GL_SIGNED_NORMALIZED ||
+             srcType == GL_FLOAT);
+      /* Boil any of those types down to GL_FLOAT */
+      srcType = GL_FLOAT;
+   }
+
+   if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
+      assert(dstType == GL_UNSIGNED_NORMALIZED ||
+             dstType == GL_SIGNED_NORMALIZED ||
+             dstType == GL_FLOAT);
+      /* Boil any of those types down to GL_FLOAT */
+      dstType = GL_FLOAT;
+   }
+
+   return srcType == dstType;
+}
+
+
+static GLboolean
+compatible_resolve_formats(const struct gl_renderbuffer *readRb,
+                           const struct gl_renderbuffer *drawRb)
+{
+   GLenum readFormat, drawFormat;
+
+   /* The simple case where we know the backing Mesa formats are the same.
+    */
+   if (_mesa_get_srgb_format_linear(readRb->Format) ==
+       _mesa_get_srgb_format_linear(drawRb->Format)) {
+      return GL_TRUE;
+   }
+
+   /* The Mesa formats are different, so we must check whether the internal
+    * formats are compatible.
+    *
+    * Under some circumstances, the user may request e.g. two GL_RGBA8
+    * textures and get two entirely different Mesa formats like RGBA8888 and
+    * ARGB8888. Drivers behaving like that should be able to cope with
+    * non-matching formats by themselves, because it's not the user's fault.
+    *
+    * Blits between linear and sRGB formats are also allowed.
+    */
+   readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat);
+   drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat);
+   readFormat = _mesa_get_linear_internalformat(readFormat);
+   drawFormat = _mesa_get_linear_internalformat(drawFormat);
+
+   if (readFormat == drawFormat) {
+      return GL_TRUE;
+   }
+
+   return GL_FALSE;
+}
+
+
+static GLboolean
+is_valid_blit_filter(const struct gl_context *ctx, GLenum filter)
+{
+   switch (filter) {
+   case GL_NEAREST:
+   case GL_LINEAR:
+      return true;
+   case GL_SCALED_RESOLVE_FASTEST_EXT:
+   case GL_SCALED_RESOLVE_NICEST_EXT:
+      return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled;
+   default:
+      return false;
+   }
+}
+
+
+/**
+ * Blit rectangular region, optionally from one framebuffer to another.
+ *
+ * Note, if the src buffer is multisampled and the dest is not, this is
+ * when the samples must be resolved to a single color.
+ */
+void GLAPIENTRY
+_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                         GLbitfield mask, GLenum filter)
+{
+   const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
+                                     GL_DEPTH_BUFFER_BIT |
+                                     GL_STENCIL_BUFFER_BIT);
+   const struct gl_framebuffer *readFb, *drawFb;
+   GET_CURRENT_CONTEXT(ctx);
+
+   FLUSH_VERTICES(ctx, 0);
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx,
+                  "glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d, 0x%x, %s)\n",
+                  srcX0, srcY0, srcX1, srcY1,
+                  dstX0, dstY0, dstX1, dstY1,
+                  mask, _mesa_lookup_enum_by_nr(filter));
+
+   if (ctx->NewState) {
+      _mesa_update_state(ctx);
+   }
+
+   readFb = ctx->ReadBuffer;
+   drawFb = ctx->DrawBuffer;
+
+   if (!readFb || !drawFb) {
+      /* This will normally never happen but someday we may want to
+       * support MakeCurrent() with no drawables.
+       */
+      return;
+   }
+
+   /* check for complete framebuffers */
+   if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
+       readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+                  "glBlitFramebufferEXT(incomplete draw/read buffers)");
+      return;
+   }
+
+   if (!is_valid_blit_filter(ctx, filter)) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)",
+                  _mesa_lookup_enum_by_nr(filter));
+      return;
+   }
+
+   if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
+        filter == GL_SCALED_RESOLVE_NICEST_EXT) &&
+        (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT(%s)",
+                  _mesa_lookup_enum_by_nr(filter));
+      return;
+   }
+
+   if (mask & ~legalMaskBits) {
+      _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
+      return;
+   }
+
+   /* depth/stencil must be blitted with nearest filtering */
+   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
+        && filter != GL_NEAREST) {
+      _mesa_error(ctx, GL_INVALID_OPERATION,
+             "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
+      return;
+   }
+
+   /* get color read/draw renderbuffers */
+   if (mask & GL_COLOR_BUFFER_BIT) {
+      const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers;
+      const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
+      const struct gl_renderbuffer *colorDrawRb = NULL;
+      GLuint i;
+
+      /* From the EXT_framebuffer_object spec:
+       *
+       *     "If a buffer is specified in <mask> and does not exist in both
+       *     the read and draw framebuffers, the corresponding bit is silently
+       *     ignored."
+       */
+      if (!colorReadRb || numColorDrawBuffers == 0) {
+         mask &= ~GL_COLOR_BUFFER_BIT;
+      }
+      else {
+         for (i = 0; i < numColorDrawBuffers; i++) {
+            colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
+            if (!colorDrawRb)
+               continue;
+
+            /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
+             * ES 3.0.1 spec says:
+             *
+             *     "If the source and destination buffers are identical, an
+             *     INVALID_OPERATION error is generated. Different mipmap
+             *     levels of a texture, different layers of a three-
+             *     dimensional texture or two-dimensional array texture, and
+             *     different faces of a cube map texture do not constitute
+             *     identical buffers."
+             */
+            if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
+               _mesa_error(ctx, GL_INVALID_OPERATION,
+                           "glBlitFramebuffer(source and destination color "
+                           "buffer cannot be the same)");
+               return;
+            }
+
+            if (!compatible_color_datatypes(colorReadRb->Format,
+                                            colorDrawRb->Format)) {
+               _mesa_error(ctx, GL_INVALID_OPERATION,
+                           "glBlitFramebufferEXT(color buffer datatypes mismatch)");
+               return;
+            }
+            /* extra checks for multisample copies... */
+            if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
+               /* color formats must match */
+               if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) {
+                  _mesa_error(ctx, GL_INVALID_OPERATION,
+                         "glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
+                  return;
+               }
+            }
+         }
+         if (filter != GL_NEAREST) {
+            /* From EXT_framebuffer_multisample_blit_scaled specification:
+             * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
+             * if filter is not NEAREST and read buffer contains integer data."
+             */
+            GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
+            if (type == GL_INT || type == GL_UNSIGNED_INT) {
+               _mesa_error(ctx, GL_INVALID_OPERATION,
+                           "glBlitFramebufferEXT(integer color type)");
+               return;
+            }
+         }
+      }
+   }
+
+   if (mask & GL_STENCIL_BUFFER_BIT) {
+      struct gl_renderbuffer *readRb =
+         readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
+      struct gl_renderbuffer *drawRb =
+         drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
+
+      /* From the EXT_framebuffer_object spec:
+       *
+       *     "If a buffer is specified in <mask> and does not exist in both
+       *     the read and draw framebuffers, the corresponding bit is silently
+       *     ignored."
+       */
+      if ((readRb == NULL) || (drawRb == NULL)) {
+        mask &= ~GL_STENCIL_BUFFER_BIT;
+      }
+      else {
+         int read_z_bits, draw_z_bits;
+
+         if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glBlitFramebuffer(source and destination stencil "
+                        "buffer cannot be the same)");
+            return;
+         }
+
+         if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
+             _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
+            /* There is no need to check the stencil datatype here, because
+             * there is only one: GL_UNSIGNED_INT.
+             */
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glBlitFramebuffer(stencil attachment format mismatch)");
+            return;
+         }
+
+         read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
+         draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);
+
+         /* If both buffers also have depth data, the depth formats must match
+          * as well.  If one doesn't have depth, it's not blitted, so we should
+          * ignore the depth format check.
+          */
+         if (read_z_bits > 0 && draw_z_bits > 0 &&
+             (read_z_bits != draw_z_bits ||
+              _mesa_get_format_datatype(readRb->Format) !=
+              _mesa_get_format_datatype(drawRb->Format))) {
+
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
+                        "(stencil attachment depth format mismatch)");
+            return;
+         }
+      }
+   }
+
+   if (mask & GL_DEPTH_BUFFER_BIT) {
+      struct gl_renderbuffer *readRb =
+         readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
+      struct gl_renderbuffer *drawRb =
+         drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
+
+      /* From the EXT_framebuffer_object spec:
+       *
+       *     "If a buffer is specified in <mask> and does not exist in both
+       *     the read and draw framebuffers, the corresponding bit is silently
+       *     ignored."
+       */
+      if ((readRb == NULL) || (drawRb == NULL)) {
+        mask &= ~GL_DEPTH_BUFFER_BIT;
+      }
+      else {
+         int read_s_bit, draw_s_bit;
+
+         if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glBlitFramebuffer(source and destination depth "
+                        "buffer cannot be the same)");
+            return;
+         }
+
+         if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
+              _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
+             (_mesa_get_format_datatype(readRb->Format) !=
+              _mesa_get_format_datatype(drawRb->Format))) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glBlitFramebuffer(depth attachment format mismatch)");
+            return;
+         }
+
+         read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
+         draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);
+
+         /* If both buffers also have stencil data, the stencil formats must
+          * match as well.  If one doesn't have stencil, it's not blitted, so
+          * we should ignore the stencil format check.
+          */
+         if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
+            _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
+                        "(depth attachment stencil bits mismatch)");
+            return;
+         }
+      }
+   }
+
+
+   if (_mesa_is_gles3(ctx)) {
+      /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
+       * 3.0.1 spec says:
+       *
+       *     "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
+       *     an INVALID_OPERATION error is generated."
+       */
+      if (drawFb->Visual.samples > 0) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glBlitFramebuffer(destination samples must be 0)");
+         return;
+      }
+
+      /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
+       * 3.0.1 spec says:
+       *
+       *     "If SAMPLE_BUFFERS for the read framebuffer is greater than zero,
+       *     no copy is performed and an INVALID_OPERATION error is generated
+       *     if the formats of the read and draw framebuffers are not
+       *     identical or if the source and destination rectangles are not
+       *     defined with the same (X0, Y0) and (X1, Y1) bounds."
+       *
+       * The format check was made above because desktop OpenGL has the same
+       * requirement.
+       */
+      if (readFb->Visual.samples > 0
+          && (srcX0 != dstX0 || srcY0 != dstY0
+              || srcX1 != dstX1 || srcY1 != dstY1)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glBlitFramebuffer(bad src/dst multisample region)");
+         return;
+      }
+   } else {
+      if (readFb->Visual.samples > 0 &&
+          drawFb->Visual.samples > 0 &&
+          readFb->Visual.samples != drawFb->Visual.samples) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glBlitFramebufferEXT(mismatched samples)");
+         return;
+      }
+
+      /* extra checks for multisample copies... */
+      if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) &&
+          (filter == GL_NEAREST || filter == GL_LINEAR)) {
+         /* src and dest region sizes must be the same */
+         if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
+             abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "glBlitFramebufferEXT(bad src/dst multisample region sizes)");
+            return;
+         }
+      }
+   }
+
+   /* Debug code */
+   if (DEBUG_BLIT) {
+      const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
+      const struct gl_renderbuffer *colorDrawRb = NULL;
+      GLuint i = 0;
+
+      printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
+            " 0x%x, 0x%x)\n",
+            srcX0, srcY0, srcX1, srcY1,
+            dstX0, dstY0, dstX1, dstY1,
+            mask, filter);
+      if (colorReadRb) {
+         const struct gl_renderbuffer_attachment *att;
+
+         att = find_attachment(readFb, colorReadRb);
+         printf("  Src FBO %u  RB %u (%dx%d)  ",
+               readFb->Name, colorReadRb->Name,
+               colorReadRb->Width, colorReadRb->Height);
+         if (att && att->Texture) {
+            printf("Tex %u  tgt 0x%x  level %u  face %u",
+                  att->Texture->Name,
+                  att->Texture->Target,
+                  att->TextureLevel,
+                  att->CubeMapFace);
+         }
+         printf("\n");
+
+         /* Print all active color render buffers */
+         for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
+            colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
+            if (!colorDrawRb)
+               continue;
+
+            att = find_attachment(drawFb, colorDrawRb);
+            printf("  Dst FBO %u  RB %u (%dx%d)  ",
+                  drawFb->Name, colorDrawRb->Name,
+                  colorDrawRb->Width, colorDrawRb->Height);
+            if (att && att->Texture) {
+               printf("Tex %u  tgt 0x%x  level %u  face %u",
+                     att->Texture->Name,
+                     att->Texture->Target,
+                     att->TextureLevel,
+                     att->CubeMapFace);
+            }
+            printf("\n");
+         }
+      }
+   }
+
+   if (!mask ||
+       (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
+       (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
+      return;
+   }
+
+   ASSERT(ctx->Driver.BlitFramebuffer);
+   ctx->Driver.BlitFramebuffer(ctx,
+                               srcX0, srcY0, srcX1, srcY1,
+                               dstX0, dstY0, dstX1, dstY1,
+                               mask, filter);
+}
diff --git a/src/mesa/main/blit.h b/src/mesa/main/blit.h
new file mode 100644 (file)
index 0000000..533d6e5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef BLIT_H
+#define BLIT_H
+
+#include "compiler.h"
+#include "glheader.h"
+
+
+extern void GLAPIENTRY
+_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                         GLbitfield mask, GLenum filter);
+
+
+#endif /* BLIT_H */
index b5b55fc83d1ab7226b061d0b35ae7c89b2280063..7a1761f0237f37127dca46cdd141ba5c09107b48 100644 (file)
 #include "texobj.h"
 
 
-/** Set this to 1 to debug/log glBlitFramebuffer() calls */
-#define DEBUG_BLIT 0
-
-
 /**
  * Notes:
  *
@@ -3069,475 +3065,6 @@ _mesa_GenerateMipmap(GLenum target)
    _mesa_unlock_texture(ctx, texObj);
 }
 
-
-static const struct gl_renderbuffer_attachment *
-find_attachment(const struct gl_framebuffer *fb,
-                const struct gl_renderbuffer *rb)
-{
-   GLuint i;
-   for (i = 0; i < Elements(fb->Attachment); i++) {
-      if (fb->Attachment[i].Renderbuffer == rb)
-         return &fb->Attachment[i];
-   }
-   return NULL;
-}
-
-
-/**
- * Helper function for checking if the datatypes of color buffers are
- * compatible for glBlitFramebuffer.  From the 3.1 spec, page 198:
- *
- * "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
- *  and any of the following conditions hold:
- *   - The read buffer contains fixed-point or floating-point values and any
- *     draw buffer contains neither fixed-point nor floating-point values.
- *   - The read buffer contains unsigned integer values and any draw buffer
- *     does not contain unsigned integer values.
- *   - The read buffer contains signed integer values and any draw buffer
- *     does not contain signed integer values."
- */
-static GLboolean
-compatible_color_datatypes(mesa_format srcFormat, mesa_format dstFormat)
-{
-   GLenum srcType = _mesa_get_format_datatype(srcFormat);
-   GLenum dstType = _mesa_get_format_datatype(dstFormat);
-
-   if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
-      assert(srcType == GL_UNSIGNED_NORMALIZED ||
-             srcType == GL_SIGNED_NORMALIZED ||
-             srcType == GL_FLOAT);
-      /* Boil any of those types down to GL_FLOAT */
-      srcType = GL_FLOAT;
-   }
-
-   if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
-      assert(dstType == GL_UNSIGNED_NORMALIZED ||
-             dstType == GL_SIGNED_NORMALIZED ||
-             dstType == GL_FLOAT);
-      /* Boil any of those types down to GL_FLOAT */
-      dstType = GL_FLOAT;
-   }
-
-   return srcType == dstType;
-}
-
-
-static GLboolean
-compatible_resolve_formats(const struct gl_renderbuffer *readRb,
-                           const struct gl_renderbuffer *drawRb)
-{
-   GLenum readFormat, drawFormat;
-
-   /* The simple case where we know the backing Mesa formats are the same.
-    */
-   if (_mesa_get_srgb_format_linear(readRb->Format) ==
-       _mesa_get_srgb_format_linear(drawRb->Format)) {
-      return GL_TRUE;
-   }
-
-   /* The Mesa formats are different, so we must check whether the internal
-    * formats are compatible.
-    *
-    * Under some circumstances, the user may request e.g. two GL_RGBA8
-    * textures and get two entirely different Mesa formats like RGBA8888 and
-    * ARGB8888. Drivers behaving like that should be able to cope with
-    * non-matching formats by themselves, because it's not the user's fault.
-    *
-    * Blits between linear and sRGB formats are also allowed.
-    */
-   readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat);
-   drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat);
-   readFormat = _mesa_get_linear_internalformat(readFormat);
-   drawFormat = _mesa_get_linear_internalformat(drawFormat);
-
-   if (readFormat == drawFormat) {
-      return GL_TRUE;
-   }
-
-   return GL_FALSE;
-}
-
-static GLboolean
-is_valid_blit_filter(const struct gl_context *ctx, GLenum filter)
-{
-   switch (filter) {
-   case GL_NEAREST:
-   case GL_LINEAR:
-      return true;
-   case GL_SCALED_RESOLVE_FASTEST_EXT:
-   case GL_SCALED_RESOLVE_NICEST_EXT:
-      return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled;
-   default:
-      return false;
-   }
-}
-
-/**
- * Blit rectangular region, optionally from one framebuffer to another.
- *
- * Note, if the src buffer is multisampled and the dest is not, this is
- * when the samples must be resolved to a single color.
- */
-void GLAPIENTRY
-_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
-                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
-                         GLbitfield mask, GLenum filter)
-{
-   const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
-                                     GL_DEPTH_BUFFER_BIT |
-                                     GL_STENCIL_BUFFER_BIT);
-   const struct gl_framebuffer *readFb, *drawFb;
-   GET_CURRENT_CONTEXT(ctx);
-
-   FLUSH_VERTICES(ctx, 0);
-
-   if (MESA_VERBOSE & VERBOSE_API)
-      _mesa_debug(ctx,
-                  "glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d, 0x%x, %s)\n",
-                  srcX0, srcY0, srcX1, srcY1,
-                  dstX0, dstY0, dstX1, dstY1,
-                  mask, _mesa_lookup_enum_by_nr(filter));
-
-   if (ctx->NewState) {
-      _mesa_update_state(ctx);
-   }
-
-   readFb = ctx->ReadBuffer;
-   drawFb = ctx->DrawBuffer;
-
-   if (!readFb || !drawFb) {
-      /* This will normally never happen but someday we may want to
-       * support MakeCurrent() with no drawables.
-       */
-      return;
-   }
-
-   /* check for complete framebuffers */
-   if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
-       readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
-      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
-                  "glBlitFramebufferEXT(incomplete draw/read buffers)");
-      return;
-   }
-
-   if (!is_valid_blit_filter(ctx, filter)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)",
-                  _mesa_lookup_enum_by_nr(filter));
-      return;
-   }
-
-   if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
-        filter == GL_SCALED_RESOLVE_NICEST_EXT) &&
-        (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) {
-      _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT(%s)",
-                  _mesa_lookup_enum_by_nr(filter));
-      return;
-   }
-
-   if (mask & ~legalMaskBits) {
-      _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
-      return;
-   }
-
-   /* depth/stencil must be blitted with nearest filtering */
-   if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
-        && filter != GL_NEAREST) {
-      _mesa_error(ctx, GL_INVALID_OPERATION,
-             "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
-      return;
-   }
-
-   /* get color read/draw renderbuffers */
-   if (mask & GL_COLOR_BUFFER_BIT) {
-      const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers;
-      const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
-      const struct gl_renderbuffer *colorDrawRb = NULL;
-      GLuint i;
-
-      /* From the EXT_framebuffer_object spec:
-       *
-       *     "If a buffer is specified in <mask> and does not exist in both
-       *     the read and draw framebuffers, the corresponding bit is silently
-       *     ignored."
-       */
-      if (!colorReadRb || numColorDrawBuffers == 0) {
-         mask &= ~GL_COLOR_BUFFER_BIT;
-      }
-      else {
-         for (i = 0; i < numColorDrawBuffers; i++) {
-            colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
-            if (!colorDrawRb)
-               continue;
-
-            /* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
-             * ES 3.0.1 spec says:
-             *
-             *     "If the source and destination buffers are identical, an
-             *     INVALID_OPERATION error is generated. Different mipmap
-             *     levels of a texture, different layers of a three-
-             *     dimensional texture or two-dimensional array texture, and
-             *     different faces of a cube map texture do not constitute
-             *     identical buffers."
-             */
-            if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
-               _mesa_error(ctx, GL_INVALID_OPERATION,
-                           "glBlitFramebuffer(source and destination color "
-                           "buffer cannot be the same)");
-               return;
-            }
-
-            if (!compatible_color_datatypes(colorReadRb->Format,
-                                            colorDrawRb->Format)) {
-               _mesa_error(ctx, GL_INVALID_OPERATION,
-                           "glBlitFramebufferEXT(color buffer datatypes mismatch)");
-               return;
-            }
-            /* extra checks for multisample copies... */
-            if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
-               /* color formats must match */
-               if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) {
-                  _mesa_error(ctx, GL_INVALID_OPERATION,
-                         "glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
-                  return;
-               }
-            }
-         }
-         if (filter != GL_NEAREST) {
-            /* From EXT_framebuffer_multisample_blit_scaled specification:
-             * "Calling BlitFramebuffer will result in an INVALID_OPERATION error
-             * if filter is not NEAREST and read buffer contains integer data."
-             */
-            GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
-            if (type == GL_INT || type == GL_UNSIGNED_INT) {
-               _mesa_error(ctx, GL_INVALID_OPERATION,
-                           "glBlitFramebufferEXT(integer color type)");
-               return;
-            }
-         }
-      }
-   }
-
-   if (mask & GL_STENCIL_BUFFER_BIT) {
-      struct gl_renderbuffer *readRb =
-         readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
-      struct gl_renderbuffer *drawRb =
-         drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
-
-      /* From the EXT_framebuffer_object spec:
-       *
-       *     "If a buffer is specified in <mask> and does not exist in both
-       *     the read and draw framebuffers, the corresponding bit is silently
-       *     ignored."
-       */
-      if ((readRb == NULL) || (drawRb == NULL)) {
-        mask &= ~GL_STENCIL_BUFFER_BIT;
-      }
-      else {
-         int read_z_bits, draw_z_bits;
-
-         if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glBlitFramebuffer(source and destination stencil "
-                        "buffer cannot be the same)");
-            return;
-         }
-
-         if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
-             _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
-            /* There is no need to check the stencil datatype here, because
-             * there is only one: GL_UNSIGNED_INT.
-             */
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glBlitFramebuffer(stencil attachment format mismatch)");
-            return;
-         }
-
-         read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
-         draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);
-
-         /* If both buffers also have depth data, the depth formats must match
-          * as well.  If one doesn't have depth, it's not blitted, so we should
-          * ignore the depth format check.
-          */
-         if (read_z_bits > 0 && draw_z_bits > 0 &&
-             (read_z_bits != draw_z_bits ||
-              _mesa_get_format_datatype(readRb->Format) !=
-              _mesa_get_format_datatype(drawRb->Format))) {
-
-            _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
-                        "(stencil attachment depth format mismatch)");
-            return;
-         }
-      }
-   }
-
-   if (mask & GL_DEPTH_BUFFER_BIT) {
-      struct gl_renderbuffer *readRb =
-         readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
-      struct gl_renderbuffer *drawRb =
-         drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
-
-      /* From the EXT_framebuffer_object spec:
-       *
-       *     "If a buffer is specified in <mask> and does not exist in both
-       *     the read and draw framebuffers, the corresponding bit is silently
-       *     ignored."
-       */
-      if ((readRb == NULL) || (drawRb == NULL)) {
-        mask &= ~GL_DEPTH_BUFFER_BIT;
-      }
-      else {
-         int read_s_bit, draw_s_bit;
-
-         if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glBlitFramebuffer(source and destination depth "
-                        "buffer cannot be the same)");
-            return;
-         }
-
-         if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
-              _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
-             (_mesa_get_format_datatype(readRb->Format) !=
-              _mesa_get_format_datatype(drawRb->Format))) {
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glBlitFramebuffer(depth attachment format mismatch)");
-            return;
-         }
-
-         read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
-         draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);
-
-         /* If both buffers also have stencil data, the stencil formats must
-          * match as well.  If one doesn't have stencil, it's not blitted, so
-          * we should ignore the stencil format check.
-          */
-         if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
-            _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
-                        "(depth attachment stencil bits mismatch)");
-            return;
-         }
-      }
-   }
-
-
-   if (_mesa_is_gles3(ctx)) {
-      /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
-       * 3.0.1 spec says:
-       *
-       *     "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
-       *     an INVALID_OPERATION error is generated."
-       */
-      if (drawFb->Visual.samples > 0) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glBlitFramebuffer(destination samples must be 0)");
-         return;
-      }
-
-      /* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
-       * 3.0.1 spec says:
-       *
-       *     "If SAMPLE_BUFFERS for the read framebuffer is greater than zero,
-       *     no copy is performed and an INVALID_OPERATION error is generated
-       *     if the formats of the read and draw framebuffers are not
-       *     identical or if the source and destination rectangles are not
-       *     defined with the same (X0, Y0) and (X1, Y1) bounds."
-       *
-       * The format check was made above because desktop OpenGL has the same
-       * requirement.
-       */
-      if (readFb->Visual.samples > 0
-          && (srcX0 != dstX0 || srcY0 != dstY0
-              || srcX1 != dstX1 || srcY1 != dstY1)) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glBlitFramebuffer(bad src/dst multisample region)");
-         return;
-      }
-   } else {
-      if (readFb->Visual.samples > 0 &&
-          drawFb->Visual.samples > 0 &&
-          readFb->Visual.samples != drawFb->Visual.samples) {
-         _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glBlitFramebufferEXT(mismatched samples)");
-         return;
-      }
-
-      /* extra checks for multisample copies... */
-      if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) &&
-          (filter == GL_NEAREST || filter == GL_LINEAR)) {
-         /* src and dest region sizes must be the same */
-         if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
-             abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
-            _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glBlitFramebufferEXT(bad src/dst multisample region sizes)");
-            return;
-         }
-      }
-   }
-
-   /* Debug code */
-   if (DEBUG_BLIT) {
-      const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
-      const struct gl_renderbuffer *colorDrawRb = NULL;
-      GLuint i = 0;
-
-      printf("glBlitFramebuffer(%d, %d, %d, %d,  %d, %d, %d, %d,"
-            " 0x%x, 0x%x)\n",
-            srcX0, srcY0, srcX1, srcY1,
-            dstX0, dstY0, dstX1, dstY1,
-            mask, filter);
-      if (colorReadRb) {
-         const struct gl_renderbuffer_attachment *att;
-
-         att = find_attachment(readFb, colorReadRb);
-         printf("  Src FBO %u  RB %u (%dx%d)  ",
-               readFb->Name, colorReadRb->Name,
-               colorReadRb->Width, colorReadRb->Height);
-         if (att && att->Texture) {
-            printf("Tex %u  tgt 0x%x  level %u  face %u",
-                  att->Texture->Name,
-                  att->Texture->Target,
-                  att->TextureLevel,
-                  att->CubeMapFace);
-         }
-         printf("\n");
-
-         /* Print all active color render buffers */
-         for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
-            colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
-            if (!colorDrawRb)
-               continue;
-
-            att = find_attachment(drawFb, colorDrawRb);
-            printf("  Dst FBO %u  RB %u (%dx%d)  ",
-                  drawFb->Name, colorDrawRb->Name,
-                  colorDrawRb->Width, colorDrawRb->Height);
-            if (att && att->Texture) {
-               printf("Tex %u  tgt 0x%x  level %u  face %u",
-                     att->Texture->Name,
-                     att->Texture->Target,
-                     att->TextureLevel,
-                     att->CubeMapFace);
-            }
-            printf("\n");
-         }
-      }
-   }
-
-   if (!mask ||
-       (srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
-       (dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
-      return;
-   }
-
-   ASSERT(ctx->Driver.BlitFramebuffer);
-   ctx->Driver.BlitFramebuffer(ctx,
-                               srcX0, srcY0, srcX1, srcY1,
-                               dstX0, dstY0, dstX1, dstY1,
-                               mask, filter);
-}
-
-
 static void
 invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments,
                                const GLenum *attachments, GLint x, GLint y,
index ab138cfff84dd9ab7dc9d99e4eec82e9a5363fab..1f5aa34ef74e46f7cb5a4f88d07885052344469e 100644 (file)
@@ -206,11 +206,6 @@ extern void GLAPIENTRY
 _mesa_GenerateMipmap(GLenum target);
 
 
-extern void GLAPIENTRY
-_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
-                         GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
-                         GLbitfield mask, GLenum filter);
-
 extern void GLAPIENTRY
 _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
                                const GLenum *attachments, GLint x, GLint y,