drivers/meta: Accept GL_TEXTURE_3D as target for tex image decompression
[mesa.git] / src / mesa / drivers / common / meta_copy_image.c
index 149ed18503cae0e5c3659b0f769bcde74f42e9a7..e1c90a372d2d6317d584120100910049b2b26398 100644 (file)
 #include "teximage.h"
 #include "texobj.h"
 #include "fbobject.h"
+#include "framebuffer.h"
 #include "buffers.h"
 #include "state.h"
 #include "mtypes.h"
 #include "meta.h"
 
+/**
+ * Create a texture image that wraps a renderbuffer.
+ */
+static struct gl_texture_image *
+wrap_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
+{
+   GLenum texTarget;
+   struct gl_texture_object *texObj;
+   struct gl_texture_image *texImage;
+
+   if (rb->NumSamples > 1)
+      texTarget = GL_TEXTURE_2D_MULTISAMPLE;
+   else
+      texTarget = GL_TEXTURE_2D;
+
+   /* Texture ID is not significant since it never goes into the hash table */
+   texObj = ctx->Driver.NewTextureObject(ctx, 0, texTarget);
+   assert(texObj);
+   if (!texObj)
+      return NULL;
+
+   texImage = _mesa_get_tex_image(ctx, texObj, texTarget, 0);
+   assert(texImage);
+   if (!texImage)
+      return NULL;
+
+   if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) {
+      _mesa_problem(ctx, "Failed to create texture from renderbuffer");
+      return NULL;
+   }
+
+   if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
+      rb->NeedsFinishRenderTexture = true;
+      ctx->Driver.FinishRenderTexture(ctx, rb);
+   }
+
+   return texImage;
+}
+
+
 /* This function makes a texture view without bothering with all of the API
  * checks.  Most of them are the same for CopyTexSubImage so checking would
  * be redundant.  The one major difference is that we don't check for
@@ -60,15 +101,19 @@ make_view(struct gl_context *ctx, struct gl_texture_image *tex_image,
                                            0, internal_format,
                                            GL_NONE, GL_NONE);
 
-   if (!ctx->Driver.TestProxyTexImage(ctx, tex_obj->Target, 0, tex_format,
-                                      tex_image->Width, tex_image->Height,
-                                      tex_image->Depth, 0)) {
+   if (!ctx->Driver.TestProxyTexImage(ctx, tex_obj->Target, 1, 0, tex_format,
+                                      1, tex_image->Width, tex_image->Height,
+                                      tex_image->Depth)) {
       _mesa_DeleteTextures(1, view_tex_name);
       *view_tex_name = 0;
       return false;
    }
 
+   assert(tex_obj->Target != 0);
+   assert(tex_obj->TargetIndex < NUM_TEXTURE_TARGETS);
+
    view_tex_obj->Target = tex_obj->Target;
+   view_tex_obj->TargetIndex = tex_obj->TargetIndex;
 
    *view_tex_image = _mesa_get_tex_image(ctx, view_tex_obj, tex_obj->Target, 0);
 
@@ -89,7 +134,6 @@ make_view(struct gl_context *ctx, struct gl_texture_image *tex_image,
    view_tex_obj->NumLayers = tex_obj->NumLayers;
    view_tex_obj->Immutable = tex_obj->Immutable;
    view_tex_obj->ImmutableLevels = tex_obj->ImmutableLevels;
-   view_tex_obj->Target = tex_obj->Target;
 
    if (ctx->Driver.TextureView != NULL &&
        !ctx->Driver.TextureView(ctx, view_tex_obj, tex_obj)) {
@@ -112,40 +156,73 @@ make_view(struct gl_context *ctx, struct gl_texture_image *tex_image,
 bool
 _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx,
                                          struct gl_texture_image *src_tex_image,
+                                         struct gl_renderbuffer *src_renderbuffer,
                                          int src_x, int src_y, int src_z,
                                          struct gl_texture_image *dst_tex_image,
+                                         struct gl_renderbuffer *dst_renderbuffer,
                                          int dst_x, int dst_y, int dst_z,
                                          int src_width, int src_height)
 {
+   mesa_format src_format, dst_format;
+   GLint src_internal_format, dst_internal_format;
    GLuint src_view_texture = 0;
    struct gl_texture_image *src_view_tex_image;
-   GLuint fbos[2];
+   struct gl_framebuffer *readFb;
+   struct gl_framebuffer *drawFb = NULL;
    bool success = false;
    GLbitfield mask;
    GLenum status, attachment;
 
-   if (_mesa_is_format_compressed(dst_tex_image->TexFormat))
+   if (src_renderbuffer) {
+      src_format = src_renderbuffer->Format;
+      src_internal_format = src_renderbuffer->InternalFormat;
+   } else {
+      assert(src_tex_image);
+      src_format = src_tex_image->TexFormat;
+      src_internal_format = src_tex_image->InternalFormat;
+   }
+
+   if (dst_renderbuffer) {
+      dst_format = dst_renderbuffer->Format;
+      dst_internal_format = dst_renderbuffer->InternalFormat;
+   } else {
+      assert(dst_tex_image);
+      dst_format = dst_tex_image->TexFormat;
+      dst_internal_format = dst_tex_image->InternalFormat;
+   }
+
+   if (_mesa_is_format_compressed(src_format))
       return false;
 
-   if (_mesa_is_format_compressed(src_tex_image->TexFormat))
+   if (_mesa_is_format_compressed(dst_format))
       return false;
 
-   if (src_tex_image->InternalFormat == dst_tex_image->InternalFormat) {
+   if (src_internal_format == dst_internal_format) {
       src_view_tex_image = src_tex_image;
    } else {
+      if (src_renderbuffer) {
+         assert(src_tex_image == NULL);
+         src_tex_image = wrap_renderbuffer(ctx, src_renderbuffer);
+      }
       if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture,
-                     dst_tex_image->InternalFormat))
+                     dst_internal_format))
          goto cleanup;
    }
 
    /* We really only need to stash the bound framebuffers and scissor. */
    _mesa_meta_begin(ctx, MESA_META_SCISSOR);
 
