mesa: Move check for vbo mapping into api_validate.c.
[mesa.git] / src / mesa / main / blit.c
index b244c8de8468e858fab4e473f4d0e9f209222804..e739130f98491bb1c901e6caeccd05cd52c9b4eb 100644 (file)
  */
 
 #include <stdbool.h>
+#include <stdio.h>
 
 #include "context.h"
 #include "enums.h"
 #include "blit.h"
 #include "fbobject.h"
+#include "framebuffer.h"
 #include "glformats.h"
 #include "mtypes.h"
+#include "macros.h"
 #include "state.h"
 
 
@@ -48,7 +51,7 @@ find_attachment(const struct gl_framebuffer *fb,
                 const struct gl_renderbuffer *rb)
 {
    GLuint i;
-   for (i = 0; i < Elements(fb->Attachment); i++) {
+   for (i = 0; i < ARRAY_SIZE(fb->Attachment); i++) {
       if (fb->Attachment[i].Renderbuffer == rb)
          return &fb->Attachment[i];
    }
@@ -56,6 +59,31 @@ find_attachment(const struct gl_framebuffer *fb,
 }
 
 
+/**
+ * \return true if two regions overlap, false otherwise
+ */
+bool
+_mesa_regions_overlap(int srcX0, int srcY0,
+                      int srcX1, int srcY1,
+                      int dstX0, int dstY0,
+                      int dstX1, int dstY1)
+{
+   if (MAX2(srcX0, srcX1) <= MIN2(dstX0, dstX1))
+      return false; /* dst completely right of src */
+
+   if (MAX2(dstX0, dstX1) <= MIN2(srcX0, srcX1))
+      return false; /* dst completely left of src */
+
+   if (MAX2(srcY0, srcY1) <= MIN2(dstY0, dstY1))
+      return false; /* dst completely above src */
+
+   if (MAX2(dstY0, dstY1) <= MIN2(srcY0, srcY1))
+      return false; /* dst completely below src */
+
+   return true; /* some overlap */
+}
+
+
 /**
  * Helper function for checking if the datatypes of color buffers are
  * compatible for glBlitFramebuffer.  From the 3.1 spec, page 198:
@@ -101,20 +129,22 @@ compatible_resolve_formats(const struct gl_renderbuffer *readRb,
 {
    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.
+   /* This checks whether the internal formats are compatible rather than the
+    * Mesa format for two reasons:
     *
-    * 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.
+    * • 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.
+    *
+    * • Picking two different internal formats can end up with the same Mesa
+    *   format. For example the driver might be simulating GL_RGB textures
+    *   with GL_RGBA internally and in that case both internal formats would
+    *   end up with RGBA8888.
+    *
+    * This function is used to generate a GL error according to the spec so in
+    * both cases we want to be looking at the application-level format, which
+    * is InternalFormat.
     *
     * Blits between linear and sRGB formats are also allowed.
     */
@@ -147,38 +177,25 @@ is_valid_blit_filter(const struct gl_context *ctx, GLenum filter)
 }
 
 
-/**
- * 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)
+void
+_mesa_blit_framebuffer(struct gl_context *ctx,
+                       struct gl_framebuffer *readFb,
+                       struct gl_framebuffer *drawFb,
+                       GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                       GLbitfield mask, GLenum filter, const char *func)
 {
    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);
-   }
+   /* Update completeness status of readFb and drawFb. */
+   _mesa_update_framebuffer(ctx, readFb, drawFb);
 
-   readFb = ctx->ReadBuffer;
-   drawFb = ctx->DrawBuffer;
+   /* Make sure drawFb has an initialized bounding box. */
+   _mesa_update_draw_buffer_bounds(ctx, drawFb);
 
    if (!readFb || !drawFb) {
       /* This will normally never happen but someday we may want to
@@ -191,26 +208,26 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    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)");
+                  "%s(incomplete draw/read buffers)", func);
       return;
    }
 
    if (!is_valid_blit_filter(ctx, filter)) {
-      _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)",
-                  _mesa_lookup_enum_by_nr(filter));
+      _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid filter %s)", func,
+                  _mesa_enum_to_string(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));
+      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s: invalid samples)", func,
+                  _mesa_enum_to_string(filter));
       return;
    }
 
    if (mask & ~legalMaskBits) {
-      _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
+      _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid mask bits set)", func);
       return;
    }
 
@@ -218,13 +235,13 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    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)");
+             "%s(depth/stencil requires GL_NEAREST filter)", func);
       return;
    }
 
    /* get color read/draw renderbuffers */
    if (mask & GL_COLOR_BUFFER_BIT) {
-      const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers;
+      const GLuint numColorDrawBuffers = drawFb->_NumColorDrawBuffers;
       const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
       const struct gl_renderbuffer *colorDrawRb = NULL;
       GLuint i;
@@ -240,7 +257,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
       }
       else {
          for (i = 0; i < numColorDrawBuffers; i++) {
-            colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
+            colorDrawRb = drawFb->_ColorDrawBuffers[i];
             if (!colorDrawRb)
                continue;
 
@@ -256,23 +273,32 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
              */
             if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
                _mesa_error(ctx, GL_INVALID_OPERATION,
-                           "glBlitFramebuffer(source and destination color "
-                           "buffer cannot be the same)");
+                           "%s(source and destination color "
+                           "buffer cannot be the same)", func);
                return;
             }
 
             if (!compatible_color_datatypes(colorReadRb->Format,
                                             colorDrawRb->Format)) {
                _mesa_error(ctx, GL_INVALID_OPERATION,
-                           "glBlitFramebufferEXT(color buffer datatypes mismatch)");
+                           "%s(color buffer datatypes mismatch)", func);
                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)) {
+               /* color formats must match on GLES. This isn't checked on
+                * desktop GL because the GL 4.4 spec was changed to allow it.
+                * In the section entitled “Changes in the released
+                * Specification of July 22, 2013” it says:
+                *
+                * “Relax BlitFramebuffer in section 18.3.1 so that format
+                *  conversion can take place during multisample blits, since
+                *  drivers already allow this and some apps depend on it.”
+                */
+               if (_mesa_is_gles(ctx) &&
+                   !compatible_resolve_formats(colorReadRb, colorDrawRb)) {
                   _mesa_error(ctx, GL_INVALID_OPERATION,
-                         "glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
+                         "%s(bad src/dst multisample pixel formats)", func);
                   return;
                }
             }
