Merge branch '7.8'
[mesa.git] / src / mesa / state_tracker / st_gen_mipmap.c
index dc6d77825f5dcce0246e63adf824603c262239e3..030b0a0f0655ce7bbc7d053f15be823504d84acb 100644 (file)
@@ -27,6 +27,7 @@
 
 
 #include "main/imports.h"
+#include "main/macros.h"
 #include "main/mipmap.h"
 #include "main/teximage.h"
 #include "main/texformat.h"
 
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
-#include "pipe/p_inlines.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
 #include "util/u_gen_mipmap.h"
+#include "util/u_math.h"
 
 #include "cso_cache/cso_cache.h"
 #include "cso_cache/cso_context.h"
 
+#include "st_debug.h"
 #include "st_context.h"
-#include "st_draw.h"
 #include "st_gen_mipmap.h"
-#include "st_program.h"
 #include "st_texture.h"
 #include "st_cb_texture.h"
 #include "st_inlines.h"
@@ -77,22 +79,23 @@ st_destroy_generate_mipmap(struct st_context *st)
 static boolean
 st_render_mipmap(struct st_context *st,
                  GLenum target,
-                 struct pipe_texture *pt,
+                 struct st_texture_object *stObj,
                  uint baseLevel, uint lastLevel)
 {
    struct pipe_context *pipe = st->pipe;
    struct pipe_screen *screen = pipe->screen;
+   struct pipe_sampler_view *psv = st_get_stobj_sampler_view(stObj);
    const uint face = _mesa_tex_target_to_face(target);
 
    assert(target != GL_TEXTURE_3D); /* not done yet */
 
    /* check if we can render in the texture's format */
-   if (!screen->is_format_supported(screen, pt->format, pt->target,
+   if (!screen->is_format_supported(screen, psv->format, psv->texture->target,
                                     PIPE_TEXTURE_USAGE_RENDER_TARGET, 0)) {
       return FALSE;
    }
 
-   util_gen_mipmap(st->gen_mipmap, pt, face, baseLevel, lastLevel,
+   util_gen_mipmap(st->gen_mipmap, psv, face, baseLevel, lastLevel,
                    PIPE_TEX_FILTER_LINEAR);
 
    return TRUE;
@@ -104,7 +107,6 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target,
                          struct gl_texture_object *texObj)
 {
    struct pipe_context *pipe = ctx->st->pipe;
-   struct pipe_screen *screen = pipe->screen;
    struct pipe_texture *pt = st_get_texobj_texture(texObj);
    const uint baseLevel = texObj->BaseLevel;
    const uint lastLevel = pt->last_level;
@@ -112,6 +114,9 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target,
    uint dstLevel;
    GLenum datatype;
    GLuint comps;
+   
+   if (ST_DEBUG & DEBUG_FALLBACK)
+      debug_printf("%s: fallback processing\n", __FUNCTION__);
 
    assert(target != GL_TEXTURE_3D); /* not done yet */
 
@@ -128,35 +133,76 @@ fallback_generate_mipmap(GLcontext *ctx, GLenum target,
       srcTrans = st_cond_flush_get_tex_transfer(st_context(ctx), pt, face,
                                                srcLevel, zslice,
                                                PIPE_TRANSFER_READ, 0, 0,
-                                               pt->width[srcLevel],
-                                               pt->height[srcLevel]);
+                                               u_minify(pt->width0, srcLevel),
+                                               u_minify(pt->height0, srcLevel));
 
       dstTrans = st_cond_flush_get_tex_transfer(st_context(ctx), pt, face,
                                                dstLevel, zslice,
                                                PIPE_TRANSFER_WRITE, 0, 0,
-                                               pt->width[dstLevel],
-                                               pt->height[dstLevel]);
+                                               u_minify(pt->width0, dstLevel),
+                                               u_minify(pt->height0, dstLevel));
 
-      srcData = (ubyte *) screen->transfer_map(screen, srcTrans);
-      dstData = (ubyte *) screen->transfer_map(screen, dstTrans);
+      srcData = (ubyte *) pipe->transfer_map(pipe, srcTrans);
+      dstData = (ubyte *) pipe->transfer_map(pipe, dstTrans);
 
-      srcStride = srcTrans->stride / srcTrans->block.size;
-      dstStride = dstTrans->stride / dstTrans->block.size;
+      srcStride = srcTrans->stride / util_format_get_blocksize(srcTrans->texture->format);
+      dstStride = dstTrans->stride / util_format_get_blocksize(dstTrans->texture->format);
 
       _mesa_generate_mipmap_level(target, datatype, comps,
-                   0 /*border*/,
-                   pt->width[srcLevel], pt->height[srcLevel], pt->depth[srcLevel],
-                   srcData,
-                   srcStride, /* stride in texels */
-                   pt->width[dstLevel], pt->height[dstLevel], pt->depth[dstLevel],
-                   dstData,
-                   dstStride); /* stride in texels */
-
-      screen->transfer_unmap(screen, srcTrans);
-      screen->transfer_unmap(screen, dstTrans);
-
-      screen->tex_transfer_destroy(srcTrans);
-      screen->tex_transfer_destroy(dstTrans);
+                                  0 /*border*/,
+                                  u_minify(pt->width0, srcLevel),
+                                  u_minify(pt->height0, srcLevel),
+                                  u_minify(pt->depth0, srcLevel),
+                                  srcData,
+                                  srcStride, /* stride in texels */
+                                  u_minify(pt->width0, dstLevel),
+                                  u_minify(pt->height0, dstLevel),
+                                  u_minify(pt->depth0, dstLevel),
+                                  dstData,
+                                  dstStride); /* stride in texels */
+
+      pipe->transfer_unmap(pipe, srcTrans);
+      pipe->transfer_unmap(pipe, dstTrans);
+
+      pipe->tex_transfer_destroy(pipe, srcTrans);
+      pipe->tex_transfer_destroy(pipe, dstTrans);
+   }
+}
+
+
+/**
+ * Compute the expected number of mipmap levels in the texture given
+ * the width/height/depth of the base image and the GL_TEXTURE_BASE_LEVEL/
+ * GL_TEXTURE_MAX_LEVEL settings.  This will tell us how many mipmap
+ * level should be generated.
+ */
+static GLuint
+compute_num_levels(GLcontext *ctx,
+                   struct gl_texture_object *texObj,
+                   GLenum target)
+{
+   if (target == GL_TEXTURE_RECTANGLE_ARB) {
+      return 1;
+   }
+   else {
+      const GLuint maxLevels = texObj->MaxLevel - texObj->BaseLevel + 1;
+      const struct gl_texture_image *baseImage = 
+         _mesa_get_tex_image(ctx, texObj, target, texObj->BaseLevel);
+      GLuint size, numLevels;
+
+      size = MAX2(baseImage->Width2, baseImage->Height2);
+      size = MAX2(size, baseImage->Depth2);
+
+      numLevels = 0;
+
+      while (size > 0) {
+         numLevels++;
+         size >>= 1;
+      }
+
+      numLevels = MIN2(numLevels, maxLevels);
+
+      return numLevels;
    }
 }
 