-   _mesa_GenFramebuffers(2, fbos);
-   _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
-   _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
+   readFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF);
+   if (readFb == NULL)
+      goto meta_end;
+
+   drawFb = ctx->Driver.NewFramebuffer(ctx, 0xDEADBEEF);
+   if (drawFb == NULL)
+      goto meta_end;
 
-   switch (_mesa_get_format_base_format(src_tex_image->TexFormat)) {
+   _mesa_bind_framebuffers(ctx, drawFb, readFb);
+
+   switch (_mesa_get_format_base_format(src_format)) {
    case GL_DEPTH_COMPONENT:
       attachment = GL_DEPTH_ATTACHMENT;
       mask = GL_DEPTH_BUFFER_BIT;
@@ -165,20 +242,36 @@ _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx,
       _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0);
    }
 
-   _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment,
-                             src_view_tex_image, src_z);
+   if (src_view_tex_image) {
+      /* Prefer the tex image because, even if we have a renderbuffer, we may
+       * have had to wrap it in a texture view.
+       */
+      _mesa_meta_framebuffer_texture_image(ctx, ctx->ReadBuffer, attachment,
+                                           src_view_tex_image, src_z);
+   } else {
+      _mesa_framebuffer_renderbuffer(ctx, ctx->ReadBuffer, attachment,
+                                     src_renderbuffer);
+   }
 
-   status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
+   status = _mesa_check_framebuffer_status(ctx, ctx->ReadBuffer);
    if (status != GL_FRAMEBUFFER_COMPLETE)
       goto meta_end;
 
-   _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment,
-                             dst_tex_image, dst_z);
+   if (dst_renderbuffer) {
+      _mesa_framebuffer_renderbuffer(ctx, ctx->DrawBuffer, attachment,
+                                     dst_renderbuffer);
+   } else {
+      _mesa_meta_framebuffer_texture_image(ctx, ctx->DrawBuffer, attachment,
+                                           dst_tex_image, dst_z);
+   }
 
-   status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+   status = _mesa_check_framebuffer_status(ctx, ctx->DrawBuffer);
    if (status != GL_FRAMEBUFFER_COMPLETE)
       goto meta_end;
 
+   /* Explicitly disable sRGB encoding */
+   ctx->DrawBuffer->Visual.sRGBCapable = false;
+
    /* Since we've bound a new draw framebuffer, we need to update its
     * derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to
     * be correct.
@@ -199,11 +292,16 @@ _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx,
    success = true;
 
 meta_end:
-   _mesa_DeleteFramebuffers(2, fbos);
+   _mesa_reference_framebuffer(&readFb, NULL);
+   _mesa_reference_framebuffer(&drawFb, NULL);
    _mesa_meta_end(ctx);
 
 cleanup:
    _mesa_DeleteTextures(1, &src_view_texture);
 
+   /* If we got a renderbuffer source, delete the temporary texture */
+   if (src_renderbuffer && src_tex_image)
+      ctx->Driver.DeleteTexture(ctx, src_tex_image->TexObject);
+
    return success;
 }