@@ -285,7 +311,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
             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)");
+                           "%s(integer color type)", func);
                return;
             }
          }
@@ -305,15 +331,15 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
        *     ignored."
        */
       if ((readRb == NULL) || (drawRb == NULL)) {
-        mask &= ~GL_STENCIL_BUFFER_BIT;
+         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)");
+                        "%s(source and destination stencil "
+                        "buffer cannot be the same)", func);
             return;
          }
 
@@ -323,7 +349,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
              * there is only one: GL_UNSIGNED_INT.
              */
             _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glBlitFramebuffer(stencil attachment format mismatch)");
+                        "%s(stencil attachment format mismatch)", func);
             return;
          }
 
@@ -339,8 +365,8 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
               _mesa_get_format_datatype(readRb->Format) !=
               _mesa_get_format_datatype(drawRb->Format))) {
 
-            _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
-                        "(stencil attachment depth format mismatch)");
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "%s(stencil attachment depth format mismatch)", func);
             return;
          }
       }
@@ -359,15 +385,15 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
        *     ignored."
        */
       if ((readRb == NULL) || (drawRb == NULL)) {
-        mask &= ~GL_DEPTH_BUFFER_BIT;
+         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)");
+                        "%s(source and destination depth "
+                        "buffer cannot be the same)", func);
             return;
          }
 
@@ -376,7 +402,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
              (_mesa_get_format_datatype(readRb->Format) !=
               _mesa_get_format_datatype(drawRb->Format))) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
-                        "glBlitFramebuffer(depth attachment format mismatch)");
+                        "%s(depth attachment format mismatch)", func);
             return;
          }
 
@@ -388,8 +414,8 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
           * 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)");
+            _mesa_error(ctx, GL_INVALID_OPERATION,
+                        "%s(depth attachment stencil bits mismatch)", func);
             return;
          }
       }