@@ -166,6 +212,7 @@ st_generate_mipmap(GLcontext *ctx, GLenum target,
                    struct gl_texture_object *texObj)
 {
    struct st_context *st = ctx->st;
+   struct st_texture_object *stObj = st_texture_object(texObj);
    struct pipe_texture *pt = st_get_texobj_texture(texObj);
    const uint baseLevel = texObj->BaseLevel;
    uint lastLevel;
@@ -174,9 +221,52 @@ st_generate_mipmap(GLcontext *ctx, GLenum target,
    if (!pt)
       return;
 
-   lastLevel = pt->last_level;
+   /* find expected last mipmap level */
+   lastLevel = compute_num_levels(ctx, texObj, target) - 1;
+
+   if (lastLevel == 0)
+      return;
+
+   if (pt->last_level < lastLevel) {
+      /* The current gallium texture doesn't have space for all the
+       * mipmap levels we need to generate.  So allocate a new texture.
+       */
+      struct pipe_texture *oldTex = stObj->pt;
+      GLboolean needFlush;
+
+      /* create new texture with space for more levels */
+      stObj->pt = st_texture_create(st,
+                                    oldTex->target,
+                                    oldTex->format,
+                                    lastLevel,
+                                    oldTex->width0,
+                                    oldTex->height0,
+                                    oldTex->depth0,
+                                    oldTex->tex_usage);
+
+      /* The texture isn't in a "complete" state yet so set the expected
+       * lastLevel here, since it won't get done in st_finalize_texture().
+       */
+      stObj->lastLevel = lastLevel;
+
+      /* This will copy the old texture's base image into the new texture
+       * which we just allocated.
+       */
+      st_finalize_texture(ctx, st->pipe, texObj, &needFlush);
+
+      /* release the old tex (will likely be freed too) */
+      pipe_texture_reference(&oldTex, NULL);
+      pipe_sampler_view_reference(&stObj->sampler_view, NULL);
+
+      pt = stObj->pt;
+   }
 
-   if (!st_render_mipmap(st, target, pt, baseLevel, lastLevel)) {
+   assert(lastLevel <= pt->last_level);
+
+   /* Recall that the Mesa BaseLevel image is stored in the gallium
+    * texture's level[0] position.  So pass baseLevel=0 here.
+    */
+   if (!st_render_mipmap(st, target, stObj, 0, lastLevel)) {
       fallback_generate_mipmap(ctx, target, texObj);
    }
 
@@ -187,9 +277,9 @@ st_generate_mipmap(GLcontext *ctx, GLenum target,
          = _mesa_get_tex_image(ctx, texObj, target, srcLevel);
       struct gl_texture_image *dstImage;
       struct st_texture_image *stImage;
-      uint dstWidth = pt->width[dstLevel];
-      uint dstHeight = pt->height[dstLevel];
-      uint dstDepth = pt->depth[dstLevel];
+      uint dstWidth = u_minify(pt->width0, dstLevel);
+      uint dstHeight = u_minify(pt->height0, dstLevel);
+      uint dstDepth = u_minify(pt->depth0, dstLevel); 
       uint border = srcImage->Border;
 
       dstImage = _mesa_get_tex_image(ctx, texObj, target, dstLevel);
@@ -198,9 +288,6 @@ st_generate_mipmap(GLcontext *ctx, GLenum target,
          return;
       }
 
-      if (dstImage->ImageOffsets)
-         _mesa_free(dstImage->ImageOffsets);
-
       /* Free old image data */
       if (dstImage->Data)
          ctx->Driver.FreeTexImageData(ctx, dstImage);