@@ -405,7 +431,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
        */
       if (drawFb->Visual.samples > 0) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glBlitFramebuffer(destination samples must be 0)");
+                     "%s(destination samples must be 0)", func);
          return;
       }
 
@@ -425,7 +451,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
           && (srcX0 != dstX0 || srcY0 != dstY0
               || srcX1 != dstX1 || srcY1 != dstY1)) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glBlitFramebuffer(bad src/dst multisample region)");
+                     "%s(bad src/dst multisample region)", func);
          return;
       }
    } else {
@@ -433,7 +459,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
           drawFb->Visual.samples > 0 &&
           readFb->Visual.samples != drawFb->Visual.samples) {
          _mesa_error(ctx, GL_INVALID_OPERATION,
-                     "glBlitFramebufferEXT(mismatched samples)");
+                     "%s(mismatched samples)", func);
          return;
       }
 
@@ -444,7 +470,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
          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)");
+                        "%s(bad src/dst multisample region sizes)", func);
             return;
          }
       }
@@ -456,43 +482,44 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
       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);
+      printf("%s(%d, %d, %d, %d,  %d, %d, %d, %d,"
+             " 0x%x, 0x%x)\n", func,
+             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);
+                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);
+                   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];
+         for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
+            colorDrawRb = drawFb->_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);
+                   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);
+                      att->Texture->Name,
+                      att->Texture->Target,
+                      att->TextureLevel,
+                      att->CubeMapFace);
             }
             printf("\n");
          }
@@ -506,8 +533,87 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
    }
 
    assert(ctx->Driver.BlitFramebuffer);
-   ctx->Driver.BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
+   ctx->Driver.BlitFramebuffer(ctx, readFb, drawFb,
                                srcX0, srcY0, srcX1, srcY1,
                                dstX0, dstY0, dstX1, dstY1,
                                mask, filter);
 }
+
+
+/**
+ * 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)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   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_enum_to_string(filter));
+
+   _mesa_blit_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
+                          srcX0, srcY0, srcX1, srcY1,
+                          dstX0, dstY0, dstX1, dstY1,
+                          mask, filter, "glBlitFramebuffer");
+}
+
+
+void GLAPIENTRY
+_mesa_BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer,
+                           GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+                           GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+                           GLbitfield mask, GLenum filter)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct gl_framebuffer *readFb, *drawFb;
+
+   if (MESA_VERBOSE & VERBOSE_API)
+      _mesa_debug(ctx,
+                  "glBlitNamedFramebuffer(%u %u %d, %d, %d, %d, "
+                  " %d, %d, %d, %d, 0x%x, %s)\n",
+                  readFramebuffer, drawFramebuffer,
+                  srcX0, srcY0, srcX1, srcY1,
+                  dstX0, dstY0, dstX1, dstY1,
+                  mask, _mesa_enum_to_string(filter));
+
+   /*
+    * According to PDF page 533 of the OpenGL 4.5 core spec (30.10.2014,
+    * Section 18.3 Copying Pixels):
+    *   "... if readFramebuffer or drawFramebuffer is zero (for
+    *   BlitNamedFramebuffer), then the default read or draw framebuffer is
+    *   used as the corresponding source or destination framebuffer,
+    *   respectively."
+    */
+   if (readFramebuffer) {
+      readFb = _mesa_lookup_framebuffer_err(ctx, readFramebuffer,
+                                            "glBlitNamedFramebuffer");
+      if (!readFb)
+         return;
+   }
+   else
+      readFb = ctx->WinSysReadBuffer;
+
+   if (drawFramebuffer) {
+      drawFb = _mesa_lookup_framebuffer_err(ctx, drawFramebuffer,
+                                            "glBlitNamedFramebuffer");
+      if (!drawFb)
+         return;
+   }
+   else
+      drawFb = ctx->WinSysDrawBuffer;
+
+   _mesa_blit_framebuffer(ctx, readFb, drawFb,
+                          srcX0, srcY0, srcX1, srcY1,
+                          dstX0, dstY0, dstX1, dstY1,
+                          mask, filter, "glBlitNamedFramebuffer");
+}